diff --git a/.editorconfig b/.editorconfig index 88af77a0f..316758e94 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,4 @@ -# THis is an EditorConfig file +# This is an EditorConfig file # https://EditorConfig.org root = true diff --git a/.github/workflows/consistency-checks.yml b/.github/workflows/consistency-checks.yml index af01aa365..f3fdc5d19 100644 --- a/.github/workflows/consistency-checks.yml +++ b/.github/workflows/consistency-checks.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.11'] + python-version: ['3.13'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -22,13 +22,9 @@ jobs: run: | sudo apt update -qq && sudo apt install llvm-dev remake python -m pip install --upgrade pip - pip install -e . # We can comment out after next Mathics-Scanner release - # python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] - # git clone https://github.com/Mathics3/mathics-scanner.git - # cd mathics-scanner/ - # pip install -e . - # cd .. + python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] + pip install -e . - name: Install Mathics with minimum dependencies run: | diff --git a/.github/workflows/isort-and-black-checks.yml b/.github/workflows/isort-and-black-checks.yml index 00bd2362b..f8fc90b64 100644 --- a/.github/workflows/isort-and-black-checks.yml +++ b/.github/workflows/isort-and-black-checks.yml @@ -13,7 +13,7 @@ jobs: - name: Set up Python 3.11 uses: actions/setup-python@v5 with: - python-version: 3.11 + python-version: 3.13 - name: Install click, black and isort run: pip install 'click==8.0.4' 'black==23.12.1' 'isort==5.13.2' - name: Run isort --check . diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 5bdcf7d0e..f062515e1 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: os: [macOS] - python-version: ['3.10', '3.11'] + python-version: ['3.13', '3.12'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -33,14 +33,10 @@ jobs: cd stopit/ pip install -e . cd .. - python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] # We can comment out after next Mathics-Scanner release - git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git - # git clone --single-branch --branch operator-refactor-part1.5 https://github.com/Mathics3/mathics-scanner.git - cd mathics-scanner/ - pip install -e . - cd .. # python -m pip install Mathics-Scanner[full] + python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] + pip install -e . remake -x develop-full - name: Test Mathics3 run: | diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index 22d56bef5..9f0b86ee3 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.12'] + python-version: ['3.13'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -22,21 +22,17 @@ jobs: run: | sudo apt update -qq && sudo apt install llvm-dev remake python -m pip install --upgrade pip - pip install -e . - # python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] - # We can comment out after next Mathics-Scanner release - # git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git - # cd mathics-scanner/ - # pip install -e . - # cd .. - - name: Install Mathics with minimum dependencies - run: | - make develop - name: Run mypy run: | pip install mypy==1.13 sympy==1.12 - git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git + # Adjust below for right branch + git clone --depth 1 https://github.com/Mathics3/mathics-scanner + cd mathics-scanner/ + pip install -e . + bash ./admin-tools/make-JSON-tables.sh + pip install -e . + cd .. touch ./mathics-scanner/mathics_scanner/py.typed - pip install ./mathics-scanner/ - mypy --install-types --non-interactive mathics + make develop + mypy --install-types --ignore-missing-imports --non-interactive mathics diff --git a/.github/workflows/packages.yml b/.github/workflows/packages.yml index 596688775..44c72f6b5 100644 --- a/.github/workflows/packages.yml +++ b/.github/workflows/packages.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.11'] + python-version: ['3.13'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -26,12 +26,6 @@ jobs: python -m pip install --upgrade pip # We can comment out after next Mathics-Scanner release python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] - git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git - # git clone --single-branch --branch operator-refactor-part1.5 https://github.com/Mathics3/mathics-scanner.git - cd src/mathics-scanner/ - pip install -e . - python -m mathics_scanner.generate.build_tables - cd ../.. - name: Run Mathics3 Combinatorica tests run: | git submodule init diff --git a/.github/workflows/pyodide.yml b/.github/workflows/pyodide.yml index eb330cda7..2780cf7b1 100644 --- a/.github/workflows/pyodide.yml +++ b/.github/workflows/pyodide.yml @@ -55,9 +55,7 @@ jobs: pip install "setuptools>=70.0.0" PyYAML click packaging pytest # We can comment out after next Mathics-Scanner release - # git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git - # git clone --single-branch --branch operator-refactor-part1.5 https://github.com/Mathics3/mathics-scanner.git - # cd mathics-scanner/ + python -m pip install --no-build-isolation -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner # pip install --no-build-isolation -e . # cd .. diff --git a/.github/workflows/ubuntu-cython.yml b/.github/workflows/ubuntu-cython.yml index 6eda26f41..c57bba501 100644 --- a/.github/workflows/ubuntu-cython.yml +++ b/.github/workflows/ubuntu-cython.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.12'] + python-version: ['3.13'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -30,10 +30,7 @@ jobs: pip install -e . cd .. # We can comment out after next Mathics-Scanner release - # python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] - # git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git - # git clone --single-branch --branch operator-refactor-part1.5 https://github.com/Mathics3/mathics-scanner.git - # cd mathics-scanner/ + python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] pip install -e . cd .. diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index d886d5b64..1bfa738e5 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.12', '3.11', '3.8', '3.9', '3.10'] + python-version: ['3.13', '3.12', '3.11', '3.10', '3.9'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -30,15 +30,9 @@ jobs: pip install -e . cd .. # We can comment out after next Mathics-Scanner release - # python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] - # git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git - # git clone --single-branch --branch operator-refactor-part1.5 https://github.com/Mathics3/mathics-scanner.git - # cd mathics-scanner/ - # pip install -e . - # python -m mathics_scanner.generate.build_tables - # cd .. - - python -m pip install Mathics-Scanner[full] + # python -m pip install Mathics-Scanner[full] + python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] + pip install -e . remake -x develop-full - name: Test Mathics run: | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ad2ffffae..a112eba9c 100755 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -14,7 +14,7 @@ jobs: os: [windows] # "make doctest" on MS Windows fails without showing much of a # trace of where things went wrong on Python before 3.11. - python-version: ['3.12'] + python-version: ['3.13'] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -39,13 +39,7 @@ jobs: pip install -e . cd .. # We can comment out after next Mathics-Scanner release - # python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] - # git clone --depth 1 https://github.com/Mathics3/mathics-scanner.git - # git clone --single-branch --branch operator-refactor-part1.5 https://github.com/Mathics3/mathics-scanner.git - # cd mathics-scanner - # pip install -e . - # python -m mathics_scanner.generate.build_tables - # cd .. + python -m pip install -e git+https://github.com/Mathics3/mathics-scanner#egg=Mathics-Scanner[full] pip install -e . # python -m pip install Mathics-Scanner[full] diff --git a/.gitignore b/.gitignore index 68aa74947..039c83dc8 100644 --- a/.gitignore +++ b/.gitignore @@ -15,8 +15,9 @@ .vscode /.cache /.gdbinit -/.python-version /.pyodide-xbuildenv-* +/.python-version +/ChangeLog.spell-corrected /Mathics.egg-info /Mathics3.egg-info ChangeLog diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e2427101f..648473fbb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ repos: - id: check-merge-conflict - id: debug-statements stages: [pre-commit] - exclude: ChangeLog-spell-corrected.diff + exclude: ChangeLog-spell-corrected.diff|mathics/builtin/system.py - id: end-of-file-fixer stages: [pre-commit] exclude: ChangeLog-spell-corrected.diff diff --git a/CHANGES.rst b/CHANGES.rst index d2760b5e9..f1b2160c9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,7 +1,59 @@ CHANGES ======= -8.0.0 +New Builtins +++++++++++++ + +* ``$SessionID`` +* ``BinaryReadList`` + +Internals +--------- + +Mathics scanner exceptions of class TranslateError are incompatible +with previous versions, and now store error parameters, "name", "tag", and +"args". + +8.0.1 +----- + +Feb 8, 2025 + +Some work was made to the Mathics3 Kernel to work in Python 3.13. +The maximum version of numpy was increased to < 2.3 so as to allow marimo to work. + + +Bugs +---- + +Correct for mismatch between ListExpression and tuple in ``DispatchAtom``. +This is needed for PacletManager code to work better. + + +Compatibility +------------- + +* When the result of an evaluation is ``Symbol`Null``, Mathics CLI + now does not show an ``Out[...]=`` line, following the behavior of + the WMA CLI. +* Asymptote rendering of platonic solids added. + + +Internals +--------- + +Document tagging code handles TeX math mode more completely. Image tags in PDF properly. + +Documentation +------------- + +* Documentation has been gone over so that expressions are tagged in TeX. As a result the user guide and reference manual render much nicer in the PDF as well as in Django. +* More links have been added. References to The Digital Library of Mathematical Functions https://dlmf.nist.gov/ have been added where appropriate. +* Add mention of MathicsLive +* Platonic solid render properly in PDF + + + 8.0.0 ----- Jan 26, 2025 diff --git a/ChangeLog-spell-corrected.diff b/ChangeLog-spell-corrected.diff index ea35e9da5..24f208259 100644 --- a/ChangeLog-spell-corrected.diff +++ b/ChangeLog-spell-corrected.diff @@ -1,6 +1,28 @@ ---- ChangeLog 2025-01-26 11:55:55.226254640 -0500 -+++ ChangeLog.spell-corrected 2025-01-26 12:01:11.081508449 -0500 -@@ -80,7 +80,7 @@ +--- ChangeLog 2025-02-08 08:24:39.225280293 -0500 ++++ ChangeLog.spell-corrected 2025-02-08 08:25:17.574285289 -0500 +@@ -135,10 +135,10 @@ + mathics/builtin/files_io/importexport.py, + mathics/builtin/numbers/randomnumbers.py, + mathics/doc/common_doc.py, mathics/doc/doc_entries.py, +- mathics/doc/documentation/1-Manual.mdoc, mathics/doc/latex_doc.py: ++ mathics/doc/documentation/1-Manual.mdoc, mathics/doc/latex_doc.py: + Last changes in documentation system (#1356) I hope, this are the last changes to do with the documentation + system. As always, trying to fix something simple other things come +- up. But I guess I cover all of them: * Procesing recurrent replacements in `post_sub`. * Removing the ++ up. But I guess I cover all of them: * Processing recurrent replacements in `post_sub`. * Removing the + non-existing `` tag, and replacing it by the existing but + not used . * Fixing remaining docstrings containing '$Symbol' + +@@ -232,7 +232,7 @@ + * mathics/builtin/numbers/calculus.py, + mathics/builtin/specialfns/elliptic.py, + mathics/builtin/specialfns/orthogonal.py, +- mathics/builtin/vectors/constructing.py, mathics/doc/doc_entries.py: ++ mathics/builtin/vectors/constructing.py, mathics/doc/doc_entries.py: + Adjust the plain-text form of documentation (#1340) This PR modifies the code that generates the text shown in + `Information`. * Remove escape characters * symbols with subindices are resembled as valid variable names. + +@@ -570,7 +570,7 @@ mathics/eval/makeboxes/operators.py, mathics/eval/makeboxes/outputforms.py, mathics/eval/makeboxes/precedence.py, setup.py, @@ -9,7 +31,7 @@ Moving evaluation code from mathics.builtin.makeboxes to mathics.eval.makeboxes (#1309) This goes in the same line as #1307. Essentially, moving code from mathics.builtin.makeboxes to `mathics.eval.makeboxes`, and -@@ -132,7 +132,7 @@ +@@ -622,7 +622,7 @@ mathics/builtin/intfns/combinatorial.py, mathics/builtin/numbers/numbertheory.py, mathics/builtin/specialfns/bessel.py, mathics/builtin/system.py, @@ -18,7 +40,7 @@ (#1306) Also some linting 2025-01-19 Juan Mauricio Matera -@@ -144,7 +144,7 @@ +@@ -634,7 +634,7 @@ * mathics/builtin/arithfns/basic.py, test/builtin/arithmetic/test_basic.py, @@ -27,7 +49,7 @@ flycheck two pytests (#1294) @mmatera I was trying to add a test for `HoldForm[Times[x]] == Times[x]` of a recent PR of yours (from a while ago) but haven't been able to figure out how to do. in the process, I have this lint -@@ -187,7 +187,7 @@ +@@ -677,7 +677,7 @@ mathics/builtin/functional/apply_fns_to_lists.py, mathics/builtin/testing_expressions/equality_inequality.py, mathics/builtin/trace.py, mathics/core/builtin.py, @@ -36,7 +58,7 @@ Doc updates (#1297) First part of an unknown number of rounds of documentation review. 2025-01-17 Juan Mauricio Matera -@@ -443,7 +443,7 @@ +@@ -933,7 +933,7 @@ 2025-01-05 R. Bernstein @@ -45,7 +67,7 @@ Add SequenceForm... (#1258) It is used in CombinatoricaV201 even though it is deprecated. 2025-01-05 R. Bernstein -@@ -469,7 +469,7 @@ +@@ -959,7 +959,7 @@ 2025-01-05 R. Bernstein @@ -54,7 +76,7 @@ Parser refactor part2 (#1262) Last round of changes before getting to box parsing proper. 2025-01-03 rocky -@@ -532,7 +532,7 @@ +@@ -1022,7 +1022,7 @@ 2024-12-29 R. Bernstein * mathics/builtin/functional/functional_iteration.py, @@ -63,7 +85,7 @@ Administrative fixups and tweak (#1254) Miscellaneous docstring hard linebreaks removed and some mypy linting. -@@ -559,7 +559,7 @@ +@@ -1049,7 +1049,7 @@ 2024-12-29 rocky @@ -72,7 +94,7 @@ Spelling/grammar typos 2024-12-29 R. Bernstein -@@ -603,7 +603,7 @@ +@@ -1093,7 +1093,7 @@ test/builtin/{test_functional.py => functional/test_apply_fns_to_lists.py}: Corrections to MapAt for Multi-dimensions... (#1239) The following changes implement pretty much all of what @@ -81,7 +103,7 @@ MapAt[] 2024-12-24 R. Bernstein -@@ -717,7 +717,7 @@ +@@ -1207,7 +1207,7 @@ * mathics/packages/DiscreteMath/CombinatoricaV0.9.m, test/package/test_combinatorica.py: Combinatorica V0.9 workarounds @@ -90,7 +112,7 @@ V2.0 (In V.09 it is not broken, it is just altogether missing.) So copy the 2.0.0 code into V0.9 2024-12-14 R. Bernstein -@@ -874,7 +874,7 @@ +@@ -1364,7 +1364,7 @@ mathics/eval/testing_expressions.py, test/builtin/calculus/test_integrate.py, test/builtin/distance/__init__.py, @@ -99,7 +121,7 @@ that class 2024-12-02 rocky -@@ -896,7 +896,7 @@ +@@ -1386,7 +1386,7 @@ 2024-12-01 R. Bernstein * mathics/builtin/files_io/files.py, mathics/core/streams.py, @@ -108,7 +130,7 @@ Lookup streams by user (short) names (#1188) We need to lookup streams opened by the name or string the gives, not the resolved path name. This bug was discovered in trying to run Analytica. At some point in the vague future, I'll write up a bug report, and possibly -@@ -1241,7 +1241,7 @@ +@@ -1731,7 +1731,7 @@ 2024-10-28 R. Bernstein * mathics/builtin/atomic/numbers.py, @@ -117,7 +139,7 @@ Two postponed TODOs in recent PRs... (#1148) * Move eval functions to mathics.eval.numbers.numbers * Move "no_doc" after imports 2024-10-28 David A Roberts -@@ -1339,7 +1339,7 @@ +@@ -1829,7 +1829,7 @@ 2024-10-22 R. Bernstein * CHANGES.rst, mathics/builtin/scipy_utils/integrators.py, @@ -126,7 +148,7 @@ Romberg is deprecated... (#1131) and will be removed by SciPyi 1.15 2024-10-21 Juan Mauricio Matera -@@ -1410,7 +1410,7 @@ +@@ -1900,7 +1900,7 @@ mathics/builtin/file_operations/file_utilities.py, mathics/builtin/files_io/files.py, mathics/builtin/functional/apply_fns_to_lists.py, @@ -135,7 +157,7 @@ Remove duplication of "intnm" messages (#1128) 2024-10-12 R. Bernstein -@@ -1505,7 +1505,7 @@ +@@ -1995,7 +1995,7 @@ * .github/workflows/{osx.yml => macos.yml}, CHANGES.rst, mathics/builtin/box/compilation.py, mathics/core/pattern.py: A few @@ -144,7 +166,7 @@ pattern comment * Remove Lint warning on compilation box * rename osx to macos in CI test 2024-10-02 R. Bernstein -@@ -1536,7 +1536,7 @@ +@@ -2026,7 +2026,7 @@ mathics/builtin/patterns.py, mathics/core/builtin.py, mathics/core/pattern.py, mathics/core/rules.py, mathics/eval/numbers/calculus/series.py, mathics/eval/parts.py, @@ -153,7 +175,7 @@ Earlier initialization of patterns (#1103) When a ExpressionPattern is created, the way in which the matching with expressions is determined in part by the attributes of its head. For example, if `S` is `Orderless`, the match method of the -@@ -1596,7 +1596,7 @@ +@@ -2086,7 +2086,7 @@ 2024-09-27 R. Bernstein @@ -162,7 +184,7 @@ Get trace/debug tweaks and fixes... (#1098) Get[xx, Trace->True] was not showing all lines read. And we did not properly hook into a changeable print function. Using: import a.b.c as e reduces unchangeable lookup (a.b.c) does not change and simplifies and use -- e.GET_PRINT_FN as opposed to a.b.c.GET_PRINT_FN -@@ -1614,8 +1614,8 @@ +@@ -2104,8 +2104,8 @@ 2024-09-26 R. Bernstein * mathics/builtin/files_io/files.py, mathics/core/rules.py, @@ -173,7 +195,7 @@ the call. * Change the way Get[..., Trace->True] so that a debugger can hook into this more naturally -- separate the line number from the text. Some other small changes were made like putting the Number class in alphabetic order, or adding more annotations. -@@ -1651,8 +1651,8 @@ +@@ -2141,8 +2141,8 @@ 2024-09-21 R. Bernstein @@ -184,7 +206,7 @@ outside in the interactive session we set "In[]" to be "Debug In[]" and Out[] to be "Debug Out[]". Also we DRY the eval loop of main() -@@ -1663,7 +1663,7 @@ +@@ -2153,7 +2153,7 @@ 2024-09-19 R. Bernstein @@ -193,7 +215,7 @@ `isinstance(pat, Pattern)`. I think there are other places where we are using ``get_head_name() == "System`xxx`` but that is left for a different time. -@@ -1675,7 +1675,7 @@ +@@ -2165,7 +2165,7 @@ mathics/builtin/numbers/calculus.py, mathics/builtin/patterns.py, mathics/core/builtin.py, mathics/core/pattern.py, mathics/core/rules.py, mathics/eval/numbers/calculus/series.py, @@ -202,7 +224,7 @@ Starting to tidy up mathics.core.pattern (#1086) In line with the last changes proposed by @rocky, I was doing a pass over mathics.core.pattern and fixing some issues reported by the linter. --------- Co-authored-by: R. Bernstein -@@ -1690,7 +1690,7 @@ +@@ -2180,7 +2180,7 @@ 2024-09-15 R. Bernstein @@ -211,7 +233,7 @@ apply_rule -> apply_function ... (#1084) Change `apply_rule()` -> to `apply_function()` when that is what is is; (and not when it is not). Also mark BaseRule an abstract class, and go over docstrings in mathics.core.rules @mmatera I think i now understand what you were getting at when we -@@ -1701,7 +1701,7 @@ +@@ -2191,7 +2191,7 @@ 2024-09-08 R. Bernstein @@ -220,7 +242,7 @@ do_replace -> apply_rule (#1083) 2024-08-31 R. Bernstein -@@ -1721,7 +1721,7 @@ +@@ -2211,7 +2211,7 @@ 2024-08-31 Juan Mauricio Matera @@ -229,7 +251,7 @@ Blanks as singleton (#1081) Looking at the initialization process, `Blank*` PatternObjets are created several times. This PR makes that these elements be created just once when a parameter is not provided. This would also help to -@@ -1783,7 +1783,7 @@ +@@ -2273,7 +2273,7 @@ .github/workflows/ubuntu.yml, .github/workflows/windows.yml, mathics/builtin/assignments/assign_binaryop.py, mathics/builtin/atomic/strings.py, @@ -238,7 +260,7 @@ Go over operators (#1076) 2024-08-29 R. Bernstein -@@ -1796,7 +1796,7 @@ +@@ -2286,7 +2286,7 @@ 2024-08-20 Juan Mauricio Matera @@ -247,7 +269,7 @@ fix tests for sympy conversions (#1073) This PR just fixes the pytest, and marks some issues in the conversion of Lambda functions. --------- Co-authored-by: rocky -@@ -1804,7 +1804,7 @@ +@@ -2294,7 +2294,7 @@ * CHANGES.rst, mathics/builtin/numbers/algebra.py, mathics/builtin/numbers/numbertheory.py, @@ -256,7 +278,7 @@ Misc tweaks... (#1072) (These were noticed in working on event tracing) `mathics/builtin/numbers/algebra.py`: black changes its autoformatting `mathics/builtin/numbers/numbertheory.py`: some linting prefers triples quotes for docstrings `mathics/core/convert/sympy.py`: use accurate location for singleton -@@ -1827,7 +1827,7 @@ +@@ -2317,7 +2317,7 @@ mathics/core/convert/sympy.py: Remove "sympy_name" in from_sympy() calls: (#1070) Generally, we can get sympy_name from the object. Previously, we sometimes we had two-parameter "from_sympy()" calls and @@ -265,7 +287,7 @@ 2024-08-13 R. Bernstein -@@ -1872,7 +1872,7 @@ +@@ -2362,7 +2362,7 @@ 2024-08-09 rocky * AUTHORS.txt, Makefile, README.rst, mathics/__init__.py, @@ -274,7 +296,7 @@ 2024-08-09 rocky -@@ -1968,7 +1968,7 @@ +@@ -2458,7 +2458,7 @@ mathics/builtin/procedural.py, mathics/builtin/specialfns/gamma.py, mathics/builtin/system.py, mathics/builtin/testing_expressions/logic.py, @@ -283,7 +305,7 @@ normalizing linebreaks after (#1055) This PR just normalizes the line breaks after in the docstrings -@@ -2030,7 +2030,7 @@ +@@ -2520,7 +2520,7 @@ mathics/doc/latex/mathics.tex: Misc doc-related changes (#1051) * numbers.py: Precision; fix spelling, remove hard line-wrap and make render in LaTeX better * symbols.py: Need `\n` after ``. Hash was not doctest'd properly combinatorial.py: Add Subset link; shorten Subset * test @@ -292,7 +314,7 @@ DirectedInfinity orderstats. WMA -> WMA link (when there are no other links) expression_tests.py: move and *Q here. * systemsymbols.py: More symbols -@@ -2060,7 +2060,7 @@ +@@ -2550,7 +2550,7 @@ * mathics/doc/latex/mathics-test.tex, mathics/docpipeline.py: using more print_and_log (#1050) In the refactor of docpipeline I forgot to use more this method, and also at some place it was called from the wrong object. This PR @@ -301,7 +323,7 @@ 2024-08-03 Juan Mauricio Matera -@@ -2173,7 +2173,7 @@ +@@ -2663,7 +2663,7 @@ 2024-07-29 R. Bernstein * pyproject.toml: Minimum Python version supported is 3.8 (#1040) MathicsScanner currently supports 3.8 or greater in order to support @@ -310,7 +332,7 @@ 2024-07-29 Juan Mauricio Matera -@@ -2183,7 +2183,7 @@ +@@ -2673,7 +2673,7 @@ mathics/builtin/testing_expressions/numerical_properties.py, mathics/core/atoms.py, mathics/eval/testing_expressions.py: Sympy 1.13 compatibility (#1037) This PR implements the changes required for compatibility with the @@ -319,7 +341,7 @@ that the new version does not allows to compare `Sympy.Float`s against Python `float`s -@@ -2312,7 +2312,7 @@ +@@ -2802,7 +2802,7 @@ 2024-02-10 Juan Mauricio Matera * mathics/builtin/evaluation.py, @@ -328,7 +350,7 @@ adding Exit as an alias of Quit (#998) This fixes #996. It seems that the rule for `Exit` was not loaded together with `Quit`. --------- Co-authored-by: R. Bernstein -@@ -2546,7 +2546,7 @@ +@@ -3036,7 +3036,7 @@ * mathics/session.py, test/builtin/test_attributes.py, test/builtin/{test_evalution.py => test_evaluation.py}, test/builtin/test_functional.py, test/builtin/test_messages.py, @@ -337,7 +359,7 @@ MathicsSession.evaluate_as_in_cli (#931) This PR implements a method in the `MathicsSession` class that uses the `Evaluation.evaluate` method. This allows to handle exceptions and special symbols like % or Line references. This method is used -@@ -2946,7 +2946,7 @@ +@@ -3436,7 +3436,7 @@ 2023-11-19 rocky @@ -346,7 +368,7 @@ 2023-11-16 rocky -@@ -3002,7 +3002,7 @@ +@@ -3492,7 +3492,7 @@ mathics/builtin/drawing/graphics3d.py, mathics/builtin/drawing/plot.py, test/builtin/colors/test_color_directives.py, @@ -355,7 +377,7 @@ move private doctests to pytest for builtin.drawing and builtin.colors (#930) -@@ -3027,8 +3027,8 @@ +@@ -3517,8 +3517,8 @@ mathics/builtin/functional/application.py, mathics/builtin/functional/apply_fns_to_lists.py, mathics/builtin/functional/functional_iteration.py, @@ -366,7 +388,7 @@ (#927) and another 2023-10-15 Juan Mauricio Matera -@@ -3254,7 +3254,7 @@ +@@ -3744,7 +3744,7 @@ 2023-08-14 mmatera * test/builtin/list/test_association.py, @@ -375,7 +397,7 @@ adding pytests modules for list 2023-08-13 mmatera -@@ -3275,7 +3275,7 @@ +@@ -3765,7 +3765,7 @@ mathics/builtin/image/geometric.py, mathics/builtin/image/misc.py, mathics/builtin/image/pixel.py, mathics/builtin/image/properties.py, @@ -384,7 +406,7 @@ Moving private doctests to pytest for assignment and image (#901) Just another round Co-authored-by: R. Bernstein 2023-08-12 R. Bernstein -@@ -3285,7 +3285,7 @@ +@@ -3775,7 +3775,7 @@ 2023-08-12 rocky * mathics/builtin/image/basic.py: tolerate various Threshold values; @@ -393,7 +415,7 @@ 2023-08-12 rocky -@@ -3500,7 +3500,7 @@ +@@ -3990,7 +3990,7 @@ 2023-07-21 Juan Mauricio Matera @@ -402,7 +424,7 @@ trailing changes (#887) This PR fixes the `RealSign` docstring and removes a trailing unreachable piece of code in the `eval_Sign` function. -@@ -3595,7 +3595,7 @@ +@@ -4085,7 +4085,7 @@ 2023-07-10 rocky @@ -411,7 +433,7 @@ Combine CProfiling and Tracing Both are pretty short and it makes the overall organization more coherent. (Should both code grow a lot, we can create a directory to make this a "Guide Section". -@@ -3719,9 +3719,9 @@ +@@ -4209,9 +4209,9 @@ * mathics/builtin/drawing/graphics3d.py, mathics/builtin/drawing/graphics_internals.py, @@ -423,7 +445,7 @@ 2023-06-01 R. Bernstein -@@ -3760,7 +3760,7 @@ +@@ -4250,7 +4250,7 @@ 2023-05-28 rocky * mathics/builtin/files_io/filesystem.py, mathics/core/number.py: Go @@ -432,7 +454,7 @@ 2023-05-28 R. Bernstein -@@ -3815,7 +3815,7 @@ +@@ -4305,7 +4305,7 @@ mathics/builtin/string/operations.py, mathics/builtin/string/patterns.py, mathics/builtin/vectors/math_ops.py, mathics/core/convert/regex.py, @@ -441,7 +463,7 @@ passing callables instead of Evaluation when messages are required. 2023-05-24 Juan Mauricio Matera -@@ -3901,13 +3901,13 @@ +@@ -4391,13 +4391,13 @@ * mathics/builtin/atomic/strings.py, mathics/builtin/atomic/symbols.py, @@ -457,7 +479,7 @@ 3.11 supported Note in regexp conversion function the change that needs to go on. 2023-05-08 R. Bernstein -@@ -3942,7 +3942,7 @@ +@@ -4432,7 +4432,7 @@ 2023-04-25 Juan Mauricio Matera @@ -466,7 +488,7 @@ Enclosing autoload Limit rules between Begin/End context (#842) This just adds the Begin/End block to the `autoload/rules/Limit.m` module. The `BeginPackage` is not used here because we are not trying to define a package, but just to define the default context. -@@ -4060,7 +4060,7 @@ +@@ -4550,7 +4550,7 @@ 2023-04-06 Juan Mauricio Matera @@ -475,7 +497,7 @@ Arithmetic refactor 0 (#826) Another smaller chunk of #766. 2023-04-06 Juan Mauricio Matera -@@ -4073,7 +4073,7 @@ +@@ -4563,7 +4563,7 @@ mathics/builtin/string/operations.py, mathics/builtin/testing_expressions/equality_inequality.py, mathics/core/atoms.py, mathics/core/convert/mpmath.py, @@ -484,7 +506,7 @@ Expression constants (#831) This comes from #828. Here a new module is added to contain the expression constants of the form `DirectedInfinity[...]`. -@@ -4102,7 +4102,7 @@ +@@ -4592,7 +4592,7 @@ 2023-03-25 rocky * SYMBOLS_MANIFEST.txt, mathics/builtin/atomic/symbols.py, @@ -493,7 +515,7 @@ Go over mathics.builtin.image.colors Remove ColorCombine which does not work Move pytests out of doctests 2023-03-23 rocky -@@ -4327,7 +4327,7 @@ +@@ -4817,7 +4817,7 @@ 2023-02-23 rocky * mathics/doc/documentation/1-Manual.mdoc: Wolfram Alpha -> Wolfram @@ -502,7 +524,7 @@ 2023-02-23 rocky -@@ -4364,7 +4364,7 @@ +@@ -4854,7 +4854,7 @@ 2023-02-17 rocky * mathics/doc/latex/Makefile: Use UTF-8 for MATHICS_ENCODING in @@ -511,7 +533,7 @@ 2023-02-17 R. Bernstein -@@ -4421,7 +4421,7 @@ +@@ -4911,7 +4911,7 @@ mathics/builtin/statistics/dependency.py, mathics/builtin/string/operations.py, mathics/builtin/system.py, mathics/core/convert/mpmath.py, mathics/core/parser/convert.py, @@ -520,7 +542,7 @@ Flake8 cleans (#791) Just another round of cleaning 2023-02-16 Juan Mauricio Matera -@@ -4436,7 +4436,7 @@ +@@ -4926,7 +4926,7 @@ 2023-02-14 Juan Mauricio Matera * mathics/builtin/arithfns/basic.py, mathics/builtin/arithmetic.py, @@ -529,7 +551,7 @@ move basic arithmetic to mathics.eval.arithmetic (#789) This PR starts to move the context independent arithmetic to a separate module. Interestingly, just by moving around a little piece of code, the doctest time seems to be reduced in another 10 seconds -@@ -4445,7 +4445,7 @@ +@@ -4935,7 +4935,7 @@ 2023-02-13 Juan Mauricio Matera * mathics/builtin/files_io/files.py, @@ -538,7 +560,7 @@ removing the use of Evaluation.format_output in builtins (#786) This PR fixes an issue reported by @rocky, where the behavior or `Put` was modified when is was called from mathics-server. Now, in `mathics.builtin` all the references to `format_output` which is -@@ -4458,7 +4458,7 @@ +@@ -4948,7 +4948,7 @@ 2023-02-11 rocky @@ -547,7 +569,7 @@ Better document what's up in the PCL file also change Makefile target doc-data -> doctest-data 2023-02-11 rocky -@@ -4632,7 +4632,7 @@ +@@ -5122,7 +5122,7 @@ 2023-02-04 rocky * mathics/builtin/assignments/assignment.py, @@ -556,7 +578,7 @@ mathics.core.pymathics -> mathics.eval.pymathics What is in mathics.eval is primarily for builtin LoadModule mathics.core are for atoms, symbols, parsing, conversion - things at the very lowest level that aren't focused directly around evaluation of a particular Mathics3 builtin function. -@@ -4644,14 +4644,14 @@ +@@ -5134,14 +5134,14 @@ 2023-02-04 mmatera * mathics/core/convert/mpmath.py: removing prec and acc parameters @@ -573,7 +595,7 @@ improving precision handling in from_mpmath 2023-02-02 rocky -@@ -4678,7 +4678,7 @@ +@@ -5168,7 +5168,7 @@ mathics/core/convert/mpmath.py, mathics/core/convert/sympy.py, mathics/core/number.py, mathics/core/parser/convert.py, test/builtin/colors/test_colors.py: renaming constants according to @@ -582,7 +604,7 @@ arithmetic/precision code. 2023-02-01 R. Bernstein -@@ -4873,7 +4873,7 @@ +@@ -5363,7 +5363,7 @@ 2023-01-17 Juan Mauricio Matera * mathics/builtin/box/image.py, mathics/builtin/image/base.py, @@ -591,7 +613,7 @@ the PDF documentation. 2023-01-17 rocky -@@ -4915,12 +4915,12 @@ +@@ -5405,12 +5405,12 @@ 2023-01-14 rocky @@ -606,7 +628,7 @@ assigned - fix 2023-01-14 rocky -@@ -4948,7 +4948,7 @@ +@@ -5438,7 +5438,7 @@ mathics/builtin/numpy_utils/__init__.py, mathics/builtin/numpy_utils/without_numpy.py, mathics/builtin/options.py, mathics/core/expression.py: Last batch @@ -615,7 +637,7 @@ been converted Now that numpy is required we can remove the numpy simulation. Less homegrown code and more reliance on better maintained libraries == win. -@@ -5008,7 +5008,7 @@ +@@ -5498,7 +5498,7 @@ mathics/core/element.py, mathics/core/rules.py, mathics/core/systemsymbols.py, test/builtin/box/test_custom_boxexpression.py: Last of the @@ -624,7 +646,7 @@ 2023-01-12 rocky -@@ -5049,7 +5049,7 @@ +@@ -5539,7 +5539,7 @@ * mathics/algorithm/parts.py, mathics/builtin/base.py, mathics/builtin/box/layout.py, mathics/builtin/distance/numeric.py, mathics/builtin/list/constructing.py, @@ -633,7 +655,7 @@ apply->eval + spelling, long lines, etc. 2023-01-11 rocky -@@ -5068,7 +5068,7 @@ +@@ -5558,7 +5558,7 @@ 2023-01-11 rocky * .github/workflows/isort-and-black-checks.yml: Comment out @@ -642,7 +664,7 @@ 2023-01-11 rocky -@@ -5118,7 +5118,7 @@ +@@ -5608,7 +5608,7 @@ * mathics/builtin/attributes.py, mathics/builtin/functional/composition.py, mathics/builtin/inout.py, mathics/builtin/intfns/divlike.py, @@ -651,7 +673,7 @@ apply->eval and doc stuff some do changes and the usual stuff. 2023-01-10 R. Bernstein -@@ -5187,7 +5187,7 @@ +@@ -5677,7 +5677,7 @@ mathics/builtin/numbers/diffeqns.py, mathics/builtin/numbers/hyperbolic.py, mathics/builtin/numbers/linalg.py, mathics/builtin/numbers/trig.py, @@ -660,7 +682,7 @@ apply->eval go over trig fns & some hyperbolic... The usual eval->apply, long lines, Add Wiki + SymPy, mpmath to trig. Start hyperbolic for the same. More should be done in another PR. -@@ -5197,7 +5197,7 @@ +@@ -5687,7 +5687,7 @@ 2023-01-08 rocky @@ -669,7 +691,7 @@ NO_PARENTHESIS_EVER -> NEVER_ADD_PARENTHESIS thanks Tiago 2023-01-08 rocky -@@ -5384,7 +5384,7 @@ +@@ -5874,7 +5874,7 @@ mathics/builtin/forms/output.py, mathics/builtin/layout.py, mathics/builtin/list/associations.py, mathics/builtin/quantities.py, mathics/builtin/specialfns/gamma.py, @@ -678,7 +700,7 @@ showing... in docs because no header text. more apply->eval conversions misc doc tweaks 2023-01-03 R. Bernstein -@@ -5458,7 +5458,7 @@ +@@ -5948,7 +5948,7 @@ 2023-01-02 rocky @@ -687,7 +709,7 @@ Adjust tests. and comment graphics routine a little better 2023-01-02 rocky -@@ -5472,7 +5472,7 @@ +@@ -5962,7 +5962,7 @@ 2023-01-02 R. Bernstein @@ -696,7 +718,7 @@ 2023-01-01 R. Bernstein -@@ -5504,7 +5504,7 @@ +@@ -5994,7 +5994,7 @@ 2022-12-31 rocky * mathics/builtin/graphics.py, mathics/core/atoms.py, @@ -705,7 +727,7 @@ More url hacking. Make sure ref's are $ safe. 2022-12-30 rocky -@@ -5539,7 +5539,7 @@ +@@ -6029,7 +6029,7 @@ 2022-12-30 rocky * CHANGES.rst, mathics/builtin/image/misc.py, @@ -714,7 +736,7 @@ Split out Image Pixel operations Update CHANGES.rst for all of the splitting going on 2022-12-30 rocky -@@ -5581,7 +5581,7 @@ +@@ -6071,7 +6071,7 @@ 2022-12-29 rocky @@ -723,7 +745,7 @@ TextRecognize.png: data file for trying out OCR recognition 2022-12-29 R. Bernstein -@@ -5590,7 +5590,7 @@ +@@ -6080,7 +6080,7 @@ 2022-12-28 rocky @@ -732,7 +754,7 @@ streamline a little & document TODO's. 2022-12-28 rocky -@@ -5688,7 +5688,7 @@ +@@ -6178,7 +6178,7 @@ 2022-12-25 rocky @@ -741,7 +763,7 @@ Make a pass over importexport 2022-12-25 rocky -@@ -5723,7 +5723,7 @@ +@@ -6213,7 +6213,7 @@ 2022-12-25 rocky * mathics/__init__.py, mathics/doc/common_doc.py, mathics/main.py, @@ -750,7 +772,7 @@ 2022-12-25 R. Bernstein -@@ -5990,7 +5990,7 @@ +@@ -6480,7 +6480,7 @@ 2022-12-21 mmatera @@ -759,7 +781,7 @@ docstr url for files_io, intfns, list and trace 2022-12-24 R. Bernstein -@@ -6034,7 +6034,7 @@ +@@ -6524,7 +6524,7 @@ mathics/builtin/fileformats/htmlformat.py, mathics/builtin/fileformats/xmlformat.py, mathics/builtin/numeric.py: complete docstr url for fileformats, @@ -768,7 +790,7 @@ 2022-12-21 mmatera -@@ -6091,7 +6091,7 @@ +@@ -6581,7 +6581,7 @@ 2022-12-23 rocky * mathics/eval/image.py: Correct use of numpy bool type... remove a Builtin-specific "no-doc" module variable. Since this has @@ -777,7 +799,7 @@ modularization can *simplify* workarounds. 2022-12-23 rocky -@@ -6188,7 +6188,7 @@ +@@ -6678,7 +6678,7 @@ mathics/core/list.py, mathics/core/symbols.py, test/core/test_atoms.py: Correct singleton atoms and revise atom tests We were allocating singleton numbers/atoms like like Integer(1) more @@ -786,7 +808,7 @@ now checks *all* symbols for dissimilarity from one another. It also starts a test for object canonicalization, e.g. Integer(1) and Complex(Integer(1), Integer(0)) are the same object. In a few places we have propagate constants for number other than -@@ -6320,7 +6320,7 @@ +@@ -6810,7 +6810,7 @@ 2022-12-14 rocky @@ -795,7 +817,7 @@ Add WMA and other links 2022-12-14 rocky -@@ -6344,14 +6344,14 @@ +@@ -6834,14 +6834,14 @@ 2022-12-07 R. Bernstein @@ -812,7 +834,7 @@ to be rebased after this and #651 go in. 2022-12-07 rocky -@@ -6485,7 +6485,7 @@ +@@ -6975,7 +6975,7 @@ 2022-11-19 rocky @@ -821,7 +843,7 @@ get_module_doc move to mathics.doc.common_doc 2022-11-19 Juan Mauricio Matera -@@ -6510,13 +6510,13 @@ +@@ -7000,13 +7000,13 @@ mathics/builtin/scoping.py, mathics/{builtin/assignments/internals.py => core/assignment.py}, mathics/core/expression.py, mathics/core/list.py, @@ -837,7 +859,7 @@ added inside the routine, this static method got moved outside of the class. Later on, the modularity was fixed, but the hack persisted. These kinds of code smells side effects of poor communication. * Add function signature; straighten import issue * Put test_rules_patterns tests where they belong * Add note to add skipped example as a doctest ... When it gets fixed. * Changes suggested in PR review Move core-like assignment interals out of builtins and into core. -@@ -6546,7 +6546,7 @@ +@@ -7036,7 +7036,7 @@ 2022-11-12 rocky * mathics/core/pattern.py: Pattern_create -> Pattern.create It appears this was originally Pattern.create. I suspect due to bad @@ -846,7 +868,7 @@ added inside the routine, this static method got moved outside of the class. Later on, the modularity was fixed, but the hack persisted. These kinds of code smells side effects of poor communication. -@@ -6618,7 +6618,7 @@ +@@ -7108,7 +7108,7 @@ 2022-11-10 mmatera @@ -855,7 +877,7 @@ fix a bug that makes that URLSave always fails 2022-11-07 mmatera -@@ -6904,7 +6904,7 @@ +@@ -7394,7 +7394,7 @@ evaluation. As a result, we now use operator-to-{ascii,unicode}. operator-to-{unicode-wl} still needs adding. Some hard nl's on docstrings on Builtins have been removed since formatting doesn't handle that. Some methods and classes have been alphabeticed better. $CharacterEncoding now respects MATHICS_CHARACTER_ENCODING @@ -864,7 +886,7 @@ 2022-10-04 rocky -@@ -6978,7 +6978,7 @@ +@@ -7468,7 +7468,7 @@ 2022-09-18 Juan Mauricio Matera @@ -873,7 +895,7 @@ moving pending doctests in MakeBoxes to pytests (#558) * moving pending doctests in MakeBoxes to pytests * improving tests and mark what is working now * xfailed optional 2022-09-16 R. Bernstein -@@ -7005,7 +7005,7 @@ +@@ -7495,7 +7495,7 @@ test/builtin/atomic/test_numbers.py: Go over docs for Accuracy and Precision * Shy away from using markup that doesn't render properly in Django. In partuclar, math mode * Add Wiki and WMA links in Accuracy and Precision builtin @@ -882,7 +904,7 @@ character 2022-09-13 Juan Mauricio Matera -@@ -7023,7 +7023,7 @@ +@@ -7513,7 +7513,7 @@ mathics/builtin/numbers/randomnumbers.py, mathics/core/convert/function.py, mathics/core/element.py, mathics/core/symbols.py: This is one part of #551, plus several @@ -891,7 +913,7 @@ ``expr.to_python(n_evaluation=evaluation)`` in favor of ``eval_N(expr, evaluation).to_python()`` * adding several comments. -@@ -7056,7 +7056,7 @@ +@@ -7546,7 +7546,7 @@ 2022-09-11 mmatera @@ -900,7 +922,7 @@ improving Accuracy docstring. fixing a typo 2022-09-11 mmatera -@@ -7088,7 +7088,7 @@ +@@ -7578,7 +7578,7 @@ 2022-09-09 mmatera @@ -909,7 +931,7 @@ fix typo in docstring. Check the arguments in comparison. 2022-09-09 mmatera -@@ -7130,7 +7130,7 @@ +@@ -7620,7 +7620,7 @@ 2022-08-28 rocky * mathics/builtin/arithmetic.py, mathics/builtin/atomic/numbers.py, @@ -918,7 +940,7 @@ Add cache for running sympy with literals 2022-08-28 rocky -@@ -7147,7 +7147,7 @@ +@@ -7637,7 +7637,7 @@ mathics/builtin/base.py, mathics/core/atoms.py, mathics/core/convert/expression.py, mathics/core/element.py, mathics/core/expression.py, mathics/core/list.py, @@ -927,7 +949,7 @@ Start to make use of literalness... to reduce conversions If an object is_literal, then its value is the Python representation. Although there may be benefit in noting literals that do not have direct Python representations like Complex (as it currently is -@@ -7225,13 +7225,13 @@ +@@ -7715,13 +7715,13 @@ mathics/builtin/lists.py, mathics/builtin/numbers/exp.py, mathics/builtin/numbers/{exptrig.py => trig.py}, mathics/builtin/procedural.py, mathics/builtin/statistics/shape.py, @@ -943,7 +965,7 @@ KroneckerProduct signature fix was previous detected and fixed in docs but not in code 2022-08-25 R. Bernstein -@@ -7263,7 +7263,7 @@ +@@ -7753,7 +7753,7 @@ * mathics/builtin/atomic/numbers.py, mathics/builtin/list/rearrange.py, mathics/builtin/lists.py, mathics/builtin/numbers/algebra.py, @@ -952,7 +974,7 @@ removing duplicated 1 (#525) 2022-08-21 Juan Mauricio Matera -@@ -7376,7 +7376,7 @@ +@@ -7866,7 +7866,7 @@ 2022-08-14 rocky @@ -961,7 +983,7 @@ Go over parser/convert ... and have it create ListExpression for list expressions Try to make this less confusing by using more traditional Python practice, and add type annotations -@@ -7621,7 +7621,7 @@ +@@ -8111,7 +8111,7 @@ admin-tools/pyenv-versions, mathics/builtin/specialfns/elliptic.py, mathics/doc/tex/sed-hack.sh, mathics/version.py: Into 5.0.0.dev0 now... version.py: bump version Linking a section heading message up Mathics-Django. Remove it on @@ -970,7 +992,7 @@ 2022-07-31 R. Bernstein -@@ -7639,7 +7639,7 @@ +@@ -8129,7 +8129,7 @@ 2022-07-30 rocky @@ -979,7 +1001,7 @@ 2022-07-30 rocky -@@ -7720,7 +7720,7 @@ +@@ -8210,7 +8210,7 @@ mathics/builtin/intfns/combinatorial.py, mathics/builtin/specialfns/__init__.py, mathics/builtin/specialfns/bessel.py, @@ -988,7 +1010,7 @@ Allow text link in URL try it out and some small typos. There needs to be a corresponding change made in Django. -@@ -7734,7 +7734,7 @@ +@@ -8224,7 +8224,7 @@ 2022-07-27 Juan Mauricio Matera @@ -997,7 +1019,7 @@ adding controls for the number of arguments (#472) * adding controls for the number of arguments * Update elliptic.py 2022-07-27 rocky -@@ -7847,7 +7847,7 @@ +@@ -8337,7 +8337,7 @@ 2022-07-24 R. Bernstein @@ -1006,7 +1028,7 @@ 2022-07-24 rocky -@@ -7881,7 +7881,7 @@ +@@ -8371,7 +8371,7 @@ 2022-07-24 rocky * mathics/builtin/intfns/divlike.py: Tweak ModularInverse doc @@ -1015,7 +1037,7 @@ 2022-07-24 rocky -@@ -7890,7 +7890,7 @@ +@@ -8380,7 +8380,7 @@ 2022-07-24 rocky * mathics/doc/common_doc.py, mathics/docpipeline.py: WIP - start to @@ -1024,7 +1046,7 @@ 2022-07-24 R. Bernstein -@@ -7962,7 +7962,7 @@ +@@ -8452,7 +8452,7 @@ * mathics/builtin/atomic/symbols.py, mathics/builtin/scoping.py, mathics/core/definitions.py: Reinstate documenting "Scoping @@ -1033,7 +1055,7 @@ don't run pytest kinds of tests in doctest. A pytest should be written here. I fear the entire module was disabled because too many of the tests were flaky. -@@ -8050,7 +8050,7 @@ +@@ -8540,7 +8540,7 @@ * mathics/builtin/atomic/strings.py, mathics/core/element.py, mathics/core/systemsymbols.py: Move SymbolOutputForm & other @@ -1042,7 +1064,7 @@ 2022-07-21 R. Bernstein -@@ -8084,7 +8084,7 @@ +@@ -8574,7 +8574,7 @@ 2022-07-20 rocky @@ -1051,7 +1073,7 @@ significantly 2022-07-19 rocky -@@ -8232,15 +8232,15 @@ +@@ -8722,15 +8722,15 @@ mathics/builtin/numbers/calculus.py, mathics/builtin/scipy_utils/optimizers.py, mathics/core/convert/function.py, mathics/core/expression.py, @@ -1070,7 +1092,7 @@ Nuke the python3 This was misguided and it hinders our ability to run pyston 2022-07-15 R. Bernstein -@@ -8389,7 +8389,7 @@ +@@ -8879,7 +8879,7 @@ mathics/builtin/string/operations.py, mathics/core/atoms.py, mathics/core/convert/expression.py, mathics/core/convert/mpmath.py, mathics/core/convert/python.py, mathics/core/evaluation.py, @@ -1079,7 +1101,7 @@ Move from_pyton to convert module 2022-06-22 rocky -@@ -8610,7 +8610,7 @@ +@@ -9100,7 +9100,7 @@ * .github/workflows/windows.yml, CHANGES.rst, mathics/builtin/__init__.py, mathics/builtin/base.py, @@ -1088,7 +1110,7 @@ more control over tests and doctest 2022-06-19 R. Bernstein -@@ -8628,7 +8628,7 @@ +@@ -9118,7 +9118,7 @@ mathics/builtin/scipy_utils/integrators.py, mathics/builtin/scipy_utils/optimizers.py, mathics/builtin/system.py, mathics/core/util.py, @@ -1097,7 +1119,7 @@ Changes to allow PyPy to build and mostly run ... we can get through pytests and the Gries & Schneider tests. There is probably a PyPy bug or weirdness around `Binarize`: ``` In[1]:= img = Import["ExampleData/lena.tif"] Out[1]= -Image- In[2]:= Binarize[img] terminate called after throwing an instance of 'pybind11::error_already_set' what(): IndentationError: -@@ -8660,7 +8660,7 @@ +@@ -9150,7 +9150,7 @@ * mathics/builtin/list/associations.py, mathics/builtin/list/constructing.py, mathics/builtin/list/eol.py, mathics/builtin/numbers/diffeqns.py, @@ -1106,7 +1128,7 @@ 72 more conversions to go And the usual imports and class variable ordering, and docstring tagging canonicalization -@@ -8723,7 +8723,7 @@ +@@ -9213,7 +9213,7 @@ mathics/builtin/matrices/constrmatrix.py, mathics/builtin/sparse.py, mathics/builtin/string/operations.py, mathics/builtin/tensors.py, mathics/core/systemsymbols.py, @@ -1115,7 +1137,7 @@ ...) removal and other Expressions as well 2022-06-15 R. Bernstein -@@ -8785,7 +8785,7 @@ +@@ -9275,7 +9275,7 @@ 2022-06-12 Juan Mauricio Matera * mathics/algorithm/integrators.py, @@ -1124,7 +1146,7 @@ fixing NIntegrate to make the internal integrators available. (#363) 2022-06-12 R. Bernstein -@@ -8811,7 +8811,7 @@ +@@ -9301,7 +9301,7 @@ 2022-06-10 rocky * mathics/builtin/numbers/numbertheory.py, mathics/core/convert.py, @@ -1133,7 +1155,7 @@ Expression -> ListExpression penultimate 2022-06-09 R. Bernstein -@@ -8852,7 +8852,7 @@ +@@ -9342,7 +9342,7 @@ mathics/builtin/box/graphics.py, mathics/builtin/box/inout.py, mathics/builtin/colors/color_directives.py, mathics/builtin/colors/color_operations.py, @@ -1142,7 +1164,7 @@ Expression(SymbolList -> ListExpression... or to_mathics_ilst 2022-06-09 R. Bernstein -@@ -8863,7 +8863,7 @@ +@@ -9353,7 +9353,7 @@ * mathics/builtin/attributes.py, mathics/builtin/options.py, mathics/core/convert.py, mathics/core/evaluation.py, @@ -1151,7 +1173,7 @@ {List,}Expression changes to pass test/builtins 2022-06-07 rocky -@@ -8900,8 +8900,8 @@ +@@ -9390,8 +9390,8 @@ 2022-06-07 rocky * mathics/builtin/list/eol.py, mathics/builtin/list/rearrange.py, @@ -1162,7 +1184,7 @@ 2022-06-07 R. Bernstein -@@ -8997,7 +8997,7 @@ +@@ -9487,7 +9487,7 @@ mathics/builtin/scipy_utils/optimizers.py, test/builtin/files_io/__init__.py, test/{ => builtin/files_io}/test_importexport.py: more about removing @@ -1171,7 +1193,7 @@ 2022-06-06 Juan Mauricio Matera -@@ -9011,7 +9011,7 @@ +@@ -9501,7 +9501,7 @@ 2022-06-06 Juan Mauricio Matera @@ -1180,7 +1202,7 @@ adding a test to check that builtin classes are properly documented. Complete documentation for mathics.builtin.graphics and mathics.builtin.numbers.algebra (#341) -@@ -9028,7 +9028,7 @@ +@@ -9518,7 +9518,7 @@ 2022-06-05 rocky * mathics/algorithm/optimizers.py, mathics/algorithm/series.py, @@ -1189,7 +1211,7 @@ Use .value, .leaves and fix some bugs optimizers.py: * Was missing Integer0 import - a bug * use .value when we know the object in an Integer * remove duplicate function series.py: ome more Expression("XXX"...) removed lists.py: Make another pass over this others: more of the same -@@ -9084,7 +9084,7 @@ +@@ -9574,7 +9574,7 @@ * mathics/builtin/base.py, mathics/builtin/drawing/plot.py, mathics/builtin/files_io/importexport.py, mathics/builtin/graphics.py, mathics/builtin/options.py, @@ -1198,7 +1220,7 @@ More of the same... Partial go over of graphics, importexport, options, operations, and plot, More work could be done on graphics, and plot, but that is left for later. This is already large. Also another pass over everything to improve specific calls is -@@ -9125,8 +9125,8 @@ +@@ -9615,8 +9615,8 @@ 2022-06-03 rocky @@ -1209,7 +1231,7 @@ that will come as a later step. 2022-06-02 rocky -@@ -9181,7 +9181,7 @@ +@@ -9671,7 +9671,7 @@ mathics/core/atoms.py, mathics/core/convert.py, mathics/core/expression.py, mathics/core/symbols.py, mathics/core/systemsymbols.py, @@ -1218,7 +1240,7 @@ Use symbols in NumericOperators 2022-06-01 rocky -@@ -9350,7 +9350,7 @@ +@@ -9840,7 +9840,7 @@ 2022-05-28 rocky * CHANGES.rst, mathics/builtin/arithfns/basic.py, @@ -1227,7 +1249,7 @@ and small corrections 2022-05-28 rocky -@@ -9432,7 +9432,7 @@ +@@ -9922,7 +9922,7 @@ * CHANGES.rst, mathics/algorithm/simplify.py, mathics/builtin/numbers/algebra.py, mathics/builtin/numbers/calculus.py, mathics/core/systemsymbols.py, @@ -1236,7 +1258,7 @@ 2022-05-24 R. Bernstein -@@ -9447,7 +9447,7 @@ +@@ -9937,7 +9937,7 @@ mathics/core/element.py, mathics/core/expression.py, mathics/core/symbols.py, test/test_format.py: Expression and Symbol are EvalMixin (#293) * adding tests * simplify get_option_values * improve get_option_values * renaming InstanceableBuiltin-> BuiltinElement and BoxConstruct -> @@ -1245,7 +1267,7 @@ Co-authored-by: rocky 2022-05-23 R. Bernstein -@@ -9505,7 +9505,7 @@ +@@ -9995,7 +9995,7 @@ * mathics/builtin/assignments/internals.py, mathics/builtin/base.py, mathics/builtin/box/graphics.py, mathics/builtin/inference.py, mathics/builtin/patterns.py, @@ -1254,7 +1276,7 @@ BaseElement.apply_rules-> BaseElement.do_apply_rules BoxConstruct now inherits from BaseElement -@@ -9526,7 +9526,7 @@ +@@ -10016,7 +10016,7 @@ 2022-05-17 mmatera @@ -1263,7 +1285,7 @@ recovered memory 2022-05-17 mmatera -@@ -9577,7 +9577,7 @@ +@@ -10067,7 +10067,7 @@ 2022-05-15 rocky @@ -1272,7 +1294,7 @@ Start using element_conversion_fn in Expression() 2022-05-15 rocky -@@ -9634,8 +9634,8 @@ +@@ -10124,8 +10124,8 @@ 2022-05-08 mmatera @@ -1283,7 +1305,7 @@ 2022-05-06 mmatera -@@ -9763,7 +9763,7 @@ +@@ -10253,7 +10253,7 @@ builtin}/test_assignment.py, test/helper.py: Use get_elements() (not _elements) ... get_elements is what element access uses. _elements is a private structure on Expression. Small tweaks to test_helper and move test/test_assignment.py into @@ -1292,7 +1314,7 @@ 2022-04-25 R. Bernstein -@@ -9789,7 +9789,7 @@ +@@ -10279,7 +10279,7 @@ 2022-04-24 rocky * mathics/builtin/base.py, mathics/core/evaluation.py, @@ -1301,7 +1323,7 @@ add element properties 2022-04-04 rocky -@@ -9854,7 +9854,7 @@ +@@ -10344,7 +10344,7 @@ mathics/builtin/graphics.py, mathics/core/atoms.py, mathics/core/element.py, mathics/core/streams.py, mathics/core/symbols.py: Fix merge conflicts. Revise Atom @@ -1310,7 +1332,7 @@ 2022-04-10 R. Bernstein -@@ -9900,7 +9900,7 @@ +@@ -10390,7 +10390,7 @@ 2022-03-28 rocky @@ -1319,7 +1341,7 @@ class where it makes sense. 2022-03-28 rocky -@@ -9909,7 +9909,7 @@ +@@ -10399,7 +10399,7 @@ 2022-03-27 rocky @@ -1328,7 +1350,7 @@ 2022-03-27 rocky -@@ -9937,7 +9937,7 @@ +@@ -10427,7 +10427,7 @@ 2022-04-01 mmatera @@ -1337,7 +1359,7 @@ more docstring fixes 2022-04-01 mmatera -@@ -9985,7 +9985,7 @@ +@@ -10475,7 +10475,7 @@ mathics/builtin/colors/named_colors.py, mathics/builtin/drawing/graphics3d.py, mathics/builtin/drawing/graphics_internals.py, @@ -1346,7 +1368,7 @@ fixing summary texts in builtin.box, and builtin.drawing. 2022-03-31 mmatera -@@ -10103,7 +10103,7 @@ +@@ -10593,7 +10593,7 @@ * mathics/builtin/numbers/linalg.py, mathics/builtin/numbers/numbertheory.py: summary_texts in @@ -1355,7 +1377,7 @@ 2022-03-26 mmatera -@@ -10137,7 +10137,7 @@ +@@ -10627,7 +10627,7 @@ 2022-03-24 mmatera @@ -1364,7 +1386,7 @@ comment 2022-03-24 mmatera -@@ -10296,7 +10296,7 @@ +@@ -10786,7 +10786,7 @@ 2022-03-20 Hannes Rüter @@ -1373,7 +1395,7 @@ Use python builtin escape function in GenericConverter 2022-03-20 rocky -@@ -10331,7 +10331,7 @@ +@@ -10821,7 +10821,7 @@ * mathics/builtin/compilation.py, mathics/builtin/numbers/calculus.py, @@ -1382,7 +1404,7 @@ Regularize recent summaries Summaries don't start out with a capital letter. Summaries don't end in a period. Make this more closely match form and idea reported on Mathematica site -@@ -10407,7 +10407,7 @@ +@@ -10897,7 +10897,7 @@ 2022-03-19 rocky @@ -1391,7 +1413,7 @@ Tolerate Unicode in parser testing 2022-03-18 R. Bernstein -@@ -10430,7 +10430,7 @@ +@@ -10920,7 +10920,7 @@ 2022-03-17 Tiago Cavalcante Trindade @@ -1400,7 +1422,7 @@ method remove 2022-03-17 R. Bernstein -@@ -10475,7 +10475,7 @@ +@@ -10965,7 +10965,7 @@ test/test_combinatorica.py, test/test_control.py, test/test_datentime.py, test/test_strings.py, test/test_structure.py: Improving Clear and ClearAll (#199) * adding a reset method to MathicsSession. Using it to reset the @@ -1409,7 +1431,7 @@ warning messages. * improving test initialization using pytest.fixture * improving reset in tests * Change in the logic of ``test.helper.check_evaluation``: now, if the parameter ``to_string_expected`` is ``True``, ``str_expected`` is considered as a literal, that should match with -@@ -10608,7 +10608,7 @@ +@@ -11098,7 +11098,7 @@ 2022-03-06 mmatera @@ -1418,7 +1440,7 @@ leaves->boxes 2022-02-28 mmatera -@@ -10646,7 +10646,7 @@ +@@ -11136,7 +11136,7 @@ 2022-03-06 rocky * mathics/core/atoms.py, mathics/core/expression.py: Make a stab @@ -1427,7 +1449,7 @@ 2022-03-05 R. Bernstein -@@ -10774,7 +10774,7 @@ +@@ -11264,7 +11264,7 @@ 2022-02-24 Juan Mauricio Matera * CHANGES.rst, mathics/builtin/numbers/algebra.py, @@ -1436,7 +1458,7 @@ Extend `Simplify` to handle the `Assumptions` argument more correctly (#170) * fixes 167 * fix integrate * improve FullSimplify rules -@@ -10884,7 +10884,7 @@ +@@ -11374,7 +11374,7 @@ * mathics/builtin/base.py, mathics/builtin/list/__init__.py, mathics/builtin/patterns.py, mathics/core/expression.py, @@ -1445,7 +1467,7 @@ leaf_{count{,s},index} -> element_* 2022-02-20 rocky -@@ -10902,7 +10902,7 @@ +@@ -11392,7 +11392,7 @@ 2022-02-20 mmatera @@ -1454,7 +1476,7 @@ small remaining fix 2022-02-20 mmatera -@@ -10957,7 +10957,7 @@ +@@ -11447,7 +11447,7 @@ mathics/builtin/box/graphics.py, mathics/builtin/compilation.py, mathics/builtin/files_io/importexport.py, mathics/builtin/inference.py, mathics/builtin/inout.py, @@ -1463,7 +1485,7 @@ More leaf/leaves -> element(s) conversion 2022-02-20 rocky -@@ -10973,7 +10973,7 @@ +@@ -11463,7 +11463,7 @@ mathics/builtin/drawing/graphics3d.py, mathics/builtin/numbers/algebra.py, mathics/builtin/options.py, mathics/builtin/string/charcodes.py, @@ -1472,7 +1494,7 @@ leaf -> element replacement There are more, but I need to batch changes so I can narrow in case CI fails -@@ -11011,7 +11011,7 @@ +@@ -11501,7 +11501,7 @@ mathics/core/pattern.py, mathics/core/read.py, mathics/core/rules.py, mathics/core/subexpression.py, mathics/core/symbols.py, mathics/format/svg.py, mathics/main.py, @@ -1481,7 +1503,7 @@ Start converting leaves -> elements elements is the term Mathematica uses. It is a perfectly appropriate term. "leaves" is just plain wrong. -@@ -11028,7 +11028,7 @@ +@@ -11518,7 +11518,7 @@ 2022-02-13 rocky @@ -1490,7 +1512,7 @@ docstring 2022-02-13 R. Bernstein -@@ -11106,7 +11106,7 @@ +@@ -11596,7 +11596,7 @@ mathics/builtin/numbers/exptrig.py, mathics/builtin/numbers/integer.py, mathics/builtin/numbers/numbertheory.py, @@ -1499,7 +1521,7 @@ Make a pass separating atomic.numbers from numeric 2022-02-02 mmatera -@@ -11226,7 +11226,7 @@ +@@ -11716,7 +11716,7 @@ which are necessarily not a NValues rule. N[expr, prec, Method->method] establishes the preferred method, by storing it in the queue property _preferred_n_method of the Evaluation object. * get_precision -> Optional[float] * Ensure precision is float and tidy... (#140) We were inconsistent about the type returned in precision. Also @@ -1508,7 +1530,7 @@ figure out. also a stray import things noticed by my editor. Co-authored-by: R. Bernstein 2022-01-25 mmatera -@@ -11289,7 +11289,7 @@ +@@ -11779,7 +11779,7 @@ * mathics/builtin/lists.py, mathics/builtin/procedural.py, mathics/core/evaluation.py, mathics/core/expression.py, mathics/core/interrupt.py, mathics/main.py: clean imports, reduce @@ -1517,7 +1539,7 @@ expression.py * Correct return type of Expression.evaluate() * remove unused imports including those that are imported improperly elsewhere * import from a module only once 2022-01-22 mmatera -@@ -11899,7 +11899,7 @@ +@@ -12389,7 +12389,7 @@ * mathics/builtin/assignments/assignment.py, mathics/builtin/assignments/clear.py, mathics/builtin/assignments/internals.py, @@ -1526,7 +1548,7 @@ Split out assignment upvalies and clear operations 2021-10-16 rocky -@@ -11927,11 +11927,11 @@ +@@ -12417,11 +12417,11 @@ * CHANGES.rst, mathics/builtin/trace.py, mathics/core/rules.py, mathics/main.py, test/test_cli.py: Add TraceBuiltins. I moved the @@ -1541,7 +1563,7 @@ 2021-10-03 rocky -@@ -11962,7 +11962,7 @@ +@@ -12452,7 +12452,7 @@ * .editorconfig, .github/workflows/osx.yml, .github/workflows/ubuntu-cython.yml, .github/workflows/ubuntu.yml, .github/workflows/windows.yml, CHANGES.rst, Makefile, @@ -1550,7 +1572,7 @@ running Cython Set environment variable NO_CYTHON before running setup.py to avoid running Cython even if it is installed. Go over CHANGE.rst (note NO_CYTHON) Blacken setup.py Remove Cython except once on Ubuntu 3.9 Go over workflows, and extensions Makefile: - when running develop include development Python modules - add a develop target that includes Cython .github: - Simplify by using improved develop-full and develop-full- cython target -@@ -12042,7 +12042,7 @@ +@@ -12532,7 +12532,7 @@ mathics/autoload/formats/Asy/Export.m, mathics/core/atoms.py, mathics/core/convert.py, mathics/core/expression.py, mathics/core/read.py, mathics/core/streams.py, @@ -1559,7 +1581,7 @@ SymbolMakeBoxes goes into symbols.py move systemsymbols used in symbols.py to symbols.py improving handling of circular reference flake8 flake8 2021-09-21 Tiago Cavalcante Trindade -@@ -12113,7 +12113,7 @@ +@@ -12603,7 +12603,7 @@ mathics/system_info.py, test/test_arithmetic.py, test/test_compile.py, test/test_formatter/test_asy.py, test/test_formatter/test_svg.py, test/test_hash.py, @@ -1568,7 +1590,7 @@ get_style_class() -> style_class Remove useless check The code was checking if a builtin which ends with "Box" is None, in this case it can't be None, because "Box" is only added if the non-box version of that builtin exists Remove useless imports Remove useless None checking That was never None, and if that be, an -@@ -12159,7 +12159,7 @@ +@@ -12649,7 +12649,7 @@ 2021-09-17 rocky * mathics/builtin/assignment.py, test/test_assignment.py, @@ -1577,7 +1599,7 @@ Functions. This text currently appears in Django when it is listed in a group. See for example "Operations on Strings". This PR expands that use so that this short text also appears when `?xxx` or Information[xxx, LongForm->False]` is requested. Add tests for `?` and `??` -@@ -12358,7 +12358,7 @@ +@@ -12848,7 +12848,7 @@ 2021-08-25 mmatera * mathics/builtin/numbers/constants.py, @@ -1586,7 +1608,7 @@ revert some cases... fixup: Format Python code with Black 2021-08-25 mmatera -@@ -12587,7 +12587,7 @@ +@@ -13077,7 +13077,7 @@ 2021-08-07 rocky * CHANGES.rst, mathics/builtin/numeric.py, @@ -1595,7 +1617,7 @@ Add more spherical Bessel Functions 2021-08-07 rocky -@@ -12639,7 +12639,7 @@ +@@ -13129,7 +13129,7 @@ 2021-08-03 rocky @@ -1604,7 +1626,7 @@ Aymptote: scale needs to come before figure Cuboid 2nd example. Possible workaround to ensure the 2nd test gets into the doc. -@@ -13104,7 +13104,7 @@ +@@ -13594,7 +13594,7 @@ 2021-07-01 rocky @@ -1613,7 +1635,7 @@ what's up and find and fix the bug. 2021-07-01 rocky -@@ -13319,7 +13319,7 @@ +@@ -13809,7 +13809,7 @@ 2021-06-24 rocky @@ -1622,7 +1644,7 @@ Revert theta use for now. 2021-06-24 rocky -@@ -13395,14 +13395,14 @@ +@@ -13885,14 +13885,14 @@ color_internals.py Note drawing/color_internals.py used to be somewhat vague name drawing/colors.py. But really it just had internal color routines. drawing/colors.py was selected because that's what the Section name is in WL https://reference.wolfram.com/language/guide/Colors.html @@ -1641,7 +1663,7 @@ Move spline functions to drawing 2021-06-22 Tiago Cavalcante Trindade -@@ -13492,7 +13492,7 @@ +@@ -13982,7 +13982,7 @@ 2021-06-18 rocky @@ -1650,7 +1672,7 @@ Asymptote should use evenodd crossing in polygons Like WL does. SVG was changed a little recently in another PR. 2021-06-18 rocky -@@ -13603,7 +13603,7 @@ +@@ -14093,7 +14093,7 @@ 2021-06-06 rocky @@ -1659,7 +1681,7 @@ docpipeline: add --exclude option to exclude tests 2021-06-06 rocky -@@ -13620,7 +13620,7 @@ +@@ -14110,7 +14110,7 @@ 2021-06-07 rocky @@ -1668,7 +1690,7 @@ Move Some FullForm tests to unit testing 2021-06-07 rocky -@@ -13651,7 +13651,7 @@ +@@ -14141,7 +14141,7 @@ 2021-06-07 rocky @@ -1677,7 +1699,7 @@ Allow PointSize option to pass through to 3D box 2021-06-07 rocky -@@ -13665,7 +13665,7 @@ +@@ -14155,7 +14155,7 @@ 2021-06-06 rocky @@ -1686,7 +1708,7 @@ Two more color examples 2021-06-06 rocky -@@ -13779,7 +13779,7 @@ +@@ -14269,7 +14269,7 @@ 2021-05-31 rb@dustyfeet.conf * mathics/builtin/numbers/constants.py: Go over Pi doc to make @@ -1695,7 +1717,7 @@ 2021-05-31 rb@dustyfeet.conf -@@ -13814,7 +13814,7 @@ +@@ -14304,7 +14304,7 @@ 2021-05-24 R. Bernstein @@ -1704,7 +1726,7 @@ 2021-05-24 rocky -@@ -13830,7 +13830,7 @@ +@@ -14320,7 +14320,7 @@ 2021-05-22 rocky @@ -1713,7 +1735,7 @@ Make pyston 2.2 compatible 2021-05-23 R. Bernstein -@@ -14144,7 +14144,7 @@ +@@ -14634,7 +14634,7 @@ 2021-05-04 rocky @@ -1722,7 +1744,7 @@ Unprotect All and Subsets.. These are prerequisites for having Combinatorica V2.0 to load without given errors. Combinatorica v2.0 (the version that is on par with the latest book) is starting to work, although testing shows it is not as good as -@@ -14261,7 +14261,7 @@ +@@ -14751,7 +14751,7 @@ mathics/builtin/files_io/__init__.py, mathics/builtin/{ => files_io}/files.py, mathics/builtin/{ => files_io}/filesystem.py, mathics/builtin/{ => files_io}/importexport.py, mathics/builtin/{ @@ -1731,7 +1753,7 @@ Segregate I/O, Files, and Filesystem builtins 2021-05-01 R. Bernstein -@@ -14359,7 +14359,7 @@ +@@ -14849,7 +14849,7 @@ 2021-04-30 rocky * CHANGES.rst, mathics/builtin/logic.py: Add logical operations: @@ -1740,7 +1762,7 @@ ConditionalExpressions. 2021-04-30 mmatera -@@ -14377,7 +14377,7 @@ +@@ -14867,7 +14867,7 @@ 2021-04-28 rocky @@ -1749,7 +1771,7 @@ 2021-04-28 Juan Mauricio Matera -@@ -14479,7 +14479,7 @@ +@@ -14969,7 +14969,7 @@ * mathics/builtin/__init__.py, mathics/builtin/algebra.py, mathics/builtin/arithmetic.py, mathics/builtin/bessel.py, mathics/builtin/erf.py, mathics/builtin/legendre.py, @@ -1758,7 +1780,7 @@ Split and Sort specialfunctions This is in preparation for bigger refactoring. 2021-04-25 rocky -@@ -14767,7 +14767,7 @@ +@@ -15257,7 +15257,7 @@ 2021-04-14 Juan Mauricio Matera @@ -1767,7 +1789,7 @@ methods to isolate logic. * Extensive comparison tests were added in test/test_compare.py which use make use of the Commutative property of Equal. * Equal, Unequal, SameQ and UnsameQ docs gone over and make explicit the commutative aspect of these operators * Integer1 symbolic constant introduced. -@@ -15055,7 +15055,7 @@ +@@ -15545,7 +15545,7 @@ 2021-03-31 mmatera @@ -1776,7 +1798,7 @@ conditions in SetDelayed 2021-03-31 Juan Mauricio Matera -@@ -15132,7 +15132,7 @@ +@@ -15622,7 +15622,7 @@ 2021-03-14 mmatera * mathics/builtin/strings.py, mathics/core/expression.py, @@ -1785,7 +1807,7 @@ boxes_to_text and ToString 2021-03-28 R. Bernstein -@@ -15175,7 +15175,7 @@ +@@ -15665,7 +15665,7 @@ * mathics/autoload/settings.m, mathics/main.py: Microsoft Windows-inspired fixes settings.m: a non-ASCII character got in here main.py: remove debug @@ -1794,7 +1816,7 @@ 2021-03-27 rocky -@@ -15184,7 +15184,7 @@ +@@ -15674,7 +15674,7 @@ 2021-03-27 mmatera @@ -1803,7 +1825,7 @@ implementing Conditions in LHS blacken 2021-03-26 R. Bernstein -@@ -15233,7 +15233,7 @@ +@@ -15723,7 +15723,7 @@ 2021-03-25 R. Bernstein @@ -1812,7 +1834,7 @@ 2021-03-25 rocky -@@ -15276,7 +15276,7 @@ +@@ -15766,7 +15766,7 @@ * CHANGES.rst, mathics/builtin/comparison.py, mathics/builtin/compilation.py, mathics/builtin/numbertheory.py, @@ -1821,7 +1843,7 @@ Make a pass over documents Include deletion in conjunction of worksheets. Go over typographical setting in various new docs. -@@ -15318,7 +15318,7 @@ +@@ -15808,7 +15808,7 @@ * mathics/builtin/arithmetic.py, mathics/builtin/base.py, mathics/builtin/numbertheory.py, mathics/core/convert.py: Try @@ -1830,7 +1852,7 @@ optimistic that by starting this as we add more Sympy functions we will be making more use of this. I think it is better to have one way that is used regularly than open-code this a number of places. -@@ -15331,7 +15331,7 @@ +@@ -15821,7 +15821,7 @@ 2021-03-19 rocky @@ -1839,7 +1861,7 @@ Redo PartionsP using SymPy... alphabetize numbertheory functions. 2021-03-19 R. Bernstein -@@ -15393,7 +15393,7 @@ +@@ -15883,7 +15883,7 @@ 2021-03-14 mmatera @@ -1848,7 +1870,7 @@ blacked 2021-03-14 mmatera -@@ -15422,7 +15422,7 @@ +@@ -15912,7 +15912,7 @@ 2021-02-20 mmatera @@ -1857,7 +1879,7 @@ Implementing Compile for non compilable llvmlite functions as python functions -@@ -15538,7 +15538,7 @@ +@@ -16028,7 +16028,7 @@ test/test_arithmetic.py, test/test_convert.py, test/test_datentime.py, test/test_file.py, test/test_hash.py, test/test_numpy_utils.py, test/test_parser/test_parser.py: More M$ @@ -1866,7 +1888,7 @@ 2021-03-09 mmatera -@@ -15558,7 +15558,7 @@ +@@ -16048,7 +16048,7 @@ 2021-03-09 rocky @@ -1875,7 +1897,7 @@ Try Windows CI. One more duplicate key commented out 2021-03-09 Juan Mauricio Matera -@@ -15777,7 +15777,7 @@ +@@ -16267,7 +16267,7 @@ 2021-02-28 rocky @@ -1884,7 +1906,7 @@ More lint-like things 2021-02-27 rocky -@@ -15839,7 +15839,7 @@ +@@ -16329,7 +16329,7 @@ 2021-02-21 mmatera @@ -1893,7 +1915,7 @@ https://github.com/mathics/Mathics/pull/1160#pullrequestreview-594830742 -@@ -15855,7 +15855,7 @@ +@@ -16345,7 +16345,7 @@ 2021-02-07 mmatera @@ -1902,7 +1924,7 @@ inactivating show tests for Information in documentation 2021-02-06 mmatera -@@ -15889,7 +15889,7 @@ +@@ -16379,7 +16379,7 @@ 2021-02-20 mmatera @@ -1911,7 +1933,7 @@ Implementing Compile for non compilable llvmlite functions as python functions -@@ -16023,7 +16023,7 @@ +@@ -16513,7 +16513,7 @@ 2021-02-07 mmatera @@ -1920,7 +1942,7 @@ inactivating show tests for Information in documentation 2021-02-07 rocky -@@ -16064,7 +16064,7 @@ +@@ -16554,7 +16554,7 @@ 2021-02-06 mmatera @@ -1929,7 +1951,7 @@ fixing accuracy 2021-02-06 mmatera -@@ -16111,7 +16111,7 @@ +@@ -16601,7 +16601,7 @@ 2021-02-06 rocky @@ -1938,7 +1960,7 @@ Use a released version of mathics-parser 2021-02-06 mmatera -@@ -16773,7 +16773,7 @@ +@@ -17263,7 +17263,7 @@ 2020-12-31 mmatera * mathics/builtin/xmlformat.py, mathics/core/characters.py, @@ -1947,7 +1969,7 @@ misc 2020-12-31 mmatera -@@ -18039,7 +18039,7 @@ +@@ -18529,7 +18529,7 @@ 2020-11-19 mmatera @@ -1956,7 +1978,7 @@ improving Needs to do not load again packages already loaded 2020-11-16 mmatera -@@ -18095,7 +18095,7 @@ +@@ -18585,7 +18585,7 @@ 2020-12-20 rocky @@ -1965,7 +1987,7 @@ Small doc improvements. 2020-12-20 R. Bernstein -@@ -18290,7 +18290,7 @@ +@@ -18780,7 +18780,7 @@ 2020-12-07 rocky @@ -1974,7 +1996,7 @@ Tuples[expr_, n_] -> Tuples[expr_, n_Integer]... since that's what we currently handle. In the future we should expand to Tuples[{list1, list2, ...}] Some white space and blackening done too. 2020-12-07 rocky -@@ -18511,7 +18511,7 @@ +@@ -19001,7 +19001,7 @@ 2020-11-22 rocky * mathics/packages/DiscreteMath/CombinatoricaLite.m, @@ -1983,7 +2005,7 @@ Expand via combinatorica 0.6 routines From combinatorica 0.6 add: * BinarySearch, * KSubsets, From combinatorica 2.0 add: * Compostions, * CyclicGroup, * DihedralGroupIndex, * OrbitInventory, * KSetPartitions, * TransposePartition * SetPartitions * LastLexicogrpahicTableau Add test/helper.py to DRY testing. 2020-11-22 R. Bernstein -@@ -18575,7 +18575,7 @@ +@@ -19065,7 +19065,7 @@ examples/combinatorica/test-c.sh, examples/test_driver.m, examples/combinatorica/c-small.m => mathics/autoload/combinatorica/CombinatoricaSmall.m, @@ -1992,7 +2014,7 @@ Add CombinatorcaSmall as an autoload package 2020-11-21 rocky -@@ -18584,7 +18584,7 @@ +@@ -19074,7 +19074,7 @@ 2020-11-21 rocky @@ -2001,7 +2023,7 @@ Failed attempt at adding binary search 2020-11-21 rocky -@@ -18604,7 +18604,7 @@ +@@ -19094,7 +19094,7 @@ examples/symbolic_logic/gries_schneider/GS1.m, examples/symbolic_logic/gries_schneider/GS2.m, examples/symbolic_logic/gries_schneider/GS3.m, @@ -2010,7 +2032,7 @@ Start combinatorica examples Basically try the examples in the first page of the book. The test harness has been move from GS0.m to test_driver.m so we can reuse it. (It really doesn't have anything to do with Gries-Schneider -@@ -18683,7 +18683,7 @@ +@@ -19173,7 +19173,7 @@ 2020-11-14 mmatera @@ -2019,7 +2041,7 @@ protect 2020-11-14 mmatera -@@ -18807,7 +18807,7 @@ +@@ -19297,7 +19297,7 @@ 2020-10-26 mmatera @@ -2028,7 +2050,7 @@ fixing ReplaceAll tokenizer with lookahead regexp 2020-10-26 mmatera -@@ -18847,7 +18847,7 @@ +@@ -19337,7 +19337,7 @@ * mathics/builtin/integer.py, mathics/builtin/numeric.py, mathics/builtin/options.py, mathics/builtin/patterns.py, mathics/builtin/strings.py, @@ -2037,7 +2059,7 @@ Title Capitalization; StringInsert examples 2020-10-18 R. Bernstein -@@ -18915,7 +18915,7 @@ +@@ -19405,7 +19405,7 @@ 2020-10-15 rocky @@ -2046,7 +2068,7 @@ Simplify doc building And try not to duplication running tests 2020-10-15 rocky -@@ -18929,7 +18929,7 @@ +@@ -19419,7 +19419,7 @@ 2020-10-14 rocky @@ -2055,7 +2077,7 @@ Don't be sensitive in testing to SansSerif.. 2020-10-14 rocky -@@ -19096,7 +19096,7 @@ +@@ -19586,7 +19586,7 @@ 2020-10-07 rocky * mathics/builtin/datentime.py, mathics/builtin/evaluation.py, @@ -2064,7 +2086,7 @@ Add --keep-going, and --doc-only... And also go over more test doc descriptions. Fixes #947 2020-10-07 rocky -@@ -19424,7 +19424,7 @@ +@@ -19914,7 +19914,7 @@ 2016-10-13 Bernhard Liebl @@ -2073,7 +2095,7 @@ unification with _sequences 2016-10-13 Bernhard Liebl -@@ -21481,7 +21481,7 @@ +@@ -21971,7 +21971,7 @@ 2020-09-27 rocky @@ -2082,7 +2104,7 @@ 2020-09-27 Pablo Emilio Escobar Gaviria -@@ -21490,7 +21490,7 @@ +@@ -21980,7 +21980,7 @@ 2020-09-27 Pablo Emilio Escobar Gaviria * COPYING.txt, README.rst, mathics/doc/documentation/1-Manual.mdoc, @@ -2091,7 +2113,7 @@ Updated the links in the documentation to point to mathics.org instead of mathics.github.io -@@ -21598,7 +21598,7 @@ +@@ -22088,7 +22088,7 @@ 2020-09-19 mmatera @@ -2100,7 +2122,7 @@ fix export 2020-09-19 mmatera -@@ -21611,7 +21611,7 @@ +@@ -22101,7 +22101,7 @@ 2020-09-19 mmatera @@ -2109,7 +2131,7 @@ fixing 1-Manual.doc and Format 2020-09-19 mmatera -@@ -21794,11 +21794,11 @@ +@@ -22284,11 +22284,11 @@ 2020-09-16 Pablo Emilio Escobar Gaviria @@ -2123,7 +2145,7 @@ 2020-09-16 Gark Garcia <37553739+GarkGarcia@users.noreply.github.com> -@@ -22092,7 +22092,7 @@ +@@ -22582,7 +22582,7 @@ 2020-09-12 Gark Garcia <37553739+GarkGarcia@users.noreply.github.com> @@ -2132,7 +2154,7 @@ 2019-06-06 mmatera -@@ -22109,7 +22109,7 @@ +@@ -22599,7 +22599,7 @@ 2020-09-12 Gark Garcia <37553739+GarkGarcia@users.noreply.github.com> @@ -2141,7 +2163,7 @@ 2020-09-12 Gark Garcia <37553739+GarkGarcia@users.noreply.github.com> -@@ -22151,7 +22151,7 @@ +@@ -22641,7 +22641,7 @@ 2020-09-11 rocky @@ -2150,7 +2172,7 @@ 2020-09-11 Gark Garcia <37553739+GarkGarcia@users.noreply.github.com> -@@ -22223,7 +22223,7 @@ +@@ -22713,7 +22713,7 @@ 2020-09-11 Gark Garcia <37553739+GarkGarcia@users.noreply.github.com> * : Merge pull request #859 from @@ -2159,7 +2181,7 @@ 2020-09-11 Gark Garcia <37553739+GarkGarcia@users.noreply.github.com> -@@ -22491,7 +22491,7 @@ +@@ -22981,7 +22981,7 @@ 2020-09-06 rocky @@ -2168,7 +2190,7 @@ Fix two `python mathics/test.py -o` errors graphics.py extent(): For EdgeConnectivity[Graph[{}]] total_extent can return [None, None, None, None] for {x,y}m{in,max}. So check for this and dissallowing None *= 2 graphs.py _path_layout(): For PathGraph[{1, 2, 3}] neighbors is a -@@ -22653,7 +22653,7 @@ +@@ -23143,7 +23143,7 @@ 2020-08-29 Pablo Emilio Escobar Gaviria @@ -2177,7 +2199,7 @@ implementation 2020-08-29 Bernhard Liebl -@@ -23043,7 +23043,7 @@ +@@ -23533,7 +23533,7 @@ 2019-05-26 Сухарик @@ -2186,7 +2208,7 @@ Add big O conversion 2019-05-25 Сухарик -@@ -23320,7 +23320,7 @@ +@@ -23810,7 +23810,7 @@ 2017-03-20 Long Nguyen @@ -2195,7 +2217,7 @@ to_sympy errors handling 2017-03-20 Long Nguyen -@@ -23464,7 +23464,7 @@ +@@ -23954,7 +23954,7 @@ 2016-12-28 Angus Griffith <16sn6uv@gmail.com> @@ -2204,7 +2226,7 @@ cleanup parser code 2016-12-28 Angus Griffith <16sn6uv@gmail.com> -@@ -23477,7 +23477,7 @@ +@@ -23967,7 +23967,7 @@ mathics/core/parser/ast.py, mathics/core/parser/convert.py, mathics/core/parser/feed.py, mathics/core/parser/parser.py, mathics/core/parser/prescanner.py, @@ -2213,7 +2235,7 @@ fix #654 2016-12-28 Angus Griffith <16sn6uv@gmail.com> -@@ -24262,7 +24262,7 @@ +@@ -24752,7 +24752,7 @@ 2016-09-26 Bernhard Liebl @@ -2222,7 +2244,7 @@ added display="block" to fix Jupyter display problems 2016-09-25 Angus Griffith <16sn6uv@gmail.com> -@@ -24271,7 +24271,7 @@ +@@ -24761,7 +24761,7 @@ 2016-09-25 Bernhard Liebl @@ -2231,7 +2253,7 @@ fixes test cases 2016-09-25 Bernhard Liebl -@@ -24487,7 +24487,7 @@ +@@ -24977,7 +24977,7 @@ * mathics/builtin/__init__.py, mathics/builtin/compilation.py, mathics/builtin/compile/__init__.py, mathics/builtin/compile/base.py, mathics/builtin/compile/ir.py, @@ -2240,7 +2262,7 @@ implement Compile and CompiledFunction 2016-09-14 Angus Griffith <16sn6uv@gmail.com> -@@ -24607,7 +24607,7 @@ +@@ -25097,7 +25097,7 @@ 2016-09-20 Bernhard Liebl @@ -2249,7 +2271,7 @@ StringCases, Shortest, Longest 2016-09-20 Angus Griffith <16sn6uv@gmail.com> -@@ -24909,12 +24909,12 @@ +@@ -25399,12 +25399,12 @@ 2016-05-19 Bernhard Liebl @@ -2264,7 +2286,7 @@ $OutputSizeLimit support for OutputForm 2016-05-18 Bernhard Liebl -@@ -25091,7 +25091,7 @@ +@@ -25581,7 +25581,7 @@ 2016-09-11 Josh Chen * mathics/web/media/css/styles.css, @@ -2273,7 +2295,7 @@ Checkpoint commit before starting rewrite of undo-redo 2016-09-11 Piruzzolo -@@ -25156,7 +25156,7 @@ +@@ -25646,7 +25646,7 @@ 2016-09-10 Josh Chen * mathics/web/media/css/styles.css, @@ -2282,7 +2304,7 @@ Animate logo when working 2016-09-10 Josh Chen -@@ -25599,7 +25599,7 @@ +@@ -26089,7 +26089,7 @@ * mathics/builtin/colors.py, mathics/builtin/numpy_utils/with_numpy.py, @@ -2291,7 +2313,7 @@ work in progress: bug fixes, test cases 2016-06-16 Bernhard Liebl -@@ -25612,7 +25612,7 @@ +@@ -26102,7 +26102,7 @@ numpy_utils}/__init__.py, mathics/builtin/{numpy => numpy_utils}/with_numpy.py, mathics/builtin/{numpy => numpy_utils}/without_numpy.py, mathics/builtin/randomnumbers.py, @@ -2300,7 +2322,7 @@ renamed package "numpy" back to "numpy_utils" 2016-06-16 Bernhard Liebl -@@ -25621,7 +25621,7 @@ +@@ -26111,7 +26111,7 @@ mathics/builtin/numpy/with_numpy.py, mathics/builtin/numpy/without_numpy.py, mathics/builtin/numpy_utils.py, mathics/builtin/randomnumbers.py, @@ -2309,7 +2331,7 @@ moved numpy_utils into a new "numpy" package 2016-06-15 Bernhard Liebl -@@ -25658,7 +25658,7 @@ +@@ -26148,7 +26148,7 @@ 2016-06-14 Bernhard Liebl * mathics/builtin/colors.py, mathics/builtin/graphics.py, @@ -2318,7 +2340,7 @@ work in progress: color conversion with and without numpy 2016-06-05 Bernhard Liebl -@@ -25862,7 +25862,7 @@ +@@ -26352,7 +26352,7 @@ 2016-08-22 Bernhard Liebl @@ -2327,7 +2349,7 @@ fixes for to_sympy in non-binary comparisons, fixes for Piecewise[] 2016-08-19 Bernhard Liebl -@@ -25957,7 +25957,7 @@ +@@ -26447,7 +26447,7 @@ 2016-07-17 Bernhard Liebl @@ -2336,7 +2358,7 @@ silhouette and dunn as default k criteria; use fsum where possible; major cleanup -@@ -26021,7 +26021,7 @@ +@@ -26511,7 +26511,7 @@ 2016-07-09 Bernhard Liebl @@ -2345,7 +2367,7 @@ ClusteringComponents[]: better test cases, fixes a bug with Agglomerate -@@ -26036,7 +26036,7 @@ +@@ -26526,7 +26526,7 @@ 2016-07-09 Bernhard Liebl @@ -2354,7 +2376,7 @@ DistanceFunction option for FindClusters[] 2016-07-09 Bernhard Liebl -@@ -26328,7 +26328,7 @@ +@@ -26818,7 +26818,7 @@ 2016-04-27 Bernhard Liebl @@ -2363,7 +2385,7 @@ basic support for images (python 3 version) 2016-08-16 Bernhard Liebl -@@ -26543,7 +26543,7 @@ +@@ -27033,7 +27033,7 @@ 2016-08-09 Bernhard Liebl @@ -2372,7 +2394,7 @@ cleanup 2016-08-09 Bernhard Liebl -@@ -26621,7 +26621,7 @@ +@@ -27111,7 +27111,7 @@ 2016-08-06 Angus Griffith <16sn6uv@gmail.com> @@ -2381,7 +2403,7 @@ MachineReal unittests 2016-08-05 Angus Griffith <16sn6uv@gmail.com> -@@ -26810,7 +26810,7 @@ +@@ -27300,7 +27300,7 @@ 2016-07-29 Angus Griffith <16sn6uv@gmail.com> @@ -2390,7 +2412,7 @@ implement mpmath machine precision workaround 2016-07-29 Angus Griffith <16sn6uv@gmail.com> -@@ -26873,7 +26873,7 @@ +@@ -27363,7 +27363,7 @@ 2016-07-21 Angus Griffith <16sn6uv@gmail.com> * mathics/builtin/exptrig.py, mathics/builtin/numeric.py, @@ -2399,7 +2421,7 @@ MachineReal support for N 2016-07-21 Angus Griffith <16sn6uv@gmail.com> -@@ -27366,7 +27366,7 @@ +@@ -27856,7 +27856,7 @@ 2016-07-06 Angus Griffith <16sn6uv@gmail.com> @@ -2408,7 +2430,7 @@ fix #431 and #274 2016-07-05 Angus Griffith <16sn6uv@gmail.com> -@@ -27383,7 +27383,7 @@ +@@ -27873,7 +27873,7 @@ * mathics/builtin/arithmetic.py, mathics/builtin/calculus.py, mathics/builtin/control.py, mathics/builtin/exptrig.py, mathics/builtin/graphics3d.py, mathics/builtin/linalg.py, @@ -2417,7 +2439,7 @@ fix some precision tests 2016-07-04 Angus Griffith <16sn6uv@gmail.com> -@@ -27592,12 +27592,12 @@ +@@ -28082,12 +28082,12 @@ 2016-06-23 Angus Griffith <16sn6uv@gmail.com> @@ -2432,7 +2454,7 @@ remove ExpressionGenerator 2016-06-22 Angus Griffith <16sn6uv@gmail.com> -@@ -27613,7 +27613,7 @@ +@@ -28103,7 +28103,7 @@ 2016-06-22 Angus Griffith <16sn6uv@gmail.com> @@ -2441,7 +2463,7 @@ flatten unary plus too 2016-06-22 Angus Griffith <16sn6uv@gmail.com> -@@ -27627,7 +27627,7 @@ +@@ -28117,7 +28117,7 @@ 2016-06-22 Angus Griffith <16sn6uv@gmail.com> @@ -2450,7 +2472,7 @@ fix operator precedences 2016-06-21 Angus Griffith <16sn6uv@gmail.com> -@@ -27738,7 +27738,7 @@ +@@ -28228,7 +28228,7 @@ 2016-06-18 Angus Griffith <16sn6uv@gmail.com> @@ -2459,7 +2481,7 @@ tokeniser modes 2016-06-18 Angus Griffith <16sn6uv@gmail.com> -@@ -27775,7 +27775,7 @@ +@@ -28265,7 +28265,7 @@ 2016-06-16 Angus Griffith <16sn6uv@gmail.com> @@ -2468,7 +2490,7 @@ add Backslash token (different to RawBackslash) 2016-06-16 Angus Griffith <16sn6uv@gmail.com> -@@ -27792,12 +27792,12 @@ +@@ -28282,12 +28282,12 @@ 2016-06-16 Angus Griffith <16sn6uv@gmail.com> @@ -2483,7 +2505,7 @@ tokenise slot symb 2016-06-16 Angus Griffith <16sn6uv@gmail.com> -@@ -27926,7 +27926,7 @@ +@@ -28416,7 +28416,7 @@ 2016-06-12 Angus Griffith <16sn6uv@gmail.com> @@ -2492,7 +2514,7 @@ boolean op parsing 2016-06-12 Angus Griffith <16sn6uv@gmail.com> -@@ -27936,7 +27936,7 @@ +@@ -28426,7 +28426,7 @@ 2016-06-12 Angus Griffith <16sn6uv@gmail.com> * mathics/core/parser/ast.py, mathics/core/parser/operators.py, @@ -2501,7 +2523,7 @@ inequality parsing 2016-06-12 Angus Griffith <16sn6uv@gmail.com> -@@ -27967,7 +27967,7 @@ +@@ -28457,7 +28457,7 @@ 2016-06-10 Angus Griffith <16sn6uv@gmail.com> @@ -2510,7 +2532,7 @@ fix Postfix parsing 2016-06-10 Angus Griffith <16sn6uv@gmail.com> -@@ -28074,12 +28074,12 @@ +@@ -28564,12 +28564,12 @@ 2016-06-06 Angus Griffith <16sn6uv@gmail.com> @@ -2525,7 +2547,7 @@ implement all_operator_names 2016-06-06 Angus Griffith <16sn6uv@gmail.com> -@@ -28134,7 +28134,7 @@ +@@ -28624,7 +28624,7 @@ 2016-06-05 Angus Griffith <16sn6uv@gmail.com> @@ -2534,7 +2556,7 @@ Prefix @ parsing 2016-06-05 Angus Griffith <16sn6uv@gmail.com> -@@ -28148,7 +28148,7 @@ +@@ -28638,7 +28638,7 @@ 2016-06-05 Angus Griffith <16sn6uv@gmail.com> @@ -2543,7 +2565,7 @@ postfix parsing 2016-06-05 Angus Griffith <16sn6uv@gmail.com> -@@ -28173,7 +28173,7 @@ +@@ -28663,7 +28663,7 @@ 2016-06-05 Angus Griffith <16sn6uv@gmail.com> @@ -2552,7 +2574,7 @@ fix integral parsing 2016-06-05 Angus Griffith <16sn6uv@gmail.com> -@@ -28186,7 +28186,7 @@ +@@ -28676,7 +28676,7 @@ 2016-06-05 Angus Griffith <16sn6uv@gmail.com> @@ -2561,7 +2583,7 @@ fix repreated int bug 2016-06-05 Angus Griffith <16sn6uv@gmail.com> -@@ -28206,12 +28206,12 @@ +@@ -28696,12 +28696,12 @@ 2016-06-05 Angus Griffith <16sn6uv@gmail.com> @@ -2576,7 +2598,7 @@ defaultdict for all_ops 2016-06-05 Angus Griffith <16sn6uv@gmail.com> -@@ -28246,7 +28246,7 @@ +@@ -28736,7 +28736,7 @@ 2016-06-04 Angus Griffith <16sn6uv@gmail.com> @@ -2585,7 +2607,7 @@ cleanup parser tests 2016-06-04 Angus Griffith <16sn6uv@gmail.com> -@@ -28301,7 +28301,7 @@ +@@ -28791,7 +28791,7 @@ 2016-06-04 Angus Griffith <16sn6uv@gmail.com> @@ -2594,7 +2616,7 @@ rename ParseError to TranslateError 2016-06-04 Angus Griffith <16sn6uv@gmail.com> -@@ -28318,7 +28318,7 @@ +@@ -28808,7 +28808,7 @@ mathics/core/parser/ast.py, mathics/core/parser/convert.py, mathics/core/parser/errors.py, mathics/core/parser/operators.py, mathics/core/parser/parser.py, mathics/core/parser/prescanner.py, @@ -2603,7 +2625,7 @@ recursive descent parser 2016-06-12 Angus Griffith <16sn6uv@gmail.com> -@@ -28744,7 +28744,7 @@ +@@ -29234,7 +29234,7 @@ 2016-05-10 Bernhard Liebl @@ -2612,7 +2634,7 @@ reorganization with existing DeleteDuplicates, Complement (work in progress) -@@ -29341,7 +29341,7 @@ +@@ -29831,7 +29831,7 @@ 2016-02-14 Angus Griffith <16sn6uv@gmail.com> @@ -2621,7 +2643,7 @@ patch unittest encoding 2016-02-14 Angus Griffith <16sn6uv@gmail.com> -@@ -29408,7 +29408,7 @@ +@@ -29898,7 +29898,7 @@ 2016-02-12 Angus Griffith <16sn6uv@gmail.com> @@ -2630,7 +2652,7 @@ fixup pickle binary read/write 2016-02-12 Angus Griffith <16sn6uv@gmail.com> -@@ -29456,7 +29456,7 @@ +@@ -29946,7 +29946,7 @@ 2016-02-11 Angus Griffith <16sn6uv@gmail.com> @@ -2639,7 +2661,7 @@ fix failed byte tests 2016-02-11 Angus Griffith <16sn6uv@gmail.com> -@@ -29576,7 +29576,7 @@ +@@ -30066,7 +30066,7 @@ mathics/web/media/js/authentication.js, mathics/web/media/js/doc.js, mathics/web/media/js/inout.js, mathics/web/media/js/mathics.js, mathics/web/media/js/utils.js, @@ -2648,7 +2670,7 @@ update license headers 2015-08-03 Angus Griffith <16sn6uv@gmail.com> -@@ -29632,7 +29632,7 @@ +@@ -30122,7 +30122,7 @@ * mathics/benchmark.py, mathics/builtin/arithmetic.py, mathics/builtin/calculus.py, mathics/core/evaluation.py, @@ -2657,7 +2679,7 @@ remove old style exceptions 2015-08-03 Angus Griffith <16sn6uv@gmail.com> -@@ -29779,7 +29779,7 @@ +@@ -30269,7 +30269,7 @@ 2015-09-12 mauricio @@ -2666,7 +2688,7 @@ Removing tabs from the code. modified: mathics/builtin/strings.py 2015-09-11 Juan Mauricio Matera -@@ -29946,7 +29946,7 @@ +@@ -30436,7 +30436,7 @@ * mathics/builtin/importexport.py, mathics/doc/documentation/1-Manual.mdoc, setup.py, @@ -2675,7 +2697,7 @@ drop python 2.6 support 2015-06-22 Angus Griffith <16sn6uv@gmail.com> -@@ -30221,7 +30221,7 @@ +@@ -30711,7 +30711,7 @@ * mathics/__init__.py, mathics/builtin/algebra.py, mathics/builtin/arithmetic.py, mathics/builtin/exptrig.py, mathics/builtin/numeric.py, mathics/builtin/specialfunctions.py, @@ -2684,7 +2706,7 @@ prepare for sympy/mpmath unbundle 2015-05-16 Ben Jones -@@ -30355,7 +30355,7 @@ +@@ -30845,7 +30845,7 @@ 2014-12-09 Ben Jones @@ -2693,7 +2715,7 @@ doc: disambiguate Context and $Context Django's default slugify function removes all non-alphanumeric characters, including ones that are significant in symbol names, like $ and `. This meant that although Context and $Context both -@@ -30673,12 +30673,12 @@ +@@ -31163,12 +31163,12 @@ 2013-09-28 Angus Griffith <16sn6uv@gmail.com> @@ -2708,7 +2730,7 @@ replace unittest with unittest2 2013-09-24 Angus Griffith <16sn6uv@gmail.com> -@@ -30976,7 +30976,7 @@ +@@ -31466,7 +31466,7 @@ 2014-02-21 Ben Jones @@ -2717,7 +2739,7 @@ Replace --show-contexts option with DEBUG_CONTEXTS setting 2014-02-21 Ben Jones -@@ -31554,7 +31554,7 @@ +@@ -32044,7 +32044,7 @@ 2013-10-20 Angus Griffith <16sn6uv@gmail.com> * mathics/doc/images.sh, mathics/doc/tex/Makefile, @@ -2726,7 +2748,7 @@ documentation tweaks 2013-10-21 Angus Griffith <16sn6uv@gmail.com> -@@ -33257,7 +33257,7 @@ +@@ -33747,7 +33747,7 @@ mathics/web/media/js/authentication.js, mathics/web/media/js/doc.js, mathics/web/media/js/inout.js, mathics/web/media/js/mathics.js, mathics/web/media/js/utils.js, @@ -2735,7 +2757,7 @@ Copyright is 2011-2013 The Mathics Team 2013-04-29 Angus Griffith <16sn6uv@gmail.com> -@@ -33629,7 +33629,7 @@ +@@ -34119,7 +34119,7 @@ * mathics/builtin/arithmetic.py, mathics/builtin/datentime.py, mathics/builtin/exptrig.py, mathics/builtin/inout.py, mathics/builtin/linalg.py, mathics/builtin/lists.py, @@ -2744,7 +2766,7 @@ correct some tests 2013-04-02 Angus Griffith <16sn6uv@gmail.com> -@@ -33979,7 +33979,7 @@ +@@ -34469,7 +34469,7 @@ 2013-04-21 Angus Griffith <16sn6uv@gmail.com> @@ -2753,7 +2775,7 @@ cleanup setting python recursion limit 2013-04-21 Angus Griffith <16sn6uv@gmail.com> -@@ -34127,7 +34127,7 @@ +@@ -34617,7 +34617,7 @@ 2013-03-07 Angus Griffith <16sn6uv@gmail.com> @@ -2762,7 +2784,7 @@ implement Coordinates, Paramaters, CoordinatRanges and ParamaterRanges -@@ -34142,7 +34142,7 @@ +@@ -34632,7 +34632,7 @@ 2013-03-06 Angus Griffith <16sn6uv@gmail.com> @@ -2771,7 +2793,7 @@ Implement CrossProduct DotProduct and ScalarTripleProduct 2013-03-20 Jan Pöschko -@@ -34208,7 +34208,7 @@ +@@ -34698,7 +34698,7 @@ 2013-02-26 Angus Griffith <16sn6uv@gmail.com> @@ -2780,7 +2802,7 @@ MPMathFunctions should use sympy on symbolic arguments not just exact numbers -@@ -34320,7 +34320,7 @@ +@@ -34810,7 +34810,7 @@ 2013-03-08 mr.Shu @@ -2789,7 +2811,7 @@ added CSS 2013-03-08 mr.Shu -@@ -34503,7 +34503,7 @@ +@@ -34993,7 +34993,7 @@ 2012-12-26 Angus Griffith <16sn6uv@gmail.com> @@ -2798,7 +2820,7 @@ fix bug in ReadList: graceful fail 2012-12-25 Angus Griffith <16sn6uv@gmail.com> -@@ -34515,7 +34515,7 @@ +@@ -35005,7 +35005,7 @@ 2012-12-26 Angus Griffith <16sn6uv@gmail.com> * mathics/builtin/importexport.py, @@ -2807,7 +2829,7 @@ cleanup Import tests 2012-12-26 Angus Griffith <16sn6uv@gmail.com> -@@ -34574,7 +34574,7 @@ +@@ -35064,7 +35064,7 @@ 2013-02-28 Angus Griffith <16sn6uv@gmail.com> @@ -2816,7 +2838,7 @@ correct $RecursionLimit tests 2013-02-26 Jan Pöschko -@@ -35793,7 +35793,7 @@ +@@ -36283,7 +36283,7 @@ 2012-10-26 Angus Griffith <16sn6uv@gmail.com> @@ -2825,7 +2847,7 @@ optimise RandomReal 100x 2012-10-26 Angus Griffith <16sn6uv@gmail.com> -@@ -35999,7 +35999,7 @@ +@@ -36489,7 +36489,7 @@ 2012-10-13 Angus Griffith <16sn6uv@gmail.com> @@ -2834,7 +2856,7 @@ formatting for Real, 1772 passed, 28 failed 2012-10-13 Angus Griffith <16sn6uv@gmail.com> -@@ -36023,7 +36023,7 @@ +@@ -36513,7 +36513,7 @@ 2012-10-13 Angus Griffith <16sn6uv@gmail.com> @@ -2843,7 +2865,7 @@ precision handling for Plus, fix precision bug in Real, fix formatting bug in Complex, 1756 passed, 39 failed -@@ -36054,7 +36054,7 @@ +@@ -36544,7 +36544,7 @@ 2012-10-12 Angus Griffith <16sn6uv@gmail.com> @@ -2852,7 +2874,7 @@ improvements to sympy (0.7.2) fix some issues, 1750 passed, 43 failed -@@ -36071,7 +36071,7 @@ +@@ -36561,7 +36561,7 @@ 2012-10-11 Angus Griffith <16sn6uv@gmail.com> @@ -2861,7 +2883,7 @@ fix Binomial precision 2012-10-11 Angus Griffith <16sn6uv@gmail.com> -@@ -36092,7 +36092,7 @@ +@@ -36582,7 +36582,7 @@ 2012-10-10 Angus Griffith <16sn6uv@gmail.com> @@ -2870,7 +2892,7 @@ Changed failed tests in which the new result is more accurate, 1650 passed, 140 failed -@@ -36163,7 +36163,7 @@ +@@ -36653,7 +36653,7 @@ 2012-10-08 Angus Griffith <16sn6uv@gmail.com> @@ -2879,7 +2901,7 @@ fix some complex arithmetic bugs, 1627 passed, 160 failed 2012-10-07 Angus Griffith <16sn6uv@gmail.com> -@@ -36196,7 +36196,7 @@ +@@ -36686,7 +36686,7 @@ 2012-10-05 Angus Griffith <16sn6uv@gmail.com> @@ -2888,7 +2910,7 @@ Replace gmpy.bincoef with mpmath.binomial 2012-10-05 Angus Griffith <16sn6uv@gmail.com> -@@ -36274,7 +36274,7 @@ +@@ -36764,7 +36764,7 @@ 2012-09-10 Angus Griffith <16sn6uv@gmail.com> @@ -2897,7 +2919,7 @@ 2012-09-10 Angus Griffith <16sn6uv@gmail.com> -@@ -36332,7 +36332,7 @@ +@@ -36822,7 +36822,7 @@ 2012-09-09 Angus Griffith <16sn6uv@gmail.com> * mathics/builtin/diffeqns.py, mathics/core/convert.py: Added some @@ -2906,7 +2928,7 @@ 2012-09-09 Angus Griffith <16sn6uv@gmail.com> -@@ -36444,12 +36444,12 @@ +@@ -36934,12 +36934,12 @@ 2012-09-08 Angus Griffith <16sn6uv@gmail.com> @@ -2921,7 +2943,7 @@ ThermalConductivity for ElementData 2012-09-08 Angus Griffith <16sn6uv@gmail.com> -@@ -36469,7 +36469,7 @@ +@@ -36959,7 +36959,7 @@ 2012-09-07 Angus Griffith <16sn6uv@gmail.com> @@ -2930,7 +2952,7 @@ ElectronAffinity 2012-09-07 Angus Griffith <16sn6uv@gmail.com> -@@ -36633,7 +36633,7 @@ +@@ -37123,7 +37123,7 @@ 2012-08-24 Angus Griffith <16sn6uv@gmail.com> * mathics/builtin/calculus.py, mathics/builtin/diffeqns.py, @@ -2939,7 +2961,7 @@ 2012-08-24 Angus Griffith <16sn6uv@gmail.com> -@@ -36858,7 +36858,7 @@ +@@ -37348,7 +37348,7 @@ 2012-08-04 Jan Pöschko * mathics/builtin/graphics.py, mathics/builtin/graphics3d.py, @@ -2948,7 +2970,7 @@ documentation 2012-08-04 Jan Pöschko -@@ -36887,7 +36887,7 @@ +@@ -37377,7 +37377,7 @@ 2012-08-03 Jan Pöschko @@ -2957,7 +2979,7 @@ handle parser exception 2012-08-04 Angus Griffith <16sn6uv@gmail.com> -@@ -36929,7 +36929,7 @@ +@@ -37419,7 +37419,7 @@ 2012-08-02 Angus Griffith <16sn6uv@gmail.com> @@ -2966,7 +2988,7 @@ Add ViewPoint option to client-side graphics 2012-08-02 Angus Griffith <16sn6uv@gmail.com> -@@ -36952,12 +36952,12 @@ +@@ -37442,12 +37442,12 @@ 2012-08-02 Angus Griffith <16sn6uv@gmail.com> @@ -2981,7 +3003,7 @@ Move default Point color bug fix to server-side 2012-08-02 Angus Griffith <16sn6uv@gmail.com> -@@ -36982,7 +36982,7 @@ +@@ -37472,7 +37472,7 @@ 2012-07-31 Angus Griffith <16sn6uv@gmail.com> @@ -2990,7 +3012,7 @@ Move graphics box scaling from client-side to server-side 2012-07-31 Angus Griffith <16sn6uv@gmail.com> -@@ -37044,7 +37044,7 @@ +@@ -37534,7 +37534,7 @@ 2012-07-29 Angus Griffith <16sn6uv@gmail.com> @@ -2999,7 +3021,7 @@ Add sphere rendering method to client-side 2012-07-28 Angus Griffith <16sn6uv@gmail.com> -@@ -37053,7 +37053,7 @@ +@@ -37543,7 +37543,7 @@ 2012-07-28 Angus Griffith <16sn6uv@gmail.com> @@ -3008,7 +3030,7 @@ Fix Spot light angle 2012-07-28 Angus Griffith <16sn6uv@gmail.com> -@@ -37082,7 +37082,7 @@ +@@ -37572,7 +37572,7 @@ 2012-07-27 Angus Griffith <16sn6uv@gmail.com> @@ -3017,7 +3039,7 @@ Fix Spot light angle TODO: Convert degrees input to radians. E.g. 15Degree becomes 0.2618. -@@ -37093,7 +37093,7 @@ +@@ -37583,7 +37583,7 @@ 2012-07-27 Angus Griffith <16sn6uv@gmail.com> @@ -3026,7 +3048,7 @@ Add Point and Spot lights 2012-07-27 Angus Griffith <16sn6uv@gmail.com> -@@ -37131,7 +37131,7 @@ +@@ -37621,7 +37621,7 @@ 2012-07-26 Jan Pöschko @@ -3035,7 +3057,7 @@ default face color in 3D is white 2012-07-26 Jan Pöschko -@@ -37156,7 +37156,7 @@ +@@ -37646,7 +37646,7 @@ 2012-07-25 Angus Griffith <16sn6uv@gmail.com> @@ -3044,7 +3066,7 @@ Replace tick label hack 2012-07-25 Angus Griffith <16sn6uv@gmail.com> -@@ -37223,7 +37223,7 @@ +@@ -37713,7 +37713,7 @@ 2012-07-23 Angus Griffith <16sn6uv@gmail.com> @@ -3053,7 +3075,7 @@ Use inbult methods to format axis tick labels 2012-07-20 Angus Griffith <16sn6uv@gmail.com> -@@ -37262,7 +37262,7 @@ +@@ -37752,7 +37752,7 @@ 2012-07-17 Angus Griffith <16sn6uv@gmail.com> @@ -3062,7 +3084,7 @@ Tick lines handled by server. 2012-07-16 Angus Griffith <16sn6uv@gmail.com> -@@ -37289,7 +37289,7 @@ +@@ -37779,7 +37779,7 @@ 2012-07-15 Angus Griffith <16sn6uv@gmail.com> @@ -3071,7 +3093,7 @@ Axes lines for Graphics3D. 2012-07-14 Angus Griffith <16sn6uv@gmail.com> -@@ -37423,7 +37423,7 @@ +@@ -37913,7 +37913,7 @@ 2012-07-04 Angus Griffith <16sn6uv@gmail.com> @@ -3080,7 +3102,7 @@ Accuracy of Plot3D grids is now the same as the plot itself. 2012-07-03 Angus Griffith <16sn6uv@gmail.com> -@@ -37531,7 +37531,7 @@ +@@ -38021,7 +38021,7 @@ 2012-06-30 Angus Griffith <16sn6uv@gmail.com> @@ -3089,7 +3111,7 @@ partially implemented 2012-06-29 Angus Griffith <16sn6uv@gmail.com> -@@ -37716,7 +37716,7 @@ +@@ -38206,7 +38206,7 @@ 2012-06-16 Jan Pöschko @@ -3098,7 +3120,7 @@ 2012-06-15 Jan Pöschko -@@ -37858,7 +37858,7 @@ +@@ -38348,7 +38348,7 @@ 2012-06-11 Angus Griffith <16sn6uv@gmail.com> @@ -3107,7 +3129,7 @@ rest of the code base 2012-06-11 Angus Griffith <16sn6uv@gmail.com> -@@ -37914,7 +37914,7 @@ +@@ -38404,7 +38404,7 @@ * mathics/builtin/plot.py: Implemented Mesh->All and Mesh->Full along with default Mesh->None something strange is happening with @@ -3116,7 +3138,7 @@ PlotRange . 2012-06-11 Angus Griffith <16sn6uv@gmail.com> -@@ -37971,7 +37971,7 @@ +@@ -38461,7 +38461,7 @@ 2012-06-09 Jan Pöschko @@ -3125,7 +3147,7 @@ PlotRange, to_python 2012-06-10 Angus Griffith <16sn6uv@gmail.com> -@@ -38024,7 +38024,7 @@ +@@ -38514,7 +38514,7 @@ * mathics/builtin/plot.py: Added x-scaling to the sampling algorithm so that angles are independent of x-range. All line segments of @@ -3134,7 +3156,7 @@ 2012-06-09 Angus Griffith <16sn6uv@gmail.com> -@@ -38156,7 +38156,7 @@ +@@ -38646,7 +38646,7 @@ 2012-04-19 Jan Pöschko @@ -3143,7 +3165,7 @@ MathJax config in document:loaded, minor interface text changes 2011-04-18 Jan Pöschko -@@ -39645,7 +39645,7 @@ +@@ -40135,7 +40135,7 @@ 2011-03-09 Jan Pöschko * mathics/builtin/arithmetic.py, mathics/core/evaluation.py, @@ -3152,7 +3174,7 @@ parser issue, threaded exception traceback 2011-03-09 Jan Pöschko -@@ -39678,7 +39678,7 @@ +@@ -40168,7 +40168,7 @@ * mathics/doc/doc.py, mathics/doc/documentation/1-Manual.mdoc, mathics/doc/tex/Makefile, mathics/doc/tex/logo.pdf, mathics/doc/tex/mathics.tex, mathics/doc/tex/prepare_latex.py, @@ -3161,7 +3183,7 @@ small changes to doc and setup 2011-03-07 Jan Pöschko -@@ -39706,4 +39706,3 @@ +@@ -40196,4 +40196,3 @@ 2011-03-07 Jan * initial version diff --git a/MANIFEST.in b/MANIFEST.in index a85198855..f999e8ceb 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -7,6 +7,8 @@ include Makefile include requirements-cython.txt include requirements-dev.txt include requirements-full.txt +include mathics/doc/latex/mathics.pdf recursive-include mathics *.py +recursive-include mathics/autoload * recursive-include mathics/data * -recursive-include test *.py *.m +recursive-include test *.py *.m *.wl diff --git a/SYMBOLS_MANIFEST.txt b/SYMBOLS_MANIFEST.txt index 2dd2e2bd8..6a4797982 100644 --- a/SYMBOLS_MANIFEST.txt +++ b/SYMBOLS_MANIFEST.txt @@ -63,6 +63,7 @@ System`$RandomState System`$RecursionLimit System`$RootDirectory System`$ScriptCommandLine +System`$SessionID System`$SyntaxHandler System`$SystemCharacterEncoding System`$SystemID @@ -157,6 +158,7 @@ System`BezierFunction System`Binarize System`BinaryImageQ System`BinaryRead +System`BinaryReadList System`BinaryWrite System`Binomial System`BitLength diff --git a/admin-tools/make-dist.sh b/admin-tools/make-dist.sh index c9c11c9e8..ee2c60978 100755 --- a/admin-tools/make-dist.sh +++ b/admin-tools/make-dist.sh @@ -16,7 +16,7 @@ fi cd .. source mathics/version.py -cp -v ${HOME}/.local/var/mathics/doctest_latex_data.pcl mathics/data/ +cp -v ${HOME}/.local/var/Mathics3/doctest_latex_data.pcl mathics/data/ echo $__version__ @@ -25,6 +25,5 @@ if ! pyenv local $pyversion ; then exit $? fi rm -fr build -python setup.py bdist_wheel -python ./setup.py sdist +python -m build finish diff --git a/examples/symbolic_logic/gries_schneider/test_gs.py b/examples/symbolic_logic/gries_schneider/test_gs.py index 19cd96d03..f2c74fc68 100644 --- a/examples/symbolic_logic/gries_schneider/test_gs.py +++ b/examples/symbolic_logic/gries_schneider/test_gs.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +from mathics_scanner.location import ContainerKind from mathics.core.definitions import Definitions from mathics.core.evaluation import Evaluation @@ -13,5 +14,8 @@ for i in range(0, 4): evaluation = Evaluation(definitions=definitions, catch_interrupt=False) - expr = parse(definitions, MathicsSingleLineFeeder(f"<< GS{i}.m")) + expr = parse( + definitions, + MathicsSingleLineFeeder(f"<< GS{i}.m", "", ContainerKind.STRING), + ) expr.evaluate(evaluation) diff --git a/mathics/autoload/formats/Asy/Export.m b/mathics/autoload/formats/Asy/Export.m index 303726377..380c2f2c4 100644 --- a/mathics/autoload/formats/Asy/Export.m +++ b/mathics/autoload/formats/Asy/Export.m @@ -1,4 +1,4 @@ -(* Text Exporter *) +(* Asymptote Exporter *) Begin["System`Convert`Asy`"] diff --git a/mathics/autoload/formats/CSV/Import.m b/mathics/autoload/formats/CSV/Import.m index ccd9e8c29..753b0b938 100644 --- a/mathics/autoload/formats/CSV/Import.m +++ b/mathics/autoload/formats/CSV/Import.m @@ -9,7 +9,7 @@ }; ImportCSV[stream_InputStream, OptionsPattern[]]:= - Module[{data, grid, sep = OptionValue["FieldSeparators"]}, + Module[{data, grid, sep = OptionValue["FieldSeparators"]}, data = StringSplit[#, sep]& /@ ReadList[stream, String]; grid = Grid[data]; { diff --git a/mathics/builtin/arithfns/basic.py b/mathics/builtin/arithfns/basic.py index 1409c32c5..439e2d447 100644 --- a/mathics/builtin/arithfns/basic.py +++ b/mathics/builtin/arithfns/basic.py @@ -72,7 +72,7 @@ class CubeRoot(Builtin): https://reference.wolfram.com/language/ref/CubeRoot.html)
-
'CubeRoot[$n$]' +
'CubeRoot'[$n$]
finds the real-valued cube root of the given $n$.
@@ -116,8 +116,8 @@ class Divide(InfixOperator): https://reference.wolfram.com/language/ref/Divide.html)
-
'Divide[$a$, $b$]' -
'$a$ / $b$' +
'Divide'[$a$, $b$] +
$a$ '/' $b$
represents the division of $a$ by $b$.
@@ -178,7 +178,7 @@ class Minus(PrefixOperator): https://reference.wolfram.com/language/ref/Minus.html)
-
'Minus[$expr$]' +
'Minus'[$expr$]
is the negation of $expr$.
@@ -227,7 +227,7 @@ class Plus(InfixOperator, SympyFunction): https://reference.wolfram.com/language/ref/Plus.html)
-
'Plus[$a$, $b$, ...]' +
'Plus'[$a$, $b$, ...]
$a$ + $b$ + ...
represents the sum of the terms $a$, $b$, ...
@@ -351,8 +351,8 @@ class Power(InfixOperator, MPMathFunction): https://reference.wolfram.com/language/ref/Power.html)
-
'Power[$a$, $b$]' -
'$a$ ^ $b$' +
'Power'[$a$, $b$] +
$a$ '^' $b$
represents $a$ raised to the power of $b$.
@@ -483,7 +483,7 @@ class Sqrt(SympyFunction): https://reference.wolfram.com/language/ref/Sqrt.html)
-
'Sqrt[$expr$]' +
'Sqrt'[$expr$]
returns the square root of $expr$.
@@ -526,8 +526,8 @@ class Subtract(InfixOperator): https://reference.wolfram.com/language/ref/Subtract.html)
-
'Subtract[$a$, $b$]' -
$a$ - $b$ +
'Subtract'[$a$, $b$] +
$a$ '-' $b$
represents the subtraction of $b$ from $a$.
@@ -561,9 +561,9 @@ class Times(InfixOperator, SympyFunction): :WMA:https://reference.wolfram.com/language/ref/Times.html)
-
'Times[$a$, $b$, ...]' -
'$a$ * $b$ * ...' -
'$a$ $b$ ...' +
'Times'[$a$, $b$, ...] +
$a$ '*' $b$ '*' ... +
$a$ $b$ ...
represents the product of the terms $a$, $b$, ...
diff --git a/mathics/builtin/arithfns/sums.py b/mathics/builtin/arithfns/sums.py index 50f571a06..24a4c54df 100644 --- a/mathics/builtin/arithfns/sums.py +++ b/mathics/builtin/arithfns/sums.py @@ -15,7 +15,7 @@ class Accumulate(Builtin): https://reference.wolfram.com/language/ref/Accumulate.html
-
'Accumulate[$list$]' +
'Accumulate'[$list$]
accumulates the values of $list$, returning a new list.
@@ -32,16 +32,16 @@ class Total(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Total.html
-
'Total[$list$]' +
'Total'[$list$]
adds all values in $list$. -
'Total[$list$, $n$]' +
'Total'[$list$, $n$]
adds all values up to level $n$. -
'Total[$list$, {$n$}]' +
'Total'[$list$, {$n$}]
totals only the values at level {$n$}. -
'Total[$list$, {$n_1$, $n_2$}]' +
'Total'[$list$, {$n_1$, $n_2$}]
totals at levels {$n_1$, $n_2$}.
diff --git a/mathics/builtin/arithmetic.py b/mathics/builtin/arithmetic.py index c82c92fa4..259bdebb3 100644 --- a/mathics/builtin/arithmetic.py +++ b/mathics/builtin/arithmetic.py @@ -36,6 +36,7 @@ IterationFunction, MPMathFunction, Predefined, + PrefixOperator, SympyFunction, SympyObject, Test, @@ -106,7 +107,7 @@ class Arg(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/Arg.html)
-
'Arg'[$z$, $method_option$] +
'Arg'[$z$, 'Method ->' "$option$"]
returns the argument of a complex value $z$.
@@ -177,7 +178,7 @@ class Assuming(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Assuming.html
-
'Assuming[$cond$, $expr$]' +
'Assuming'[$cond$, $expr$]
Evaluates $expr$ assuming the conditions $cond$.
@@ -212,11 +213,11 @@ def eval_assuming(self, assumptions, expr, evaluation: Evaluation): class Assumptions(Predefined): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/$Assumptions.html
-
'$Assumptions' -
is the default setting for the Assumptions option used in such functions as Simplify, Refine, and Integrate. +
'\$Assumptions' +
is the default setting for the 'Assumptions' option used in such functions as 'Simplify', 'Refine', and 'Integrate'.
""" @@ -270,7 +271,7 @@ class Complex_(Builtin):
'Complex'
is the head of complex numbers. -
'Complex[$a$, $b$]' +
'Complex'[$a$, $b$]
constructs the complex number '$a$ + I $b$'. @@ -301,7 +302,7 @@ class ConditionalExpression(Builtin): language/ref/ConditionalExpression.html
-
'ConditionalExpression[$expr$, $cond$]' +
'ConditionalExpression'[$expr$, $cond$]
returns $expr$ if $cond$ evaluates to $True$, $Undefined$ if $cond$ \ evaluates to $False$.
@@ -388,7 +389,7 @@ class Conjugate(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/Conjugate.html
-
'Conjugate[$z$]' +
'Conjugate'[$z$]
returns the complex conjugate of the complex number $z$.
@@ -412,7 +413,7 @@ class Conjugate(MPMathFunction): rules = { "Conjugate[Undefined]": "Undefined", } - summary_text = "complex conjugation" + summary_text = "compute complex conjugation" class DirectedInfinity(SympyFunction): @@ -421,7 +422,7 @@ class DirectedInfinity(SympyFunction): https://reference.wolfram.com/language/ref/DirectedInfinity.html
-
'DirectedInfinity[$z$]' +
'DirectedInfinity'[$z$]
represents an infinite multiple of the complex number $z$.
'DirectedInfinity[]'
is the same as 'ComplexInfinity'. @@ -543,9 +544,9 @@ class Element(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Element.html
-
'Element[$expr$, $domain$]' +
'Element'[$expr$, $domain$]
returns $True$ if $expr$ is an element of $domain$ -
'Element[$expr_1$|$expr_2$|..., $domain$]' +
'Element'[$expr_1$|$expr_2$|..., $domain$]
returns $True$ if all the $expr_i$ belongs to $domain$, and \ $False$ if one of the items doesn't.
@@ -630,14 +631,23 @@ class I_(Predefined, SympyObject): summary_text = "imaginary unit number Sqrt[-1]" python_equivalent = 1j + def evaluate(self, evaluation: Evaluation): + return Complex(Integer0, Integer1) + def is_constant(self) -> bool: + """The value and evaluation of this object can never change.""" return True - def to_sympy(self, symb, **kwargs): - return self.sympy_obj + @property + def is_literal(self): + return True - def evaluate(self, evaluation: Evaluation): - return Complex(Integer0, Integer1) + @property + def value(self) -> complex: + return complex(0, 1) + + def to_sympy(self, expr, **kwargs): + return self.sympy_obj class Im(SympyFunction): @@ -647,7 +657,7 @@ class Im(SympyFunction): https://reference.wolfram.com/language/ref/Im.html
-
'Im[$z$]' +
'Im'[$z$]
returns the imaginary component of the complex number $z$.
@@ -694,52 +704,70 @@ class Integer_(Builtin): name = "Integer" -class Product(IterationFunction, SympyFunction): +class Product(IterationFunction, SympyFunction, PrefixOperator): """ - :WMA link:https://reference.wolfram.com/language/ref/Product.html + :Direct product:https://en.wikipedia.org/wiki/Direct_product ( + :SymPy:https://docs.sympy.org/latest/modules/concrete.html#sympy.concrete.products.Product, + :WMA:https://reference.wolfram.com/language/ref/Product.html)
-
'Product[$expr$, {$i$, $imin$, $imax$}]' -
evaluates the discrete product of $expr$ with $i$ ranging from $imin$ to $imax$. +
'Product'[$f$, {$i$, $i_{min}$, $i_{max}$}] +
evaluates the discrete product of $f$ with $i$ ranging from $i_{min}$ to $i_{max}$. -
'Product[$expr$, {$i$, $imax$}]' -
same as 'Product[$expr$, {$i$, 1, $imax$}]'. +
'Product'[$f$, {$i$, $i_{max}$}] +
same as 'Product'[$f$, {$i, 1, i_{max}$}]. -
'Product[$expr$, {$i$, $imin$, $imax$, $di$}]' -
$i$ ranges from $imin$ to $imax$ in steps of $di$. +
'Product'[$f$, {$i, i_{min}, i_{max}$, $di$}] +
$i$ ranges from $i_{min}$ to $i_{max}$ in steps of $di$. -
'Product[$expr$, {$i$, $imin$, $imax$}, {$j$, $jmin$, $jmax$}, ...]' -
evaluates $expr$ as a multiple product, with {$i$, ...}, {$j$, ...}, ... being in outermost-to-innermost order. +
'Product'[$f$, {$i, i_{min}, i_{max}$}, {$j, j_{min}, j_{max}$}, ...] +
evaluates $f$ as a multiple product, with {$i$, ...}, {$j$, ...}, ... being in \ + outermost-to-innermost order.
- >> Product[k, {k, 1, 10}] - = 3628800 - >> 10! - = 3628800 + 'Product[k, {k, i, n}]' is defined in terms of + :Factorial: + /doc/reference-of-built-in-symbols/special-functions/gamma-and-related-functions/factorial/: + + >> Product[k, {k, i, n}] + = n! / (-1 + i)! + + When $i$ is 1, we get the factorial function: + >> Product[k, {k, 1, n}] + = n! + + Or more succinctly: + >> Product[k, {k, n}] + = n! + + Symbolic products involving the factorial are evaluated: + >> Product[k, {k, 3, n}] + = n! / 2 + + Examples of numeric evaluation using more complex functions: >> Product[x^k, {k, 2, 20, 2}] = x ^ 110 + >> Product[2 ^ i, {i, 1, n}] = 2 ^ (n / 2 + n ^ 2 / 2) + >> Product[f[i], {i, 1, 7}] = f[1] f[2] f[3] f[4] f[5] f[6] f[7] - Symbolic products involving the factorial are evaluated: - >> Product[k, {k, 3, n}] - = n! / 2 - - Evaluate the $n$th primorial: - >> primorial[0] = 1; - >> primorial[n_Integer] := Product[Prime[k], {k, 1, n}]; - >> primorial[12] + Evaluate the $n$-th :Primorial:https://en.wikipedia.org/wiki/Primorial: + >> Primorial[0] = 1; + >> Primorial[n_Integer] := Product[Prime[k], {k, 1, n}]; + >> Primorial[12] = 7420738134810 """ - summary_text = "discrete product" - throw_iterb = False - - sympy_name = "Product" - + # FIXME Product[k, {k, 3, n}] is rewritten using Factorial via + # Pochhammer rewrite rules. We want this for Product, but WMA + # does not rewrite using Factorial for Pochhammer alone, although it could. + # Nevertheless, if and when our Pochhammer is adjusted to remove + # this transformation to Factorial to match WMA behavior, + # we will need to add a rule that transforms to Factorial here. rules = IterationFunction.rules.copy() rules.update( { @@ -751,9 +779,12 @@ class Product(IterationFunction, SympyFunction): ), } ) + summary_text = "compute the direct product" + sympy_name = "Product" + throw_iterb = False - def get_result(self, items): - return Expression(SymbolTimes, *items) + def get_result(self, elements): + return Expression(SymbolTimes, *elements) def to_sympy(self, expr, **kwargs): if expr.has_form("Product", 2) and expr.elements[1].has_form("List", 3): @@ -778,7 +809,7 @@ class Rational_(Builtin):
'Rational'
is the head of rational numbers. -
'Rational[$a$, $b$]' +
'Rational'[$a$, $b$]
constructs the rational number $a$ / $b$.
@@ -806,7 +837,7 @@ class Re(SympyFunction): :WMA link:https://reference.wolfram.com/language/ref/Re.html
-
'Re[$z$]' +
'Re'[$z$]
returns the real component of the complex number $z$.
@@ -862,7 +893,7 @@ class RealValuedNumberQ(Test): :WMA link:https://reference.wolfram.com/language/ref/RealValuedNumberQ.html
-
'RealValuedNumberQ[$expr$]' +
'RealValuedNumberQ'[$expr$]
returns 'True' if $expr$ is an explicit number with no imaginary component.
@@ -894,22 +925,24 @@ def test(self, expr) -> bool: ) -class Sum(IterationFunction, SympyFunction): - """ - :WMA link:https://reference.wolfram.com/language/ref/Sum.html +class Sum(IterationFunction, SympyFunction, PrefixOperator): + r""" + :Summation:https://en.wikipedia.org/wiki/Summation ( + :SymPy:https://docs.sympy.org/latest/modules/concrete.html#sympy.concrete.summations.Sum, + :WMA:https://reference.wolfram.com/language/ref/Sum.html)
-
'Sum[$expr$, {$i$, $imin$, $imax$}]' -
evaluates the discrete sum of $expr$ with $i$ ranging from $imin$ to $imax$. +
'Sum['$f, \{i, i_{min}, i_{max}\}$']' +
evaluates the discrete sum of $f$ with $i$ ranging from $i_{min}$ to $i_{max}$. -
'Sum[$expr$, {$i$, $imax$}]' -
same as 'Sum[$expr$, {$i$, 1, $imax$}]'. +
'Sum['$f, \{i, i_{max}\}$']' +
same as 'Sum['$f, \{i, 1, i_{max}\}$']'. -
'Sum[$expr$, {$i$, $imin$, $imax$, $di$}]' -
$i$ ranges from $imin$ to $imax$ in steps of $di$. +
'Sum['$f, \{i, i_{min}, i_{max}, di\}$']' +
$i$ ranges from $i_{min}$ to $i_{max}$ in steps of $di$. -
'Sum[$expr$, {$i$, $imin$, $imax$}, {$j$, $jmin$, $jmax$}, ...]' -
evaluates $expr$ as a multiple sum, with {$i$, ...}, {$j$, ...}, ... being \ +
'Sum['$f, \{i, i_{min}, i_{max}, \{j, j_{min}, j_{max}, ...$']' +
evaluates $f$ as a multiple sum, with {$i, ...$}, {$j, ...$}, ... being \ in outermost-to-innermost order.
@@ -969,12 +1002,6 @@ class Sum(IterationFunction, SympyFunction): = 1 + 2 I """ - summary_text = "discrete sum" - # Do not throw warning message for symbolic iteration bounds - throw_iterb = False - - sympy_name = "Sum" - rules = IterationFunction.rules.copy() rules.update( { @@ -987,6 +1014,12 @@ class Sum(IterationFunction, SympyFunction): } ) + summary_text = "compute a summation" + sympy_name = "Sum" + + # Do not throw warning message for symbolic iteration bounds + throw_iterb = False + def get_result(self, elements) -> Expression: return Expression(SymbolPlus, *elements) diff --git a/mathics/builtin/assignments/assign_binaryop.py b/mathics/builtin/assignments/assign_binaryop.py index 1256d1e38..e1bed1e9c 100644 --- a/mathics/builtin/assignments/assign_binaryop.py +++ b/mathics/builtin/assignments/assign_binaryop.py @@ -47,9 +47,9 @@ class AddTo(InfixOperator, InplaceInfixOperator): :WMA link:https://reference.wolfram.com/language/ref/AddTo.html
-
'AddTo[$x$, $dx$]' -
'$x$ += $dx$' -
is equivalent to '$x$ = $x$ + $dx$'. +
'AddTo'[$x$, $dx$] +
$x$ '+=' $dx$ +
is equivalent to $x$ '=' $x$ '+' $dx$.
>> a = 10; @@ -86,9 +86,9 @@ class Decrement(InplaceInfixOperator, InfixOperator, PostfixOperator): :https://reference.wolfram.com/language/ref/Decrement.html
-
'Decrement[$x$]' +
'Decrement'[$x$] -
'$x$--' +
$x$'--'
decrements $x$ by 1, returning the original value of $x$.
@@ -132,9 +132,9 @@ class DivideBy(InplaceInfixOperator, InfixOperator): :WMA link:https://reference.wolfram.com/language/ref/DivideBy.html
-
'DivideBy[$x$, $dx$]' -
'$x$ /= $dx$' -
is equivalent to '$x$ = $x$ / $dx$'. +
'DivideBy'[$x$, $dx$] +
$x$ '/=' $dx$ +
is equivalent to $x$ = $x$ '/' $dx$.
>> a = 10; @@ -159,9 +159,9 @@ class Increment(InplaceInfixOperator, InfixOperator, PostfixOperator): https://reference.wolfram.com/language/ref/Increment.html
-
'Increment[$x$]' +
'Increment'[$x$] -
'$x$++' +
$x$'++'
increments $x$ by 1, returning the original value of $x$.
@@ -215,13 +215,13 @@ class PreDecrement(InplaceInfixOperator, PrefixOperator): https://reference.wolfram.com/language/ref/PreDecrement.html
-
'PreDecrement[$x$]' +
'PreDecrement'[$x$] -
'--$x$' +
'--'$x$
decrements $x$ by 1, returning the new value of $x$.
- '--$a$' is equivalent to '$a$ = $a$ - 1': + '--'$a$ is equivalent to $a$ '=' $a$ '- 1': >> a = 2; >> --a = 1 @@ -250,12 +250,12 @@ class PreIncrement(InplaceInfixOperator, PrefixOperator): https://reference.wolfram.com/language/ref/PreIncrement.html
-
'PreIncrement[$x$]' -
'++$x$' +
'PreIncrement'[$x$] +
'++'$x$
increments $x$ by 1, returning the new value of $x$.
- '++$a$' is equivalent to '$a$ = $a$ + 1': + '++'$a$ is equivalent to $a$ '=' $a$ '+ 1': >> a = 2 = 2 @@ -303,9 +303,9 @@ class SubtractFrom(InfixOperator): https://reference.wolfram.com/language/ref/SubtractFrom.html
-
'SubtractFrom[$x$, $dx$]' -
'$x$ -= $dx$' -
is equivalent to '$x$ = $x$ - $dx$'. +
'SubtractFrom'[$x$, $dx$] +
$x$ '-=' $dx$ +
is equivalent to $x$ '=' $x$ '-' $dx$.
>> a = 10; @@ -331,9 +331,9 @@ class TimesBy(InfixOperator): :WMA link:https://reference.wolfram.com/language/ref/TimesBy.html
-
'TimesBy[$x$, $dx$]' -
'$x$ *= $dx$' -
is equivalent to '$x$ = $x$ * $dx$'. +
'TimesBy'[$x$, $dx$] +
$x$ '*=' $dx$ +
is equivalent to $x$ '=' $x$ '*' $dx$.
>> a = 10; diff --git a/mathics/builtin/assignments/assignment.py b/mathics/builtin/assignments/assignment.py index 3c77a4fcd..4b46b4346 100644 --- a/mathics/builtin/assignments/assignment.py +++ b/mathics/builtin/assignments/assignment.py @@ -28,7 +28,7 @@ class LoadModule(Builtin): ## :mathics native for pymathics:
-
'LoadModule[$module$]' +
'LoadModule'[$module$]
'Load Mathics definitions from the python module $module$
@@ -65,14 +65,14 @@ class Set(InfixOperator): :WMA link:https://reference.wolfram.com/language/ref/Set.html
-
'Set[$expr$, $value$]' +
'Set'[$expr$, $value$]
$expr$ = $value$
evaluates $value$ and assigns it to $expr$. -
{$s1$, $s2$, $s3$} = {$v1$, $v2$, $v3$} -
sets multiple symbols ($s1$, $s2$, ...) to the corresponding \ - values ($v1$, $v2$, ...). +
{$s_1$, $s_2$, $s_3$} = {$v_1$, $v_2$, $v_3$} +
sets multiple symbols ($s_1$, $s_2$, ...) to the corresponding \ + values ($v_1$, $v_2$, ...).
'Set' can be used to give a symbol a value: @@ -150,7 +150,7 @@ class SetDelayed(Set): https://reference.wolfram.com/language/ref/SetDelayed.html
-
'SetDelayed[$expr$, $value$]' +
'SetDelayed'[$expr$, $value$]
$expr$ := $value$
assigns $value$ to $expr$, without evaluating $value$. @@ -233,9 +233,9 @@ class TagSet(Builtin): :WMA link:https://reference.wolfram.com/language/ref/TagSet.html
-
'TagSet[$f$, $expr$, $value$]' +
'TagSet'[$f$, $expr$, $value$] -
'$f$ /: $expr$ = $value$' +
$f$ '/:' $expr$ '=' $value$
assigns $value$ to $expr$, associating the corresponding assignment \ with the symbol $f$.
@@ -292,7 +292,7 @@ class TagSetDelayed(TagSet): https://reference.wolfram.com/language/ref/TagSetDelayed.html
-
'TagSetDelayed[$f$, $expr$, $value$]' +
'TagSetDelayed'[$f$, $expr$, $value$]
'$f$ /: $expr$ := $value$'
is the delayed version of 'TagSet'. @@ -331,7 +331,7 @@ class UpSet(InfixOperator): https://reference.wolfram.com/language/ref/UpSet.html
-
$f$[$x$] ^= $expression$ +
$f$[$x$] '^=' $expression$
evaluates $expression$ and assigns it to the value of $f$[$x$], \ associating the value with $x$.
@@ -374,9 +374,9 @@ class UpSetDelayed(UpSet): https://reference.wolfram.com/language/ref/UpSetDelayed.html
-
'UpSetDelayed[$expression$, $value$]' +
'UpSetDelayed'[$expression$, $value$] -
'$expression$ ^:= $value$' +
$expression$ '^:=' $value$
assigns $expression$ to the value of $f$[$x$] \ (without evaluating $expression$), associating the value with $x$.
diff --git a/mathics/builtin/assignments/clear.py b/mathics/builtin/assignments/clear.py index d645a6d12..4d10a85b3 100644 --- a/mathics/builtin/assignments/clear.py +++ b/mathics/builtin/assignments/clear.py @@ -39,7 +39,7 @@ class Clear(Builtin): https://reference.wolfram.com/language/ref/Clear.html
-
'Clear[$symb1$, $symb2$, ...]' +
'Clear'[$symb_1$, $symb_2$, ...]
clears all values of the given symbols. The arguments can also be given as strings containing symbol names.
@@ -138,7 +138,7 @@ class ClearAll(Clear): https://reference.wolfram.com/language/ref/ClearAll.html
-
'ClearAll[$symb1$, $symb2$, ...]' +
'ClearAll'[$symb_1$, $symb_2$, ...]
clears all values, attributes, messages and options associated with the given symbols. The arguments can also be given as strings containing symbol names.
@@ -176,7 +176,7 @@ class Remove(Builtin): https://reference.wolfram.com/language/ref/Remove.html
-
'Remove[$x$]' +
'Remove'[$x$]
removes the definition associated to $x$.
@@ -210,7 +210,7 @@ class Unset(PostfixOperator): https://reference.wolfram.com/language/ref/Unset.html
-
'Unset[$x$]' +
'Unset'[$x$]
'$x$=.'
removes any value belonging to $x$.
diff --git a/mathics/builtin/assignments/types.py b/mathics/builtin/assignments/types.py index 351cea8db..1f2b7f105 100644 --- a/mathics/builtin/assignments/types.py +++ b/mathics/builtin/assignments/types.py @@ -22,7 +22,7 @@ class DefaultValues(Builtin): https://reference.wolfram.com/language/ref/DefaultValues.html
-
'DefaultValues[$symbol$]' +
'DefaultValues'[$symbol$]
gives the list of default values associated with $symbol$. Note: this function is in Mathematica 5 but has been removed from \ @@ -64,7 +64,7 @@ class Messages(Builtin): https://reference.wolfram.com/language/ref/Messages.html
-
'Messages[$symbol$]' +
'Messages'[$symbol$]
gives the list of messages associated with $symbol$.
@@ -94,7 +94,7 @@ class NValues(Builtin): ## :WMA link:https://reference.wolfram.com/language/ref/NValues.html
-
'NValues[$symbol$]' +
'NValues'[$symbol$]
gives the list of numerical values associated with $symbol$. Note: this function is in Mathematica 5 but has been removed from \ @@ -144,7 +144,7 @@ class SubValues(Builtin): https://reference.wolfram.com/language/ref/SubValues.html
-
'SubValues[$symbol$]' +
'SubValues'[$symbol$]
gives the list of subvalues associated with $symbol$. Note: this function is not in current Mathematica. diff --git a/mathics/builtin/assignments/upvalues.py b/mathics/builtin/assignments/upvalues.py index 0e09f527b..df899d79a 100644 --- a/mathics/builtin/assignments/upvalues.py +++ b/mathics/builtin/assignments/upvalues.py @@ -19,7 +19,7 @@ class UpValues(Builtin): """ :WMA link: https://reference.wolfram.com/language/ref/UpValues.html
-
'UpValues[$symbol$]' +
'UpValues'[$symbol$]
gives the list of transformation rules corresponding to upvalues \ define with $symbol$.
diff --git a/mathics/builtin/atomic/atomic.py b/mathics/builtin/atomic/atomic.py index 9c57460ce..331109ff6 100644 --- a/mathics/builtin/atomic/atomic.py +++ b/mathics/builtin/atomic/atomic.py @@ -12,7 +12,7 @@ class AtomQ(Test): :WMA link:https://reference.wolfram.com/language/ref/AtomQ.html
-
'AtomQ[$expr$]' +
'AtomQ'[$expr$]
returns 'True' if $expr$ is an expression which cannot be divided into \ subexpressions, or 'False' otherwise. @@ -65,7 +65,7 @@ class Head(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Head.html
-
'Head[$expr$]' +
'Head'[$expr$]
returns the head of the expression or atom $expr$.
diff --git a/mathics/builtin/atomic/numbers.py b/mathics/builtin/atomic/numbers.py index 4459ce3ad..67c5b9ac8 100644 --- a/mathics/builtin/atomic/numbers.py +++ b/mathics/builtin/atomic/numbers.py @@ -73,7 +73,7 @@ class Accuracy(Builtin): https://reference.wolfram.com/language/ref/Accuracy.html)
-
'Accuracy[$x$]' +
'Accuracy'[$x$]
examines the number of significant digits of $expr$ after the \ decimal point in the number x.
@@ -89,7 +89,7 @@ class Accuracy(Builtin): Notice that the value is not exactly equal to the obtained in WMA: \ This is due to the different way in which 'Precision' is handled in SymPy. - Accuracy for exact atoms is $Infinity$: + Accuracy for exact atoms is 'Infinity': >> Accuracy[1] = Infinity >> Accuracy[A] @@ -145,7 +145,7 @@ class IntegerExponent(Builtin): https://reference.wolfram.com/language/ref/IntegerExponent.html
-
'IntegerExponent[$n$, $b$]' +
'IntegerExponent'[$n$, $b$]
gives the highest exponent of $b$ that divides $n$.
@@ -170,7 +170,7 @@ class IntegerExponent(Builtin): "IntegerExponent[n_]": "IntegerExponent[n, 10]", } - summary_text = "number of trailing 0s in a given base" + summary_text = "get the number of trailing 0s in a given base" def eval_two_arg_integers(self, n: Integer, b: Integer, evaluation: Evaluation): """IntegerExponent[n_Integer, b_Integer]""" @@ -218,10 +218,10 @@ class IntegerLength(Builtin): https://reference.wolfram.com/language/ref/IntegerLength.html
-
'IntegerLength[$x$]' +
'IntegerLength'[$x$]
gives the number of digits in the base-10 representation of $x$. -
'IntegerLength[$x$, $b$]' +
'IntegerLength'[$x$, $b$]
gives the number of base-$b$ digits in $x$.
@@ -257,7 +257,7 @@ class IntegerLength(Builtin): "IntegerLength[n_]": "IntegerLength[n, 10]", } - summary_text = "total number of digits in any base" + summary_text = "get total number of digits in any base" def eval(self, n, b, evaluation): """IntegerLength[n_, b_]""" @@ -301,10 +301,10 @@ class NumberDigit(Builtin): https://reference.wolfram.com/language/ref/NumberDigit.html
-
'NumberDigit[$x$, $n$]' +
'NumberDigit'[$x$, $n$]
returns the digit coefficient of 10^$n$ for the real-valued number $x$. -
'NumberDigit[$x$, $n$, $b$]' +
'NumberDigit'[$x$, $n$, $b$]
returns the coefficient of $b$^$n$ in the base-$b$ representation of $x$.
@@ -339,19 +339,19 @@ class RealDigits(Builtin): https://reference.wolfram.com/language/ref/RealDigits.html
-
'RealDigits[$n$]' -
returns the decimal representation of the real number $n$ as list \ +
'RealDigits'[$n$] +
returns the decimal representation for the real number $n$ as list \ of digits, together with the number of digits that are to the left of \ the decimal point. -
'RealDigits[$n$, $b$]' -
returns a list of base_$b$ representation of the real number $n$. +
'RealDigits'[$n$, $b$] +
returns a list of the "digits" in base-b representation for the real number $n$. -
'RealDigits[$n$, $b$, $len$]' +
'RealDigits'[$n$, $b$, $len$]
returns a list of $len$ digits. -
'RealDigits[$n$, $b$, $len$, $p$]' -
return $len$ digits starting with the coefficient of $b$^$p$ +
'RealDigits'[$n$, $b$, $len$, $p$] +
return $len$ digits starting with the coefficient of $b^p$.
Return the list of digits and exponent: @@ -391,7 +391,7 @@ class RealDigits(Builtin): "intm": "Machine-sized integer expected at position 4 in `1`.", } - summary_text = "digits of a real number" + summary_text = "get digits of a real number" def eval_complex(self, n, var, evaluation): "%(name)s[n_Complex, var___]" @@ -406,14 +406,12 @@ def eval_rational_with_base(self, n, b, evaluation): return self.eval_with_base(n, b, evaluation) else: exp = log_n_b(py_n, py_b) - (head, tails) = convert_repeating_decimal( + head, tails = convert_repeating_decimal( py_n.as_numer_denom()[0], py_n.as_numer_denom()[1], py_b ) - elements = [] - for x in head: - if x != "0": - elements.append(Integer(int(x))) + elements = [Integer(int(x)) for x in head if x != "0"] + elements.append(from_python(tails)) list_expr = ListExpression(*elements) return ListExpression(list_expr, Integer(exp)) @@ -446,7 +444,7 @@ def eval_with_base(self, n, b, evaluation, nr_elements=None, pos=None): if isinstance(n, (Expression, Symbol, Rational)): pos_len = abs(pos) + 1 if pos is not None and pos < 0 else 1 if nr_elements is not None: - # we can't use eval_n here because we have the two-arguemnt form + # we can't use eval_n here because we have the two-argument form n = Expression( SymbolN, n, @@ -580,11 +578,11 @@ def eval_with_base_length_and_precision(self, n, b, length, p, evaluation): class MaxPrecision(Predefined): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/$MaxPrecision.html
-
'$MaxPrecision' +
'\$MaxPrecision'
represents the maximum number of digits of precision permitted \ in abitrary-precision numbers.
@@ -611,16 +609,16 @@ class MaxPrecision(Predefined): "$MaxPrecision": "Infinity", } - summary_text = "settable global maximum precision bound" + summary_text = "settable global maximum precision bound variable" class MachineEpsilon_(Predefined): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/$MachineEpsilon.html
-
'$MachineEpsilon' +
'\$MachineEpsilon'
is the distance between '1.0' and the next \ nearest representable machine-precision number.
@@ -636,18 +634,18 @@ class MachineEpsilon_(Predefined): _is_numeric = True name = "$MachineEpsilon" - summary_text = "the difference between 1.0 and the next-nearest number representable as a machine-precision number" + summary_text = "get the difference between 1.0 and the next-nearest number representable as a machine-precision number" def evaluate(self, evaluation): return MachineReal(MACHINE_EPSILON) class MachinePrecision_(Predefined): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/$MachinePrecision.html
-
'$MachinePrecision' +
'\$MachinePrecision'
is the number of decimal digits of precision for machine-precision numbers.
@@ -658,7 +656,7 @@ class MachinePrecision_(Predefined): name = "$MachinePrecision" summary_text = ( - "the number of decimal digits of precision for machine-precision numbers" + "get the number of decimal digits of precision for machine-precision numbers" ) _is_numeric = True rules = { @@ -691,12 +689,12 @@ class MachinePrecision(Predefined): class MinPrecision(Builtin): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/$MinPrecision.html
-
'$MinPrecision' +
'\$MinPrecision'
represents the minimum number of digits of precision permitted in \ abitrary-precision numbers.
@@ -734,7 +732,7 @@ class Precision(Builtin): https://reference.wolfram.com/language/ref/Precision.html
-
'Precision[$expr$]' +
'Precision'[$expr$]
examines the number of significant digits of $expr$.
diff --git a/mathics/builtin/atomic/strings.py b/mathics/builtin/atomic/strings.py index a8016b14a..3ed064fc4 100644 --- a/mathics/builtin/atomic/strings.py +++ b/mathics/builtin/atomic/strings.py @@ -11,7 +11,7 @@ from heapq import heappop, heappush from typing import Any, List -from mathics_scanner import TranslateError +from mathics_scanner.errors import SyntaxError from mathics.core.atoms import Integer, Integer0, Integer1, String from mathics.core.attributes import A_LISTABLE, A_PROTECTED @@ -20,7 +20,9 @@ from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.list import ListExpression -from mathics.core.parser import MathicsFileLineFeeder, parse +from mathics.core.parser import MathicsFileLineFeeder +from mathics.core.parser.convert import convert +from mathics.core.parser.util import parser from mathics.core.systemsymbols import ( SymbolFailed, SymbolInputForm, @@ -224,7 +226,7 @@ class Alphabet(Builtin):
'Alphabet'[]
gives the list of lowercase letters a-z in the English alphabet . -
'Alphabet[$type$]' +
'Alphabet'[$type$]
gives the alphabet for the language or class $type$.
@@ -269,10 +271,10 @@ class CharacterEncoding(Predefined): https://reference.wolfram.com/language/ref/$CharacterEncoding.html
-
'$CharacterEncoding' +
'\\$CharacterEncoding'
specifies the default raw character encoding to use for input and \ output when no encoding is explicitly specified. \ - Initially this is set to '$SystemCharacterEncoding'. + Initially this is set to '\\$SystemCharacterEncoding'.
See the character encoding current is in effect and used in input and \ @@ -281,7 +283,7 @@ class CharacterEncoding(Predefined): >> $CharacterEncoding = ... - By setting its value to one of the values in '$CharacterEncodings', \ + By setting its value to one of the values in '\\$CharacterEncodings', \ operators are formatted differently. For example, >> $CharacterEncoding = "ASCII"; a -> b @@ -290,13 +292,13 @@ class CharacterEncoding(Predefined): = ... Setting its value to 'None' restore the value to \ - '$SystemCharacterEncoding': + '\\$SystemCharacterEncoding': >> $CharacterEncoding = None; >> $SystemCharacterEncoding == $CharacterEncoding = True See also - :$SystemCharacterEncoding: + :\\$SystemCharacterEncoding: /doc/reference-of-built-in-symbols/atomic-elements-of-expressions/string-manipulation/$systemcharacterencoding/. """ @@ -329,7 +331,7 @@ class CharacterEncodings(Predefined): https://reference.wolfram.com/language/ref/$CharacterEncodings.html
-
'$CharacterEncodings' +
'\\$CharacterEncodings'
stores the list of available character encodings.
@@ -365,7 +367,7 @@ class HexadecimalCharacter(Builtin): # This isn't your normal Box class. We'll keep this here rather than # in mathics.builtin.box for now. -# mmatera commenct: This does not even exist in WMA. \! should be associated +# mmatera comment: This does not even exist in WMA. \! should be associated # to `ToExpression`, but it was not properly implemented by now... class InterpretedBox(PrefixOperator): r""" @@ -374,7 +376,7 @@ class InterpretedBox(PrefixOperator): https://reference.wolfram.com/language/ref/InterpretationBox.html
-
'InterpretedBox[$box$]' +
'InterpretedBox'[$box$]
is the ad hoc fullform for \! $box$. just for internal use...
@@ -405,7 +407,7 @@ class LetterNumber(Builtin):
'LetterNumber["string"]'
returns a list of the positions of characters in string. -
'LetterNumber["string", $alpha$]' +
'LetterNumber'["string", $alpha$]
returns a list of the positions of characters in string, regarding the alphabet $alpha$.
@@ -430,6 +432,7 @@ class LetterNumber(Builtin): = 2 """ + # FIXME: put the right unicode characters in a way that the # following test works... r""" @@ -539,7 +542,7 @@ class RemoveDiacritics(Builtin): :WMA link: https://reference.wolfram.com/language/ref/RemoveDiacritics.html
-
'RemoveDiacritics[$s$]' +
'RemoveDiacritics'[$s$]
returns a version of $s$ with all diacritics removed.
@@ -609,7 +612,7 @@ class StringContainsQ(Builtin): :WMA link: https://reference.wolfram.com/language/ref/StringContainsQ.html
-
'StringContainsQ["$string$", $patt$]' +
'StringContainsQ'["$string$", $patt$]
returns True if any part of $string$ matches $patt$, and returns False otherwise.
'StringContainsQ[{"s1", "s2", ...}, patt]' @@ -656,10 +659,10 @@ class StringRepeat(Builtin): :WMA link: https://reference.wolfram.com/language/ref/StringRepeat.html
-
'StringRepeat["$string$", $n$]' +
'StringRepeat'["$string$", $n$]
gives $string$ repeated $n$ times. -
'StringRepeat["$string$", $n$, $max$]' +
'StringRepeat'["$string$", $n$, $max$]
gives $string$ repeated $n$ times, but not more than $max$ characters.
@@ -706,9 +709,9 @@ class SystemCharacterEncoding(Predefined): """ :WMA link: - https://reference.wolfram.com/language/ref/$SystemCharacterEncoding.html + https://reference.wolfram.com/language/ref/\\$SystemCharacterEncoding.html
-
$SystemCharacterEncoding +
\\$SystemCharacterEncoding
gives the default character encoding of the system. On startup, the value of environment variable 'MATHICS_CHARACTER_ENCODING' \ @@ -735,13 +738,13 @@ class ToExpression(Builtin): :WMA link: https://reference.wolfram.com/language/ref/ToExpression.html
-
'ToExpression[$input$]' +
'ToExpression'[$input$]
interprets a given string as Mathics input. -
'ToExpression[$input$, $form$]' +
'ToExpression'[$input$, $form$]
reads the given input in the specified $form$. -
'ToExpression[$input$, $form$, $h$]' +
'ToExpression'[$input$, $form$, $h$]
applies the head $h$ to the expression before evaluating it.
@@ -787,14 +790,14 @@ class ToExpression(Builtin): def eval(self, seq, evaluation: Evaluation): "ToExpression[seq__]" - # Organise Arguments + # From `seq`, extract `inp`, `form`, and `head`. py_seq = seq.get_sequence() if len(py_seq) == 1: - (inp, form, head) = (py_seq[0], SymbolInputForm, None) + inp, form, head = (py_seq[0], SymbolInputForm, None) elif len(py_seq) == 2: - (inp, form, head) = (py_seq[0], py_seq[1], None) + inp, form, head = (py_seq[0], py_seq[1], None) elif len(py_seq) == 3: - (inp, form, head) = (py_seq[0], py_seq[1], py_seq[2]) + inp, form, head = (py_seq[0], py_seq[1], py_seq[2]) else: assert len(py_seq) > 3 # 0 case handled by apply_empty evaluation.message( @@ -807,6 +810,7 @@ def eval(self, seq, evaluation: Evaluation): ) return + result = None # Apply the different forms if form is SymbolInputForm: if isinstance(inp, String): @@ -818,13 +822,14 @@ def eval(self, seq, evaluation: Evaluation): feeder = MathicsFileLineFeeder(f) while not feeder.empty(): try: - query = parse(evaluation.definitions, feeder) - except TranslateError: + ast = parser.parse(feeder) + except SyntaxError: return SymbolFailed finally: feeder.send_messages(evaluation) - if query is None: # blank line / comment + if ast is None: # blank line / comment continue + query = convert(ast, evaluation.definitions) result = query.evaluate(evaluation) else: @@ -834,8 +839,8 @@ def eval(self, seq, evaluation: Evaluation): return # Apply head if present - if head is not None: - result = Expression(head, result).evaluate(evaluation) + if head is not None and result is not None: + return Expression(head, result).evaluate(evaluation) return result @@ -853,10 +858,10 @@ class ToString(Builtin): :WMA link: https://reference.wolfram.com/language/ref/ToString.html
-
'ToString[$expr$]' +
'ToString'[$expr$]
returns a string representation of $expr$. -
'ToString[$expr$, $form$]' +
'ToString'[$expr$, $form$]
returns a string representation of $expr$ in the form $form$.
@@ -899,12 +904,12 @@ def eval_form(self, expr, form, evaluation: Evaluation, options: dict): class Transliterate(Builtin): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/Transliterate.html
-
'Transliterate[$s$]' +
'Transliterate'[$s$]
transliterates a text in some script into an ASCII string.
@@ -955,4 +960,5 @@ class Whitespace(Builtin): >> StringReplace[" this has leading and trailing whitespace \n ", (StartOfString ~~ Whitespace) | (Whitespace ~~ EndOfString) -> ""] <> " removed" // FullForm = "this has leading and trailing whitespace removed" """ + summary_text = "sequence of whitespace characters" diff --git a/mathics/builtin/atomic/symbols.py b/mathics/builtin/atomic/symbols.py index 7531c01e8..e6a7cda4c 100644 --- a/mathics/builtin/atomic/symbols.py +++ b/mathics/builtin/atomic/symbols.py @@ -177,7 +177,7 @@ class Context(Builtin): :WMA link: https://reference.wolfram.com/language/ref/Context.html
-
'Context[$symbol$]' +
'Context'[$symbol$]
yields the name of the context where $symbol$ is defined in.
'Context[]' @@ -218,7 +218,7 @@ class Definition(Builtin): :WMA link: https://reference.wolfram.com/language/ref/Definition.html
-
'Definition[$symbol$]' +
'Definition'[$symbol$]
prints as the definitions given for $symbol$. This is in a form that can e stored in a package.
@@ -348,7 +348,7 @@ class DownValues(Builtin): """ :WMA link: https://reference.wolfram.com/language/ref/DownValues.html
-
'DownValues[$symbol$]' +
'DownValues'[$symbol$]
gives the list of downvalues associated with $symbol$.
@@ -405,7 +405,7 @@ class FormatValues(Builtin): """ :WMA link:https://reference.wolfram.com/language/tutorial/PatternsAndTransformationRules.html#6025
-
'FormatValues[$symbol$]' +
'FormatValues'[$symbol$]
gives the list of formatvalues associated with $symbol$.
@@ -428,7 +428,7 @@ class Information(PrefixOperator): :WMA link: https://reference.wolfram.com/language/ref/Information.html
-
'Information[$symbol$]' +
'Information'[$symbol$]
Prints information about a $symbol$
@@ -492,7 +492,7 @@ class Names(Builtin): :WMA link: https://reference.wolfram.com/language/ref/Names.html
-
'Names["$pattern$"]' +
'Names'["$pattern$"]
returns the list of names matching $pattern$.
@@ -545,7 +545,7 @@ class OwnValues(Builtin): :WMA link: https://reference.wolfram.com/language/ref/OwnValues.html
-
'OwnValues[$symbol$]' +
'OwnValues'[$symbol$]
gives the list of ownvalue associated with $symbol$.
@@ -619,7 +619,7 @@ class SymbolName(Builtin): :WMA link: https://reference.wolfram.com/language/ref/SymbolName.html
-
'SymbolName[$s$]' +
'SymbolName'[$s$]
returns the name of the symbol $s$ (without any leading \ context name).
@@ -643,7 +643,7 @@ class SymbolQ(Test): :WMA link: https://reference.wolfram.com/language/ref/SymbolName.html
-
'SymbolQ[$x$]' +
'SymbolQ'[$x$]
is 'True' if $x$ is a symbol, or 'False' otherwise.
@@ -666,7 +666,7 @@ class ValueQ(Builtin): :WMA link: https://reference.wolfram.com/language/ref/ValueQ.html
-
'ValueQ[$expr$]' +
'ValueQ'[$expr$]
returns 'True' if and only if $expr$ is defined.
diff --git a/mathics/builtin/attributes.py b/mathics/builtin/attributes.py index be8a7cbfa..a4dc27382 100644 --- a/mathics/builtin/attributes.py +++ b/mathics/builtin/attributes.py @@ -2,7 +2,7 @@ """ Definition Attributes -While a definition like 'cube[$x_$] = $x$^3' gives a way to specify \ +While a definition like 'cube[x_] = x^3' gives a way to specify \ values of a function, attributes allow a way to \ specify general properties of functions and symbols. This is \ independent of the parameters they take and the values they produce. @@ -51,7 +51,7 @@ class Attributes(Builtin):
'Attributes'["$string$"]
returns the attributes of 'Symbol'["$string$"]. -
'Attributes'[$symbol$] = {$attr1$, $attr2$} +
'Attributes'[$symbol$] = {$attr_1$, $attr_2$}
sets the attributes of $symbol$, replacing any existing attributes.
@@ -443,7 +443,7 @@ class OneIdentity(Predefined):
'OneIdentity' -
is an attribute assigned to a symbol, say $f$, indicating that '$f$[$x$]', $f$[$f$[$x$]], etc. are all \ +
is an attribute assigned to a symbol, say $f$, indicating that $f[x]$, $f[f[x]]$, etc. are all \ equivalent to $x$ in pattern matching.
@@ -478,7 +478,7 @@ class Orderless(Predefined):
'Orderless'
is an attribute that can be assigned to a symbol $f$ to \ indicate that the elements $ei$ in expressions of the form \ - $f$[$e1$, $e2$, ...] should automatically be sorted into \ + $f$[$e_1$, $e_2$, ...] should automatically be sorted into \ canonical order. This property is accounted for in pattern \ matching.
@@ -510,10 +510,10 @@ class Protect(Builtin): https://reference.wolfram.com/language/ref/Protect.html
-
'Protect'[$s1$, $s2$, ...] +
'Protect'[$s_1$, $s_2$, ...]
sets the attribute 'Protected' for the symbols $si$. -
'Protect'[$str1$, $str2$, ...] +
'Protect'[$str_1$, $str_2$, ...]
protects all symbols whose names textually match $stri$.
@@ -743,7 +743,7 @@ class Unprotect(Builtin): https://reference.wolfram.com/language/ref/Unprotect.html
-
'Unprotect'[$s1$, $s2$, ...] +
'Unprotect'[$s_1$, $s_2$, ...]
removes the attribute 'Protected' for the symbols $si$.
'Unprotect'[$str$] diff --git a/mathics/builtin/binary/bytearray.py b/mathics/builtin/binary/bytearray.py index dbcd06283..d0c3b5975 100644 --- a/mathics/builtin/binary/bytearray.py +++ b/mathics/builtin/binary/bytearray.py @@ -16,10 +16,10 @@ class ByteArray(Builtin): https://reference.wolfram.com/language/ref/ByteArray.html
-
'ByteArray[{$b_1$, $b_2$, ...}]' +
'ByteArray'[{$b_1$, $b_2$, ...}]
Represents a sequence of Bytes $b_1$, $b_2$, ... -
'ByteArray["string"]' +
'ByteArray'["$string$"]
Constructs a byte array where bytes comes from decode a b64-encoded \ String
diff --git a/mathics/builtin/binary/io.py b/mathics/builtin/binary/io.py index 3d686017c..5479edc5d 100644 --- a/mathics/builtin/binary/io.py +++ b/mathics/builtin/binary/io.py @@ -6,25 +6,28 @@ import math import struct from itertools import chain +from typing import Optional, Tuple import mpmath import sympy from mathics.core.atoms import Complex, Integer, MachineReal, Real, String from mathics.core.builtin import Builtin -from mathics.core.convert.expression import to_expression, to_mathics_list +from mathics.core.convert.expression import to_expression from mathics.core.convert.mpmath import from_mpmath -from mathics.core.expression import Expression +from mathics.core.evaluation import Evaluation from mathics.core.expression_predefined import ( MATHICS3_I_INFINITY, MATHICS3_I_NEG_INFINITY, MATHICS3_INFINITY, MATHICS3_NEG_INFINITY, + Expression, ) -from mathics.core.streams import stream_manager +from mathics.core.list import ListExpression +from mathics.core.streams import Stream, stream_manager from mathics.core.symbols import Symbol from mathics.core.systemsymbols import SymbolIndeterminate -from mathics.eval.files_io.read import SymbolEndOfFile +from mathics.eval.binary.io import eval_BinaryReadList from mathics.eval.nevaluator import eval_N SymbolBinaryWrite = Symbol("BinaryWrite") @@ -57,7 +60,7 @@ def _IEEE_cmplx(real, imag): return Complex(MachineReal(real), MachineReal(imag)) @classmethod - def get_readers(cls): + def get_readers(cls) -> dict: readers = {} for funcname in dir(cls): if funcname.startswith("_") and funcname.endswith("_reader"): @@ -359,13 +362,13 @@ class BinaryRead(Builtin): https://reference.wolfram.com/language/ref/BinaryRead.html
-
'BinaryRead[$stream$]' +
'BinaryRead'[$stream$]
reads one byte from the stream as an integer from 0 to 255. -
'BinaryRead[$stream$, $type$]' +
'BinaryRead'[$stream$, $type$]
reads one object of specified type from the stream. -
'BinaryRead[$stream$, {$type1$, $type2$, ...}]' +
'BinaryRead'[$stream$, {$type_1$, $type_2$, ...}]
reads a sequence of objects of specified types.
@@ -376,70 +379,139 @@ class BinaryRead(Builtin): >> Close[strm]; >> strm = OpenRead[%, BinaryFormat -> True] = InputStream[...] - >> BinaryRead[strm, {"Character8", "Character8", "Character8"}] - = {a, b, c} + >> BinaryRead[strm] + = 97 + >> BinaryRead[strm, {"Character8", "Character8"}] + = {b, c} + + If you read past the end of the file, you will get 'EndOfFile' symbols: + + >> BinaryRead[strm, {"Character8", "Character8"}] + = {EndOfFile, EndOfFile} + >> DeleteFile[Close[strm]]; """ - summary_text = "read an object of the specified type" - readers = _BinaryFormat.get_readers() - messages = { "format": "`1` is not a recognized binary format.", "openw": "`1` is open for output.", "bfmt": "The stream `1` has been opened with BinaryFormat -> False and cannot be used with binary data.", } - def eval_empty(self, name, n, evaluation): - "BinaryRead[InputStream[name_, n_Integer]]" - return self.eval(name, n, None, evaluation) - - def eval(self, name, n, typ, evaluation): - "BinaryRead[InputStream[name_, n_Integer], typ_]" + readers = _BinaryFormat.get_readers() + summary_text = "read an object of the specified type" + def check_and_convert_parameters( + self, name, n: Integer, kind, evaluation: Evaluation + ) -> Tuple[bool, Expression, Optional[Stream], list]: channel = to_expression("InputStream", name, n) - # Check typ - if typ is None: + # Check kind + if kind is None: expr = to_expression("BinaryRead", channel) - typ = String("Byte") + kind = String("Byte") + else: + expr = to_expression("BinaryRead", channel, kind) + + if kind.has_form("List", None): + kinds = kind.elements else: - expr = to_expression("BinaryRead", channel, typ) + kinds = [kind] + + python_kinds = [t.get_string_value() for t in kinds] # Check channel stream = stream_manager.lookup_stream(n.value) if stream is None or stream.io.closed: evaluation.message("General", "openx", name) - return expr + return False, expr, None, python_kinds, [] if stream.mode not in ["rb"]: - evaluation.message("BinaryRead", "bfmt", channel) - return expr + evaluation.message(self.__class__.__name__, "bfmt", channel) + return False, expr, None, python_kinds, [] - if typ.has_form("List", None): - types = typ.elements - else: - types = [typ] + if not all(t in self.readers for t in python_kinds): + evaluation.message("BinaryRead", "format", kind) + return ( + False, + expr, + None, + python_kinds, + ) + + return True, expr, stream, python_kinds + + def eval_empty(self, name, n: Integer, evaluation): + "BinaryRead[InputStream[name_, n_Integer]]" + return self.eval(name, n, None, evaluation) + + def eval(self, name, n: Integer, kind, evaluation): + "BinaryRead[InputStream[name_, n_Integer], kind_]" - types = [t.get_string_value() for t in types] - if not all(t in self.readers for t in types): - evaluation.message("BinaryRead", "format", typ) + all_ok, expr, stream, python_kinds = self.check_and_convert_parameters( + name, n, kind, evaluation + ) + + if not all_ok or stream is None: return expr - # Read from stream - result = [] - for t in types: - try: - result.append(self.readers[t](stream.io)) - except struct.error: - result.append(SymbolEndOfFile) + return eval_BinaryReadList( + stream, self.readers, python_kinds, isinstance(kind, ListExpression), 1 + ) - if typ.has_form("List", None): - return to_mathics_list(*result) - else: - if len(result) == 1: - return result[0] + +class BinaryReadList(BinaryRead): + """ + + :WMA link: + https://reference.wolfram.com/language/ref/BinaryReadList.html + +
+
'BinaryReadList'[$stream$] +
reads all remaining bytes from the stream or file as an integer from 0 to 255. + +
'BinaryReadList'[$stream$, $type$] +
reads objects of the specified type file a stream or file until the end of the file. \ + The list of objects is returned. + +
'BinaryReadList'[$stream$, {$type_1$, $type_2$, ...}] +
reads a sequence of types, until the end of the file. +
+ + >> strm = OpenWrite[BinaryFormat -> True] + = OutputStream[...] + >> BinaryWrite[strm, {97, 98, 99}] + = OutputStream[...] + >> Close[strm]; + >> strm = OpenRead[%, BinaryFormat -> True] + = InputStream[...] + >> BinaryReadList[strm] + = {97, 98, 99} + >> DeleteFile[Close[strm]]; + """ + + messages = BinaryRead.messages + readers = _BinaryFormat.get_readers() + summary_text = "read a list of objects of the specified type" + + def eval_empty(self, name, n, evaluation: Evaluation): + "BinaryReadList[InputStream[name_, n_Integer]]" + return self.eval(name, n, None, evaluation) + + def eval(self, name, n: Integer, kind, evaluation: Evaluation): + "BinaryReadList[InputStream[name_, n_Integer], kind_]" + + all_ok, expr, stream, python_kinds = self.check_and_convert_parameters( + name, n, kind, evaluation + ) + + if not all_ok or stream is None: + return expr + + # TODO: improve speed when we are reading an entire binary file. Instead of read(1) we should be + # using read() + return eval_BinaryReadList(stream, self.readers, python_kinds, True, -1) class BinaryWrite(Builtin): @@ -449,22 +521,22 @@ class BinaryWrite(Builtin): https://reference.wolfram.com/language/ref/BinaryWrite.html
-
'BinaryWrite[$channel$, $b$]' +
'BinaryWrite'[$channel$, $b$]
writes a single byte given as an integer from 0 to 255. -
'BinaryWrite[$channel$, {b1, b2, ...}]' +
'BinaryWrite'[$channel$, {b1, b2, ...}]
writes a sequence of byte. -
'BinaryWrite[$channel$, "string"]' +
'BinaryWrite'[$channel$, "string"]
writes the raw characters in a string. -
'BinaryWrite[$channel$, $x$, $type$]' +
'BinaryWrite'[$channel$, $x$, $type$]
writes $x$ as the specified type. -
'BinaryWrite[$channel$, {$x1$, $x2$, ...}, $type$]' +
'BinaryWrite'[$channel$, {$x_1$, $x_2$, ...}, $type$]
writes a sequence of objects as the specified type. -
'BinaryWrite[$channel$, {$x1$, $x2$, ...}, {$type1$, $type2$, ...}]' +
'BinaryWrite'[$channel$, {$x_1$, $x_2$, ...}, {$type_1$, $type_2$, ...}]
writes a sequence of objects using a sequence of specified types.
@@ -527,17 +599,17 @@ def eval_notype(self, name, n, b, evaluation): "BinaryWrite[OutputStream[name_, n_], b_]" return self.eval(name, n, b, None, evaluation) - def eval(self, name, n, b, typ, evaluation): - "BinaryWrite[OutputStream[name_, n_], b_, typ_]" + def eval(self, name, n, b, kind, evaluation): + "BinaryWrite[OutputStream[name_, n_], b_, kind_]" channel = to_expression("OutputStream", name, n) - # Check Empty Type - if typ is None: + # Check Empty kind + if kind is None: expr = Expression(SymbolBinaryWrite, channel, b) - typ = to_expression("List") + kind = to_expression("List") else: - expr = Expression(SymbolBinaryWrite, channel, b, typ) + expr = Expression(SymbolBinaryWrite, channel, b, kind) # Check channel stream = stream_manager.lookup_stream(n.get_int_value()) @@ -557,17 +629,17 @@ def eval(self, name, n, b, typ, evaluation): pyb = [b] # Check Type - if typ.has_form("List", None): - types = typ.elements + if kind.has_form("List", None): + kinds = kind.elements else: - types = [typ] + kinds = [kind] - if len(types) == 0: # Default type is "Bytes" - types = [String("Byte")] + if len(kinds) == 0: # Default type is "Bytes" + kinds = [String("Byte")] - types = [t.get_string_value() for t in types] - if not all(t in self.writers for t in types): - evaluation.message("BinaryRead", "format", typ) + kinds = [t.get_string_value() for t in kinds] + if not all(t in self.writers for t in kinds): + evaluation.message("BinaryRead", "format", kind) return expr # Write to stream @@ -575,8 +647,8 @@ def eval(self, name, n, b, typ, evaluation): # TODO: please, modularize me. while i < len(pyb): x = pyb[i] - # Types are "repeated as many times as necessary" - t = types[i % len(types)] + # Kinds are "repeated as many times as necessary" + t = kinds[i % len(kinds)] # Coerce x if t == "TerminatedString": @@ -655,4 +727,4 @@ def eval(self, name, n, b, typ, evaluation): return channel -# TODO: BinaryReadList, BinaryWrite, BinaryReadList +# TODO: BinaryWrite, BinaryWriteList diff --git a/mathics/builtin/binary/system.py b/mathics/builtin/binary/system.py index 8887ebe8d..705e05774 100644 --- a/mathics/builtin/binary/system.py +++ b/mathics/builtin/binary/system.py @@ -29,10 +29,10 @@ class ByteOrdering(Predefined): class ByteOrdering_(Predefined): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/$ByteOrdering.html
-
'$ByteOrdering' +
'\$ByteOrdering'
returns the native ordering of bytes in binary data on your computer system.
diff --git a/mathics/builtin/box/graphics.py b/mathics/builtin/box/graphics.py index a91b55ee3..8362f6646 100644 --- a/mathics/builtin/box/graphics.py +++ b/mathics/builtin/box/graphics.py @@ -603,7 +603,6 @@ def get_range(min, max): if width > base_width: width = base_width height = width * aspect - height = height width *= size_multiplier height *= size_multiplier diff --git a/mathics/builtin/box/graphics3d.py b/mathics/builtin/box/graphics3d.py index 169e6bd99..9008c0343 100644 --- a/mathics/builtin/box/graphics3d.py +++ b/mathics/builtin/box/graphics3d.py @@ -226,8 +226,7 @@ def _prepare_elements(self, elements, options, max_width=None): boxratios = self.graphics_options["System`BoxRatios"].to_python() if boxratios == "System`Automatic": boxratios = ["System`Automatic"] * 3 - else: - boxratios = boxratios + if not isinstance(boxratios, list) or len(boxratios) != 3: raise BoxExpressionError diff --git a/mathics/builtin/box/layout.py b/mathics/builtin/box/layout.py index 94fb41c85..680215b27 100644 --- a/mathics/builtin/box/layout.py +++ b/mathics/builtin/box/layout.py @@ -50,7 +50,7 @@ class BoxData(Builtin): class ButtonBox(BoxExpression): """
-
'ButtonBox[$boxes$]' +
'ButtonBox'[$boxes$]
is a low-level box construct that represents a button \ in a notebook expression.
@@ -74,7 +74,7 @@ class FractionBox(BoxExpression): https://reference.wolfram.com/language/ref/FractionBox.html
-
'FractionBox[$x$, $y$]' +
'FractionBox'[$x$, $y$]
FractionBox[x, y] is a low-level formatting construct that represents $\frac{x}{y}$.
""" @@ -289,9 +289,9 @@ class SqrtBox(BoxExpression): :WMA link: https://reference.wolfram.com/language/ref/SqrtData.html
-
'SqrtBox[$x$]' +
'SqrtBox'[$x$]
is a low-level formatting construct that represents $\\sqrt{x}$. -
'SqrtBox[$x$, $y$]' +
'SqrtBox'[$x$, $y$]
represents $\\sqrt[y]{x}$.
""" @@ -381,7 +381,7 @@ def to_expression(self): class SubscriptBox(BoxExpression): """
-
'SubscriptBox[$a$, $b$]' +
'SubscriptBox'[$a$, $b$]
is a box construct that represents $a_b$.
@@ -426,7 +426,7 @@ class SubsuperscriptBox(BoxExpression): https://reference.wolfram.com/language/ref/SubsuperscriptBox.html
-
'SubsuperscriptBox[$a$, $b$, $c$]' +
'SubsuperscriptBox'[$a$, $b$, $c$]
is a box construct that represents $a_b^c$.
""" @@ -467,7 +467,7 @@ class SuperscriptBox(BoxExpression): :WMA link: https://reference.wolfram.com/language/ref/SuperscriptBox.html
-
'SuperscriptBox[$a$, $b$]' +
'SuperscriptBox'[$a$, $b$]
is a box construct that represents $a^b$.
@@ -522,7 +522,7 @@ class TemplateBox(BoxExpression): :WMA link: https://reference.wolfram.com/language/ref/TemplateBox.html
-
'TemplateBox[{$box_1$, $box_2$,...}, tag]' +
'TemplateBox'[{$box_1$, $box_2$,...}, tag]
is a low-level box structure that parameterizes the display and evaluation of the boxes $box_i$ .
""" diff --git a/mathics/builtin/colors/color_directives.py b/mathics/builtin/colors/color_directives.py index c9e5e949b..3a3ac6d23 100644 --- a/mathics/builtin/colors/color_directives.py +++ b/mathics/builtin/colors/color_directives.py @@ -227,7 +227,7 @@ class CMYKColor(_ColorObject): https://reference.wolfram.com/language/ref/CMYKColor.html)
-
'CMYKColor[$c$, $m$, $y$, $k$]' +
'CMYKColor'[$c$, $m$, $y$, $k$]
represents a color with the specified cyan, magenta, \ yellow and black components.
@@ -250,11 +250,11 @@ class ColorDistance(Builtin): https://reference.wolfram.com/language/ref/ColorDistance.html)
-
'ColorDistance[$c1$, $c2$]' -
returns a measure of color distance between the colors $c1$ and $c2$. +
'ColorDistance'[$c_1$, $c_2$] +
returns a measure of color distance between the colors $c_1$ and $c_2$. -
'ColorDistance[$list$, $c2$]' -
returns a list of color distances between the colors in $list$ and $c2$. +
'ColorDistance'[$list$, $c_2$] +
returns a list of color distances between the colors in $list$ and $c_2$.
The option DistanceFunction specifies the method used to measure the color @@ -460,10 +460,10 @@ class GrayLevel(_ColorObject): https://reference.wolfram.com/language/ref/GrayLevel.html
-
'GrayLevel[$g$]' +
'GrayLevel'[$g$]
represents a shade of gray specified by $g$, ranging from 0 (black) to 1 (white). -
'GrayLevel[$g$, $a$]' +
'GrayLevel'[$g$, $a$]
represents a shade of gray specified by $g$ with opacity $a$.
""" @@ -482,16 +482,16 @@ class Hue(_ColorObject): https://reference.wolfram.com/language/ref/Hue.html
-
'Hue[$h$, $s$, $l$, $a$]' +
'Hue'[$h$, $s$, $l$, $a$]
represents the color with hue $h$, saturation $s$, lightness $l$ and opacity $a$. -
'Hue[$h$, $s$, $l$]' +
'Hue'[$h$, $s$, $l$]
is equivalent to 'Hue[$h$, $s$, $l$, 1]'. -
'Hue[$h$, $s$]' +
'Hue'[$h$, $s$]
is equivalent to 'Hue[$h$, $s$, 1, 1]'. -
'Hue[$h$]' +
'Hue'[$h$]
is equivalent to 'Hue[$h$, 1, 1, 1]'.
@@ -546,7 +546,7 @@ class LABColor(_ColorObject): https://reference.wolfram.com/language/ref/LABColor.html
-
'LABColor[$l$, $a$, $b$]' +
'LABColor'[$l$, $a$, $b$]
represents a color with the specified lightness, red/green and yellow/blue components in the CIE 1976 L*a*b* (CIELAB) color space.
@@ -566,7 +566,7 @@ class LCHColor(_ColorObject): https://reference.wolfram.com/language/ref/LCHColor.html
-
'LCHColor[$l$, $c$, $h$]' +
'LCHColor'[$l$, $c$, $h$]
represents a color with the specified lightness, chroma and hue components in the CIELCh CIELab cube color space.
@@ -584,7 +584,7 @@ class LUVColor(_ColorObject): :WMA link:https://reference.wolfram.com/language/ref/LUVColor.html
-
'LCHColor[$l$, $u$, $v$]' +
'LCHColor'[$l$, $u$, $v$]
represents a color with the specified components in the CIE 1976 L*u*v* \ (CIELUV) color space.
@@ -605,7 +605,7 @@ class Opacity(_GraphicsDirective): https://reference.wolfram.com/language/ref/Opacity.html)
-
'Opacity[$level$]' +
'Opacity'[$level$]
is a graphics directive that sets the opacity to $level$; $level$ is a \ value between 0 and 1.
@@ -648,7 +648,7 @@ class RGBColor(_ColorObject): https://reference.wolfram.com/language/ref/RGBColor.html)
-
'RGBColor[$r$, $g$, $b$]' +
'RGBColor'[$r$, $g$, $b$]
represents a color with the specified red, green and blue \ components. These values should be a number between 0 and 1. \ Unless specified using the form below or using @@ -656,7 +656,7 @@ class RGBColor(_ColorObject): /doc/reference-of-built-in-symbols/colors/color-directives/opacity,\ default opacity is 1, a solid opaque color. -
'RGBColor[$r$, $g$, $b$, $a$]' +
'RGBColor'[$r$, $g$, $b$, $a$]
Same as above but an opacity value is specified. $a$ must have \ value between 0 and 1. \ 'RGBColor[$r$,$g$,$b$,$a$]' is equivalent to '{RGBColor[$r$,$g$,$b$],Opacity[$a$]}.' @@ -700,7 +700,7 @@ class XYZColor(_ColorObject): https://reference.wolfram.com/language/ref/XYZColor.html
-
'XYZColor[$x$, $y$, $z$]' +
'XYZColor'[$x$, $y$, $z$]
represents a color with the specified components in the CIE 1931 XYZ color space.
""" diff --git a/mathics/builtin/colors/color_operations.py b/mathics/builtin/colors/color_operations.py index e9b0198c8..c940e382f 100644 --- a/mathics/builtin/colors/color_operations.py +++ b/mathics/builtin/colors/color_operations.py @@ -33,15 +33,15 @@ class Blend(Builtin): https://reference.wolfram.com/language/ref/Blend.html
-
'Blend[{$c1$, $c2$}]' -
represents the color between $c1$ and $c2$. +
'Blend'[{$c_1$, $c_2$}] +
represents the color between $c_1$ and $c_2$. -
'Blend[{$c1$, $c2$}, $x$]' -
represents the color formed by blending $c1$ and $c2$ with +
'Blend'[{$c_1$, $c_2$}, $x$] +
represents the color formed by blending $c_1$ and $c_2$ with factors 1 - $x$ and $x$ respectively. -
'Blend[{$c1$, $c2$, ..., $cn$}, $x$]' -
blends between the colors $c1$ to $cn$ according to the +
'Blend'[{$c_1$, $c_2$, ..., $c_n$}, $x$] +
blends between the colors $c_1$ to $c_n$ according to the factor $x$.
@@ -153,7 +153,7 @@ class ColorConvert(Builtin): https://reference.wolfram.com/language/ref/ColorConvert.html
-
'ColorConvert[$c$, $colspace$]' +
'ColorConvert'[$c$, $colspace$]
returns the representation of $c$ in the color space $colspace$. $c$ \ may be a color or an image.
@@ -211,11 +211,11 @@ class ColorNegate(Builtin): https://reference.wolfram.com/language/ref/ColorNegate.html)
-
'ColorNegate[$color$]' +
'ColorNegate'[$color$]
returns the negative of a color, that is, the RGB color \ subtracted from white. -
'ColorNegate[$image$]' +
'ColorNegate'[$image$]
returns an image where each pixel has its color negated.
@@ -252,10 +252,10 @@ class Darker(Builtin): https://reference.wolfram.com/language/ref/Darker.html
-
'Darker[$c$, $f$]' -
is equivalent to 'Blend[{$c$, Black}, $f$]'. -
'Darker[$c$]' -
is equivalent to 'Darker[$c$, 1/3]'. +
'Darker'[$c$, $f$] +
is equivalent to 'Blend'[{$c$, 'Black'}, $f$]. +
'Darker'[$c$] +
is equivalent to 'Darker'[$c$, '1/3'].
>> Graphics[{Darker[Red], Disk[]}] @@ -279,13 +279,13 @@ class DominantColors(Builtin): https://reference.wolfram.com/language/ref/DominantColors.html
-
'DominantColors[$image$]' +
'DominantColors'[$image$]
gives a list of colors which are dominant in the given image. -
'DominantColors[$image$, $n$]' +
'DominantColors'[$image$, $n$]
returns at most $n$ colors. -
'DominantColors[$image$, $n$, $prop$]' +
'DominantColors'[$image$, $n$, $prop$]
returns the given property $prop$, which may be:
  • "Color": return RGB colors, @@ -467,11 +467,11 @@ class Lighter(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Lighter.html
    -
    'Lighter[$c$, $f$]' -
    is equivalent to 'Blend[{$c$, White}, $f$]'. +
    'Lighter'[$c$, $f$] +
    is equivalent to 'Blend'[{$c$, 'White'}, $f$]. -
    'Lighter[$c$]' -
    is equivalent to 'Lighter[$c$, 1/3]'. +
    'Lighter'[$c$] +
    is equivalent to 'Lighter'[$c$, '1/3'].
    >> Lighter[Orange, 1/4] diff --git a/mathics/builtin/compilation.py b/mathics/builtin/compilation.py index 110f5338c..629dbfc7f 100644 --- a/mathics/builtin/compilation.py +++ b/mathics/builtin/compilation.py @@ -37,11 +37,11 @@ class Compile(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Compile.html
    -
    'Compile[{$x1$, $x2$, ...}, $expr$]' +
    'Compile'[{$x_1$, $x_2$, ...}, $expr$]
    Compiles $expr$ assuming each $xi$ is a $Real$ number. -
    'Compile[{{$x1$, $t1$} {$x2$, $t1$} ...}, $expr$]' -
    Compiles assuming each $xi$ matches type $ti$. +
    'Compile'[{{$x_1$, $t_1$} {$x_2$, $t_1$} ...}, $expr$] +
    Compiles assuming each $x_i$ matches type $t_i$.
    Compilation is performed using llvmlite , or Python's builtin @@ -166,7 +166,7 @@ class CompiledFunction(Builtin): :WMA link:https://reference.wolfram.com/language/ref/CompiledFunction.html
    -
    'CompiledFunction[$args$...]' +
    'CompiledFunction'[$args$...]
    represents compiled code for evaluating a compiled function.
    diff --git a/mathics/builtin/compress.py b/mathics/builtin/compress.py index 1385a4193..e706448c6 100644 --- a/mathics/builtin/compress.py +++ b/mathics/builtin/compress.py @@ -18,7 +18,7 @@ class Compress(Builtin): https://reference.wolfram.com/language/ref/Compress.html
    -
    'Compress[$expr$]' +
    'Compress'[$expr$]
    gives a compressed string representation of $expr$.
    @@ -57,7 +57,7 @@ class Uncompress(Builtin): https://reference.wolfram.com/language/ref/Uncompress.html
    -
    'Uncompress["$string$"]' +
    'Uncompress'["$string$"]
    recovers an expression from a string generated by 'Compress'.
    diff --git a/mathics/builtin/datentime.py b/mathics/builtin/datentime.py index 4daa7dab0..b8fe6b54b 100644 --- a/mathics/builtin/datentime.py +++ b/mathics/builtin/datentime.py @@ -13,7 +13,7 @@ import sys import time from datetime import datetime, timedelta -from typing import Optional +from typing import Optional, Union import dateutil.parser @@ -97,16 +97,7 @@ EPOCH_START = datetime(1900, 1, 1) -if not hasattr(timedelta, "total_seconds"): - - def total_seconds(td): - return ( - float(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) - / 10**6 - ) - -else: - total_seconds = timedelta.total_seconds +total_seconds = timedelta.total_seconds SymbolDateObject = Symbol("DateObject") SymbolDateString = Symbol("DateString") @@ -114,8 +105,10 @@ def total_seconds(td): class _Date: - def __init__(self, datelist=[], absolute=None, datestr=None): - datelist += [1900, 1, 1, 0, 0, 0.0][len(datelist) :] + def __init__( + self, datelist_arg: Union[list, tuple] = [], absolute=None, datestr=None + ): + datelist = list(datelist_arg) + [1900, 1, 1, 0, 0, 0.0][len(datelist_arg) :] self.date = datetime( datelist[0], datelist[1], @@ -249,7 +242,7 @@ def to_datelist(self, epochtime, evaluation: Evaluation): ] return datelist - if not isinstance(etime, list): + if not isinstance(etime, (list, tuple)): evaluation.message(form_name, "arg", etime) return @@ -258,7 +251,7 @@ def to_datelist(self, epochtime, evaluation: Evaluation): for i, val in enumerate(etime) ): default_date = [1900, 1, 1, 0, 0, 0.0] - datelist = etime + default_date[len(etime) :] + datelist = list(etime) + default_date[len(etime) :] prec_part, imprec_part = datelist[:2], datelist[2:] try: @@ -289,12 +282,16 @@ def to_datelist(self, epochtime, evaluation: Evaluation): if len(etime) == 2: if ( isinstance(etime[0], str) - and isinstance(etime[1], list) # noqa + and isinstance(etime[1], (list, tuple)) # noqa and all(isinstance(s, str) for s in etime[1]) ): is_spec = [ str(s).strip('"') in DATE_STRING_FORMATS.keys() for s in etime[1] ] + + if isinstance(etime, tuple): + etime = list(etime) + etime[1] = [str(s).strip('"') for s in etime[1]] if sum(is_spec) == len(is_spec): @@ -348,13 +345,13 @@ class AbsoluteTime(_DateFormat):
    gives the local time in seconds since epoch January 1, 1900, in your \ time zone. -
    'AbsoluteTime[{$y$, $m$, $d$, $h$, $m$, $s$}]' +
    'AbsoluteTime'[{$y$, $m$, $d$, $h$, $m$, $s$}]
    gives the absolute time specification corresponding to a date list. -
    'AbsoluteTime["$string$"]' +
    'AbsoluteTime'["$string$"]
    gives the absolute time specification for a given date string. -
    'AbsoluteTime[{"$string$",{$e1$, $e2$, ...}}]' +
    'AbsoluteTime'[{"$string$",{$e_1$, $e_2$, ...}}]
    takgs the date string to contain the elements "$ei$".
@@ -389,7 +386,7 @@ def eval_spec(self, epochtime, evaluation: Evaluation) -> Optional[MachineReal]: if datelist is None: return - date = _Date(datelist=datelist) + date = _Date(datelist_arg=datelist) tdelta = date.date - EPOCH_START if tdelta.microseconds == 0: return Integer(int(total_seconds(tdelta))) @@ -401,7 +398,7 @@ class AbsoluteTiming(Builtin): :WMA link:https://reference.wolfram.com/language/ref/AbsoluteTiming.html
-
'AbsoluteTiming[$expr$]' +
'AbsoluteTiming'[$expr$]
evaluates $expr$, returning a list of the absolute number of seconds in \ real time that have elapsed, together with the result obtained.
@@ -430,13 +427,13 @@ class DateDifference(Builtin): :WMA link:https://reference.wolfram.com/language/ref/DateDifference.html
-
'DateDifference[$date1$, $date2$]' -
returns the difference between $date1$ and $date2$ in days. +
'DateDifference'[$date_1$, $date_2$] +
returns the difference between $date_1$ and $date_2$ in days. -
'DateDifference[$date1$, $date2$, $unit$]' +
'DateDifference'[$date_1$, $date_2$, $unit$]
returns the difference in the specified $unit$. -
'DateDifference[$date1$, $date2$, {$unit1$, $unit2$, ...}]' +
'DateDifference'[$date_1$, $date_2$, {$unit_1$, $unit_2$, ...}]
represents the difference as a list of integer multiples of each $unit$, with any remainder expressed in the smallest unit.
@@ -454,7 +451,7 @@ class DateDifference(Builtin): """ # FIXME: Since timedelta does not use large time units (years, months etc) - # this method can be innacuarate. The example below gives fractional Days + # this method can be inaccurate. The example below gives fractional Days # (20.1666666667 not 20). """ @@ -487,8 +484,8 @@ def eval( # Process dates pydate1, pydate2 = date1.to_python(), date2.to_python() - if isinstance(pydate1, list): # Date List - idate = _Date(datelist=pydate1) + if isinstance(pydate1, (list, tuple)): # Date List + idate = _Date(datelist_arg=pydate1) elif isinstance(pydate1, (float, int)): # Absolute Time idate = _Date(absolute=pydate1) elif isinstance(pydate1, str): # Date string @@ -497,8 +494,8 @@ def eval( evaluation.message("DateDifference", "date", date1) return - if isinstance(pydate2, list): # Date List - fdate = _Date(datelist=pydate2) + if isinstance(pydate2, (list, tuple)): # Date List + fdate = _Date(datelist_arg=pydate2) elif isinstance(pydate2, (int, float)): # Absolute Time fdate = _Date(absolute=pydate2) elif isinstance(pydate1, str): # Date string @@ -517,7 +514,9 @@ def eval( pyunits = units.to_python() if isinstance(pyunits, str): pyunits = [str(pyunits.strip('"'))] - elif isinstance(pyunits, list) and all(isinstance(p, str) for p in pyunits): + elif isinstance(pyunits, (list, tuple)) and all( + isinstance(p, str) for p in pyunits + ): pyunits = [p.strip('"') for p in pyunits] if not all(p in TIME_INCREMENTS.keys() for p in pyunits): @@ -590,7 +589,7 @@ class DateObject(_DateFormat, ImmutableValueMixin):
'DateObject[...]' -
Returns an object codifiyng DateList.... +
Returns an object codifying DateList....
>> DateObject[{2020, 4, 15}] @@ -717,19 +716,19 @@ class DatePlus(Builtin): :WMA link:https://reference.wolfram.com/language/ref/DatePlus.html
-
'DatePlus[$date$, $n$]' +
'DatePlus'[$date$, $n$]
finds the date $n$ days after $date$. -
'DatePlus[$date$, {$n$, "$unit$"}]' +
'DatePlus'[$date$, {$n$, "$unit$"}]
finds the date $n$ units after $date$. -
'DatePlus[$date$, {{$n1$, "$unit1$"}, {$n2$, "$unit2$"}, ...}]' +
'DatePlus'[$date$, {{$n_1$, "$unit_1$"}, {$n_2$, "$unit_2$"}, ...}]
finds the date which is $n_i$ specified units after $date$. -
'DatePlus[$n$]' +
'DatePlus'[$n$]
finds the date $n$ days after the current date. -
'DatePlus[$offset$]' +
'DatePlus'[$offset$]
finds the date which is offset from the current date.
@@ -762,9 +761,9 @@ def eval( # Process date pydate = date.to_python() - if isinstance(pydate, list): + if isinstance(pydate, (list, tuple)): date_prec = len(pydate) - idate = _Date(datelist=pydate) + idate = _Date(datelist_arg=pydate) elif isinstance(pydate, float) or isinstance(pydate, int): date_prec = "absolute" idate = _Date(absolute=pydate) @@ -779,13 +778,17 @@ def eval( pyoff = off.to_python() if isinstance(pyoff, float) or isinstance(pyoff, int): pyoff = [[pyoff, '"Day"']] - elif isinstance(pyoff, list) and len(pyoff) == 2 and isinstance(pyoff[1], str): + elif ( + isinstance(pyoff, (list, tuple)) + and len(pyoff) == 2 + and isinstance(pyoff[1], str) + ): pyoff = [pyoff] # Strip " marks pyoff = [[x[0], x[1].strip('"')] for x in pyoff] - if isinstance(pyoff, list) and all( # noqa + if isinstance(pyoff, (list, tuple)) and all( # noqa len(o) == 2 and o[1] in TIME_INCREMENTS.keys() and isinstance(o[0], (float, int)) @@ -820,10 +823,10 @@ class DateList(_DateFormat):
'DateList[]'
returns the current local time in the form {$year$, $month$, $day$, $hour$, $minute$, $second$}. -
'DateList[$time$]' +
'DateList'[$time$]
returns a formatted date for the number of seconds $time$ since epoch Jan 1 1900. -
'DateList[{$y$, $m$, $d$, $h$, $m$, $s$}]' +
'DateList'[{$y$, $m$, $d$, $h$, $m$, $s$}]
converts an incomplete date list to the standard representation.
@@ -888,22 +891,22 @@ class DateString(_DateFormat):
'DateString[]'
returns the current local time and date as a string. -
'DateString[$elem$]' +
'DateString'[$elem$]
returns the time formatted according to $elems$. -
'DateString[{$e1$, $e2$, ...}]' +
'DateString'[{$e_1$, $e_2$, ...}]
concatenates the time formatted according to elements $ei$. -
'DateString[$time$]' +
'DateString'[$time$]
returns the date string of an AbsoluteTime. -
'DateString[{$y$, $m$, $d$, $h$, $m$, $s$}]' +
'DateString'[{$y$, $m$, $d$, $h$, $m$, $s$}]
returns the date string of a date list specification. -
'DateString[$string$]' +
'DateString'[$string$]
returns the formatted date string of a date string specification. -
'DateString[$spec$, $elems$]' +
'DateString'[$spec$, $elems$]
formats the time in turns of $elems$. Both $spec$ and $elems$ can take any of the above formats.
@@ -940,15 +943,16 @@ def eval( self, epochtime: BaseElement, form: BaseElement, evaluation: Evaluation ) -> Optional[String]: "DateString[epochtime_, form_]" + datelist = self.to_datelist(epochtime, evaluation) if datelist is None: return - date = _Date(datelist=datelist) + date = _Date(datelist_arg=datelist) pyform = form.to_python() - if not isinstance(pyform, list): + if not isinstance(pyform, (list, tuple)): pyform = [pyform] pyform = [x.strip('"') for x in pyform] @@ -977,11 +981,11 @@ def eval( class DateStringFormat(Predefined): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/$DateStringFormat.html
-
'$DateStringFormat' +
'\$DateStringFormat'
gives the format used for dates generated by 'DateString'.
@@ -1009,7 +1013,7 @@ class EasterSunday(Builtin): # Calendar`EasterSunday https://reference.wolfram.com/language/Calendar/ref/EasterSunday.html)
-
'EasterSunday[$year$]' +
'EasterSunday'[$year$]
returns the date of the Gregorian Easter Sunday as {year, month, day}.
@@ -1046,13 +1050,13 @@ def eval(self, year: Integer, evaluation: Evaluation) -> ListExpression: class SystemTimeZone(Predefined): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/$SystemTimeZone.html
-
'$SystemTimeZone' +
'\$SystemTimeZone'
gives the current time zone for the computer system on which Mathics is \ being run.
@@ -1090,24 +1094,24 @@ def evaluate(self, evaluation: Evaluation) -> Expression: class TimeConstrained(Builtin): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/TimeConstrained.html
-
'TimeConstrained[$expr$, $t$]' +
'TimeConstrained'[$expr$, $t$]
'evaluates $expr$, stopping after $t$ seconds.' -
'TimeConstrained[$expr$, $t$, $failexpr$]' +
'TimeConstrained'[$expr$, $t$, $failexpr$]
'returns $failexpr$ if the time constraint is not met.'
Possible issues: for certain time-consuming functions (like simplify) which are based on sympy or other libraries, it is possible that the evaluation continues after the timeout. However, at the end of the \ - evaluation, the function will return '$Aborted' and the results will not affect + evaluation, the function will return '\$Aborted' and the results will not affect the state of the Mathics3 kernel. - + ## >> TimeConstrained[Pause[5]; a, 1] ## = $Aborted @@ -1155,13 +1159,13 @@ def eval_with_timeout_and_failexpr( class TimeZone(Predefined): - """ + r""" :Time Zone:https://en.wikipedia.org/wiki/Time_zone ( :WMA: https://reference.wolfram.com/language/ref/$TimeZone.html)
-
'$TimeZone' +
'\$TimeZone'
gives the current time zone to assume for dates and times.
@@ -1212,7 +1216,7 @@ class Timing(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Timing.html
-
'Timing[$expr$]' +
'Timing'[$expr$]
measures the processor time taken to evaluate $expr$. It returns a list containing the measured time in seconds and \ the result of the evaluation. @@ -1272,11 +1276,11 @@ class TimeRemaining(Builtin):
Gives the number of seconds remaining until the earliest enclosing \ 'TimeConstrained' will request the current computation to stop. -
'TimeConstrained[$expr$, $t$, $failexpr$]' +
'TimeConstrained'[$expr$, $t$, $failexpr$]
returns $failexpr$ if the time constraint is not met.
- If TimeConstrained is called out of a TimeConstrained expression, returns `Infinity` + If TimeConstrained is called out of a TimeConstrained expression, returns 'Infinity': >> TimeRemaining[] = Infinity diff --git a/mathics/builtin/directories/directory_names.py b/mathics/builtin/directories/directory_names.py index 21129c10a..b7204a349 100644 --- a/mathics/builtin/directories/directory_names.py +++ b/mathics/builtin/directories/directory_names.py @@ -21,7 +21,7 @@ class DirectoryName(Builtin): https://reference.wolfram.com/language/ref/DirectoryName.html
-
'DirectoryName["$name$"]' +
'DirectoryName'["$name$"]
extracts the directory name from a filename.
@@ -64,7 +64,7 @@ def eval_with_n(self, name, n, evaluation: Evaluation, options: dict): result = py_name for i in range(py_n): - (result, tmp) = osp.split(result) + result, tmp = osp.split(result) return String(result) @@ -79,7 +79,7 @@ class DirectoryQ(Builtin): https://reference.wolfram.com/language/ref/DirectoryQ.html
-
'DirectoryQ["$name$"]' +
'DirectoryQ'["$name$"]
returns 'True' if the directory called $name$ exists and 'False' otherwise.
@@ -118,7 +118,7 @@ class FileNameDepth(Builtin): https://reference.wolfram.com/language/ref/FileNameDepth.html
-
'FileNameDepth["$name$"]' +
'FileNameDepth'["$name$"]
gives the number of path parts in the given filename.
@@ -145,7 +145,7 @@ class FileNameJoin(Builtin): https://reference.wolfram.com/language/ref/FileNameJoin.html
-
'FileNameJoin[{"$dir_1$", "$dir_2$", ...}]' +
'FileNameJoin'[{"$dir_1$", "$dir_2$", ...}]
joins the $dir_i$ together into one path.
'FileNameJoin[..., OperatingSystem->"os"]' @@ -177,14 +177,19 @@ class FileNameJoin(Builtin): def eval(self, pathlist, evaluation: Evaluation, options: dict): "FileNameJoin[pathlist_List, OptionsPattern[FileNameJoin]]" + # Convert pathlist to a Python list, and strip leading and trailing + # quotes if that appears. py_pathlist = pathlist.to_python() - if not all(isinstance(p, str) and p[0] == p[-1] == '"' for p in py_pathlist): + + if not all(isinstance(p, str) for p in py_pathlist): return - py_pathlist = [p[1:-1] for p in py_pathlist] - operating_system = ( - options["System`OperatingSystem"].evaluate(evaluation).get_string_value() - ) + if isinstance(py_pathlist, tuple): + py_pathlist = list(py_pathlist) + else: + py_pathlist = [p[1:-1] if p[0] == p[-1] == '"' else p for p in py_pathlist] + + operating_system = options["System`OperatingSystem"].evaluate(evaluation).value if operating_system not in ["MacOSX", "Windows", "Unix"]: evaluation.message( @@ -219,7 +224,7 @@ class FileNameSplit(Builtin): https://reference.wolfram.com/language/ref/FileNameSplit.html
-
'FileNameSplit["$filenames$"]' +
'FileNameSplit'["$filenames$"]
splits a $filename$ into a list of parts.
@@ -280,7 +285,7 @@ class ParentDirectory(Builtin):
'ParentDirectory[]'
returns the parent of the current working directory. -
'ParentDirectory["$dir$"]' +
'ParentDirectory'["$dir$"]
returns the parent $dir$.
diff --git a/mathics/builtin/directories/directory_operations.py b/mathics/builtin/directories/directory_operations.py index ce27bf5bf..0461a1e2b 100644 --- a/mathics/builtin/directories/directory_operations.py +++ b/mathics/builtin/directories/directory_operations.py @@ -23,7 +23,7 @@ class CreateDirectory(Builtin): https://reference.wolfram.com/language/ref/CreateDirectory.html
-
'CreateDirectory["$dir$"]' +
'CreateDirectory'["$dir$"]
creates a directory called $dir$.
'CreateDirectory[]' @@ -88,7 +88,7 @@ class DeleteDirectory(Builtin): https://reference.wolfram.com/language/ref/DeleteDirectory.html
-
'DeleteDirectory["$dir$"]' +
'DeleteDirectory'["$dir$"]
deletes a directory called $dir$.
@@ -152,8 +152,8 @@ class RenameDirectory(Builtin): :WMA link:https://reference.wolfram.com/language/ref/RenameDirectory.html
-
'RenameDirectory["$dir1$", "$dir2$"]' -
renames directory $dir1$ to $dir2$. +
'RenameDirectory'["$dir_1$", "$dir_2$"] +
renames directory $dir_1$ to $dir_2$.
""" @@ -173,7 +173,7 @@ def eval(self, dirs, evaluation): if len(seq) != 2: evaluation.message("RenameDirectory", "argr", "RenameDirectory", 2) return - (dir1, dir2) = (s.to_python() for s in seq) + dir1, dir2 = (s.to_python() for s in seq) if not (isinstance(dir1, str) and dir1[0] == dir1[-1] == '"'): evaluation.message("RenameDirectory", "fstr", seq[0]) diff --git a/mathics/builtin/directories/system_directories.py b/mathics/builtin/directories/system_directories.py index 7165d37f8..4eb197739 100644 --- a/mathics/builtin/directories/system_directories.py +++ b/mathics/builtin/directories/system_directories.py @@ -11,12 +11,12 @@ class BaseDirectory_(Predefined): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/$BaseDirectory.html
-
'$BaseDirectory' +
'\$BaseDirectory'
returns the folder where user configurations are stored.
@@ -32,12 +32,12 @@ def evaluate(self, evaluation: Evaluation): class InitialDirectory(Predefined): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/$InitialDirectory.html
-
'$InitialDirectory' +
'\$InitialDirectory'
returns the directory from which \\Mathics was started.
@@ -53,12 +53,12 @@ def evaluate(self, evaluation: Evaluation): class InstallationDirectory(Predefined): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/InstallationDirectory.html
-
'$InstallationDirectory' +
'\$InstallationDirectory'
returns the top-level directory in which \\Mathics was installed.
@@ -76,11 +76,11 @@ def evaluate(self, evaluation): class RootDirectory(Predefined): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/$RootDirectory.html
-
'$RootDirectory' +
'\$RootDirectory'
returns the system root directory.
@@ -96,12 +96,12 @@ def evaluate(self, evaluation): class TemporaryDirectory(Predefined): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/$TemporaryDirectory.html
-
'$TemporaryDirectory' +
'\$TemporaryDirectory'
returns the directory used for temporary files.
diff --git a/mathics/builtin/distance/clusters.py b/mathics/builtin/distance/clusters.py index e82b3b6d2..96583f4bd 100644 --- a/mathics/builtin/distance/clusters.py +++ b/mathics/builtin/distance/clusters.py @@ -244,11 +244,11 @@ class ClusteringComponents(_Cluster): :WMA link:https://reference.wolfram.com/language/ref/ClusteringComponents.html
-
'ClusteringComponents[$list$]' +
'ClusteringComponents'[$list$]
forms clusters from $list$ and returns a list of cluster indices, in which each element shows the index of the cluster in which the corresponding element in $list$ ended up. -
'ClusteringComponents[$list$, $k$]' +
'ClusteringComponents'[$list$, $k$]
forms $k$ clusters from $list$ and returns a list of cluster indices, in which each element shows the index of the cluster in which the corresponding element in $list$ ended up. @@ -293,10 +293,10 @@ class FindClusters(_Cluster): :WMA link:https://reference.wolfram.com/language/ref/FindClusters.html
-
'FindClusters[$list$]' +
'FindClusters'[$list$]
returns a list of clusters formed from the elements of $list$. The number of cluster is determined automatically. -
'FindClusters[$list$, $k$]' +
'FindClusters'[$list$, $k$]
returns a list of $k$ clusters formed from the elements of $list$.
@@ -374,20 +374,20 @@ class Nearest(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Nearest.html
-
'Nearest[$list$, $x$]' +
'Nearest'[$list$, $x$]
returns the one item in $list$ that is nearest to $x$. -
'Nearest[$list$, $x$, $n$]' +
'Nearest'[$list$, $x$, $n$]
returns the $n$ nearest items. -
'Nearest[$list$, $x$, {$n$, $r$}]' +
'Nearest'[$list$, $x$, {$n$, $r$}]
returns up to $n$ nearest items that are not farther from $x$ than $r$. -
'Nearest[{$p1$ -> $q1$, $p2$ -> $q2$, ...}, $x$]' -
returns $q1$, $q2$, ... but measures the distances using $p1$, $p2$, ... +
'Nearest'[{$p_1$ -> $q_1$, $p_2$ -> $q_2$, ...}, $x$] +
returns $q_1$, $q_2$, ... but measures the distances using $p_1$, $p_2$, ... -
'Nearest[{$p1$, $p2$, ...} -> {$q1$, $q2$, ...}, $x$]' -
returns $q1$, $q2$, ... but measures the distances using $p1$, $p2$, ... +
'Nearest'[{$p_1$, $p_2$, ...} -> {$q_1$, $q_2$, ...}, $x$] +
returns $q_1$, $q_2$, ... but measures the distances using $p_1$, $p_2$, ...
>> Nearest[{5, 2.5, 10, 11, 15, 8.5, 14}, 12] diff --git a/mathics/builtin/distance/numeric.py b/mathics/builtin/distance/numeric.py index bff809d6b..ad117bcdd 100644 --- a/mathics/builtin/distance/numeric.py +++ b/mathics/builtin/distance/numeric.py @@ -48,11 +48,11 @@ class BrayCurtisDistance(Builtin): https://reference.wolfram.com/language/ref/BrayCurtisDistance.html)
-
'BrayCurtisDistance[$u$, $v$]' +
'BrayCurtisDistance'[$u$, $v$]
returns the Bray-Curtis distance between $u$ and $v$.
- The Bray-Curtis distance is equivalent to Total[Abs[u-v]]/Total[Abs[u+v]]. + The Bray-Curtis distance is equivalent to 'Total[Abs[u-v]]/Total[Abs[u+v]]'. >> BrayCurtisDistance[-7, 5] = 6 @@ -85,7 +85,7 @@ class CanberraDistance(Builtin): https://reference.wolfram.com/language/ref/CanberraDistance.html)
-
'CanberraDistance[$u$, $v$]' +
'CanberraDistance'[$u$, $v$]
returns the canberra distance between $u$ and $v$, which is a weighted version of the Manhattan distance.
@@ -122,7 +122,7 @@ class ChessboardDistance(Builtin): https://reference.wolfram.com/language/ref/ChessboardDistance.html)
-
'ChessboardDistance[$u$, $v$]' +
'ChessboardDistance'[$u$, $v$]
returns the chessboard distance (also known as Chebyshev distance) between $u$ and $v$, which is the number of moves a king on a chessboard needs to get from square $u$ to square $v$.
@@ -150,11 +150,11 @@ class CosineDistance(Builtin): https://reference.wolfram.com/language/ref/CosineDistance.html)
-
'CosineDistance[$u$, $v$]' +
'CosineDistance'[$u$, $v$]
returns the angular cosine distance between vectors $u$ and $v$.
- The cosine distance is equivalent to 1 - ($u$.Conjugate[$v$]) / ('Norm[$u$] Norm[$v$]'). + The cosine distance is equivalent to $1 - (u.Conjugate[v]) / (Norm[u] Norm[v])$. >> N[CosineDistance[{7, 9}, {71, 89}]] = 0.0000759646 @@ -229,7 +229,7 @@ class EuclideanDistance(Builtin): https://reference.wolfram.com/language/ref/EuclideanDistance.html)
-
'EuclideanDistance[$u$, $v$]' +
'EuclideanDistance'[$u$, $v$]
returns the euclidean distance between $u$ and $v$.
@@ -262,7 +262,7 @@ class ManhattanDistance(Builtin): https://reference.wolfram.com/language/ref/ManhattanDistance.html)
-
'ManhattanDistance[$u$, $v$]' +
'ManhattanDistance'[$u$, $v$]
returns the Manhattan distance between $u$ and $v$, which is the number of horizontal or vertical moves in the gridlike Manhattan city layout to get from $u$ to $v$.
@@ -289,7 +289,7 @@ class SquaredEuclideanDistance(Builtin): https://reference.wolfram.com/language/ref/SquaredEuclideanDistance.html
-
'SquaredEuclideanDistance[$u$, $v$]' +
'SquaredEuclideanDistance'[$u$, $v$]
returns squared the euclidean distance between $u$ and $v$.
diff --git a/mathics/builtin/distance/stringdata.py b/mathics/builtin/distance/stringdata.py index e4099c6b5..7275a89e6 100644 --- a/mathics/builtin/distance/stringdata.py +++ b/mathics/builtin/distance/stringdata.py @@ -148,7 +148,7 @@ class DamerauLevenshteinDistance(_StringDistance): :WMA link:https://reference.wolfram.com/language/ref/DamerauLevenshteinDistance.html
-
'DamerauLevenshteinDistance[$a$, $b$]' +
'DamerauLevenshteinDistance'[$a$, $b$]
returns the Damerau-Levenshtein distance of $a$ and $b$, which is defined as the minimum number of transpositions, insertions, deletions and substitutions needed to transform one into the other. In contrast to EditDistance, DamerauLevenshteinDistance counts transposition of adjacent items (e.g. @@ -190,7 +190,7 @@ class EditDistance(_StringDistance): :WMA link:https://reference.wolfram.com/language/ref/EditDistance.html
-
'EditDistance[$a$, $b$]' +
'EditDistance'[$a$, $b$]
returns the Levenshtein distance of $a$ and $b$, which is defined as the minimum number of insertions, deletions and substitutions on the constituents of $a$ and $b$ needed to transform one into the other. @@ -231,7 +231,7 @@ class HammingDistance(Builtin): :WMA link:https://reference.wolfram.com/language/ref/HammingDistance.html
-
'HammingDistance[$u$, $v$]' +
'HammingDistance'[$u$, $v$]
returns the Hamming distance between $u$ and $v$, i.e. the number of different elements. $u$ and $v$ may be lists or strings.
diff --git a/mathics/builtin/drawing/drawing_options.py b/mathics/builtin/drawing/drawing_options.py index 4c7cb7a40..5d7406821 100644 --- a/mathics/builtin/drawing/drawing_options.py +++ b/mathics/builtin/drawing/drawing_options.py @@ -318,7 +318,7 @@ class PlotRange(Builtin):
  • $max$ - explicit limit for each function.
  • {$min$, $max$} - explicit limits for $y$ (2D), $z$ (3D), \ or array values. -
  • {{$x$_$min$, $x$_$max$}, {{$y_min}, {$y_max}} - explicit limits for \ +
  • {{$x_{min}$, $x_{max}$}, {{$y_{min}$}, {$y_{max}$}} - explicit limits for \ $x$ and $y$. diff --git a/mathics/builtin/drawing/graphics3d.py b/mathics/builtin/drawing/graphics3d.py index 230b72535..fe965c120 100644 --- a/mathics/builtin/drawing/graphics3d.py +++ b/mathics/builtin/drawing/graphics3d.py @@ -66,7 +66,7 @@ class Graphics3D(Graphics): :WMA link:https://reference.wolfram.com/language/ref/Graphics3D.html
    -
    'Graphics3D[$primitives$, $options$]' +
    'Graphics3D'[$primitives$, $options$]
    represents a three-dimensional graphic. See :Drawing Option and Option Values: @@ -90,7 +90,7 @@ class Graphics3D(Graphics): . import tube; . size(6.6667cm, 6.6667cm); . currentprojection=perspective(2.6,-4.8,4.0); - . currentlight=light(rgb(0.5,0.5,1), specular=red, (2,0,2), (2,2,2), (0,2,2)); + . currentlight=light(rgb(0.5,0.5,0.5), specular=red, (2,0,2), (2,2,2), (0,2,2)); . // Sphere3DBox . draw(surface(sphere((0, 0, 0), 1)), rgb(1,1,1)+opacity(1)); . draw(((-1,-1,-1)--(1,-1,-1)), rgb(0.4, 0.4, 0.4)+linewidth(1)); @@ -165,50 +165,26 @@ def _apply_boxscaling(self, boxscale): element._apply_boxscaling(boxscale) -class Sphere(Builtin): - """ - :WMA link:https://reference.wolfram.com/language/ref/Sphere.html - -
    -
    'Sphere[{$x$, $y$, $z$}]' -
    is a sphere of radius 1 centered at the point {$x$, $y$, $z$}. -
    'Sphere[{$x$, $y$, $z$}, $r$]' -
    is a sphere of radius $r$ centered at the point {$x$, $y$, $z$}. -
    'Sphere[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z2$}, ... }, $r$]' -
    is a collection spheres of radius $r$ centered at the points \ - {$x1$, $y2$, $z2$}, {$x2$, $y2$, $z2$}, ... -
    - - >> Graphics3D[Sphere[{0, 0, 0}, 1]] - = -Graphics3D- - - >> Graphics3D[{Yellow, Sphere[{{-1, 0, 0}, {1, 0, 0}, {0, 0, Sqrt[3.]}}, 1]}] - = -Graphics3D- - """ - - summary_text = "a sphere" - rules = { - "Sphere[]": "Sphere[{0, 0, 0}, 1]", - "Sphere[positions_]": "Sphere[positions, 1]", - } - - class Cone(Builtin): """ - :WMA link:https://reference.wolfram.com/language/ref/Cone.html + :Cone:https://en.wikipedia.org/wiki/Cone ( + :WMA:https://reference.wolfram.com/language/ref/Cone.html)
    -
    'Cone[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z2$}}]' -
    represents a cone of radius 1. +
    'Cone'[] +
    is a cone of radius 1 and height 2 oriented in the upward $z$ direction. -
    'Cone[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z2$}}, $r$]' -
    is a cone of radius $r$ starting at ($x1$, $y1$, $z1$) and ending at \ - ($x2$, $y2$, $z2$). +
    'Cone'[{{$x_1$, $y_1$, $z_1$}, {$x_2$, $y_2$, $z_2$}}, $r$] +
    is a cone of radius $r$ starting at ($x_1$, $y_1$, $z_1$) and ending at \ + ($x_2$, $y_2$, $z_2$). -
    'Cone[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z2$}, ... }, $r$]' +
    'Cone'[{{$x_1$, $y_1$, $z_1$}, {$x_2$, $y_2$, $z_2$}, ... }, $r$]
    is a collection cones of radius $r$.
    + >> Graphics3D[Cone[]] + = -Graphics3D- + >> Graphics3D[Cone[{{0, 0, 0}, {1, 1, 1}}, 1]] = -Graphics3D- @@ -216,14 +192,14 @@ class Cone(Builtin): = -Graphics3D- """ - summary_text = "a cone" + summary_text = "represent a cone" messages = { "oddn": "The number of points must be even.", "nrr": "The radius must be a real number", } rules = { - "Cone[]": "Cone[{{0, 0, 0}, {1, 1, 1}}, 1]", + "Cone[]": "Cone[{{0, 0, 0}, {0, 0, 2}}, 1]", "Cone[positions_List]": "Cone[positions, 1]", } @@ -243,23 +219,26 @@ def eval_check(self, positions, radius, evaluation: Evaluation): class Cuboid(Builtin): """ - :WMA link:https://reference.wolfram.com/language/ref/Cuboid.html + :Cuboid: + https://en.wikipedia.org/wiki/Cuboid ( + :WMA:https://reference.wolfram.com/language/ref/Cuboid.html) - Cuboid also known as interval, rectangle, square, cube, rectangular parallelepiped, tesseract, orthotope, and box. + Cuboid also known as interval, rectangle, square, cube, rectangular parallelepiped, \ + tesseract, orthotope, and box.
    -
    'Cuboid[$p_min$]' -
    is a unit cube/square with its lower corner at point $p_min$. +
    'Cuboid'[$p_{min}$] +
    is a unit cube/square with its lower corner at point $p_{min}$. -
    'Cuboid[$p_min$, $p_max$] -
    is a 2d square with with lower corner $p_min$ and upper corner $p_max$. +
    'Cuboid'[$p_{min}$, $p_{max}$] +
    is a 2d square with with lower corner $p_{min}$ and upper corner $p_{max}$. -
    'Cuboid[{$p_min$, $p_max$}]' -
    is a cuboid with lower corner $p_min$ and upper corner $p_max$. +
    'Cuboid'[{$p_{min}$, $p_{max}$}] +
    is a cuboid with lower corner $p_{min}$ and upper corner $p_{max}$. -
    'Cuboid[{$p1_min$, $p1_max$, ...}]' +
    'Cuboid'[{$p1_{min}$, $p1_{max}$, ...}]
    is a collection of cuboids. -
    'Cuboid[]' is equivalent to 'Cuboid[{0,0,0}]'. +
    'Cuboid[]' is equivalent to 'Cuboid'[{0,0,0}].
    >> Graphics3D[Cuboid[{0, 0, 1}]] @@ -270,8 +249,6 @@ class Cuboid(Builtin): >> Graphics[Cuboid[{0, 0}]] = -Graphics- - - ## """ messages = {"oddn": "The number of points must be even."} @@ -283,7 +260,7 @@ class Cuboid(Builtin): "Cuboid[{xmin_, ymin_, zmin_}]": "Cuboid[{{xmin, ymin, zmin}, {xmin + 1, ymin + 1, zmin + 1}}]", } - summary_text = "unit cube" + summary_text = "represent a unit cube" def eval_check(self, positions, evaluation: Evaluation): "Cuboid[positions_List]" @@ -297,18 +274,20 @@ def eval_check(self, positions, evaluation: Evaluation): class Cylinder(Builtin): """ - :WMA link:https://reference.wolfram.com/language/ref/Cylinder.html + :Cylinder: + https://en.wikipedia.org/wiki/Cylinder ( + :WMA:https://reference.wolfram.com/language/ref/Cylinder.html)
    -
    'Cylinder[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z2$}}]' +
    'Cylinder'[{{$x_1$, $y_1$, $z_1$}, {$x_2$, $y_2$, $z_2$}}]
    represents a cylinder of radius 1. -
    'Cylinder[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z2$}}, $r$]' -
    is a cylinder of radius $r$ starting at ($x1$, $y1$, $z1$) and ending at \ - ($x2$, $y2$, $z2$). +
    'Cylinder'[{{$x_1$, $y_1$, $z_1$}, {$x_2$, $y_2$, $z_2$}}, $r$] +
    represents a cylinder of radius $r$ starting at ($x_1$, $y_1$, $z_1$) and ending at \ + ($x_2$, $y_2$, $z_2$). -
    'Cylinder[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z2$}, ... }, $r$]' -
    is a collection cylinders of radius $r$. +
    'Cylinder'[{{$x_1$, $y_1$, $z_1$}, {$x_2$, $y_2$, $z_2$}, ... }, $r$] +
    represents is a collection cylinders of radius $r$.
    >> Graphics3D[Cylinder[{{0, 0, 0}, {1, 1, 1}}, 1]] @@ -318,7 +297,7 @@ class Cylinder(Builtin): = -Graphics3D- """ - summary_text = "a cylinder" + summary_text = "represent a cylinder" messages = { "oddn": "The number of points must be even.", "nrr": "The radius must be a real number", @@ -343,15 +322,43 @@ def eval_check(self, positions, radius, evaluation: Evaluation): return +class Sphere(Builtin): + """ + :WMA link:https://reference.wolfram.com/language/ref/Sphere.html + +
    +
    'Sphere'[{$x$, $y$, $z$}] +
    is a sphere of radius 1 centered at the point {$x$, $y$, $z$}. +
    'Sphere'[{$x$, $y$, $z$}, $r$] +
    is a sphere of radius $r$ centered at the point {$x$, $y$, $z$}. +
    'Sphere'[{{$x_1$, $y_1$, $z_1$}, {$x_2$, $y_2$, $z_2$}, ... }, $r$] +
    is a collection spheres of radius $r$ centered at the points \ + {$x_1$, $y_2$, $z_2$}, {$x_2$, $y_2$, $z_2$}, ... +
    + + >> Graphics3D[Sphere[{0, 0, 0}, 1]] + = -Graphics3D- + + >> Graphics3D[{Yellow, Sphere[{{-1, 0, 0}, {1, 0, 0}, {0, 0, Sqrt[3.]}}, 1]}] + = -Graphics3D- + """ + + summary_text = "represent a sphere" + rules = { + "Sphere[]": "Sphere[{0, 0, 0}, 1]", + "Sphere[positions_]": "Sphere[positions, 1]", + } + + class Tube(Builtin): """ :WMA link:https://reference.wolfram.com/language/ref/Tube.html
    -
    'Tube[{$p1$, $p2$, ...}]' -
    represents a tube passing through $p1$, $p2$, ... with radius 1. +
    'Tube'[{$p_1$, $p_2$, ...}] +
    represents a tube passing through $p_1$, $p_2$, ... with radius 1. -
    'Tube[{$p1$, $p2$, ...}, $r$]' +
    'Tube'[{$p_1$, $p_2$, ...}, $r$]
    represents a tube with radius $r$.
    @@ -362,7 +369,7 @@ class Tube(Builtin): = -Graphics3D- """ - summary_text = "a tube" + summary_text = "represent a tube" rules = { "Tube[]": "Tube[{{0, 0, 0}, {1, 1, 1}}, 1]", "Tube[positions_]": "Tube[positions, 1]", diff --git a/mathics/builtin/drawing/graphics_internals.py b/mathics/builtin/drawing/graphics_internals.py index fdbba4c4b..adb5c27aa 100644 --- a/mathics/builtin/drawing/graphics_internals.py +++ b/mathics/builtin/drawing/graphics_internals.py @@ -26,7 +26,7 @@ def create_as_style(klass, graphics, item): class _GraphicsElementBox(BoxExpression, ABC): - def init(self, graphics, item=None, style=None, opacity=1.0): + def init(self, graphics, item=None, style={}, opacity=1.0): if item is not None and not item.has_form(self.get_name(), None): raise BoxExpressionError self.graphics = graphics diff --git a/mathics/builtin/drawing/plot.py b/mathics/builtin/drawing/plot.py index b273ebf34..b2d7fee3f 100644 --- a/mathics/builtin/drawing/plot.py +++ b/mathics/builtin/drawing/plot.py @@ -427,8 +427,8 @@ class BarChart(_Chart): """ :WMA link: https://reference.wolfram.com/language/ref/BarChart.html
    -
    'BarChart[{$b1$, $b2$ ...}]' -
    makes a bar chart with lengths $b1$, $b2$, .... +
    'BarChart'[{$b_1$, $b_2$ ...}] +
    makes a bar chart with lengths $b_1$, $b_2$, ....
    Drawing options include - @@ -484,7 +484,7 @@ class ColorData(Builtin): """ :WMA link: https://reference.wolfram.com/language/ref/ColorData.html
    -
    'ColorData["$name$"]' +
    'ColorData'["$name$"]
    returns a color function with the given $name$.
    @@ -550,8 +550,8 @@ class DensityPlot(_Plot3D): """ :WMA link: https://reference.wolfram.com/language/ref/DensityPlot.html
    -
    'DensityPlot[$f$, {$x$, $xmin$, $xmax$}, {$y$, $ymin$, $ymax$}]' -
    plots a density plot of $f$ with $x$ ranging from $xmin$ to $xmax$ and $y$ ranging from $ymin$ to $ymax$. +
    'DensityPlot'[$f$, {$x$, $x_{min}$, $x_{max}$}, {$y$, $y_{min}$, $y_{max}$}] +
    plots a density plot of $f$ with $x$ ranging from $x_{min}$ to $x_{max}$ and $y$ ranging from $y_{min}$ to $y_{max}$.
    >> DensityPlot[x ^ 2 + 1 / y, {x, -1, 1}, {y, 1, 4}] @@ -610,16 +610,16 @@ class DiscretePlot(_Plot): """ :WMA link: https://reference.wolfram.com/language/ref/DiscretePlot.html
    -
    'DiscretePlot[$expr$, {$x$, $n_max$}]' -
    plots $expr$ with $x$ ranging from 1 to $n_max$. +
    'DiscretePlot'[$expr$, {$x$, $n_{max}$}] +
    plots $expr$ with $x$ ranging from 1 to $n_{max}$. -
    'DiscretePlot[$expr$, {$x$, $n_min$, $n_max$}]' -
    plots $expr$ with $x$ ranging from $n_min$ to $n_max$. +
    'DiscretePlot'[$expr$, {$x$, $n_{min}$, $n_{max}$}] +
    plots $expr$ with $x$ ranging from $n_{min}$ to $n_{max}$. -
    'DiscretePlot[$expr$, {$x$, $n_min$, $n_max$, $dn$}]' -
    plots $expr$ with $x$ ranging from $n_min$ to $n_max$ usings steps $dn$. +
    'DiscretePlot'[$expr$, {$x$, $n_{min}$, $n_{max}$, $dn$}] +
    plots $expr$ with $x$ ranging from $n_{min}$ to $n_{max}$ usings steps $dn$. -
    'DiscretePlot[{$expr1$, $expr2$, ...}, ...]' +
    'DiscretePlot'[{$expr_1$, $expr_2$, ...}, ...]
    plots the values of all $expri$.
    @@ -631,7 +631,7 @@ class DiscretePlot(_Plot): >> DiscretePlot[2.5 Sqrt[k], {k, 100}] = -Graphics- - Notice in the above that when the starting value, $n_min$, is 1, we can \ + Notice in the above that when the starting value, $n_{min}$, is 1, we can \ omit it. A plot can contain several functions, using the same parameter, here $x$: @@ -674,7 +674,7 @@ class DiscretePlot(_Plot): "DiscretePlot[expr_, {var_Symbol, nmin_Integer, nmax_Integer}, options___]": "DiscretePlot[expr, {var, nmin, nmax, 1, options}]", } - summary_text = "discrete plot of a one-paremeter function" + summary_text = "discrete plot of a one-parameter function" def eval( self, functions, x, start, nmax, step, evaluation: Evaluation, options: dict @@ -791,8 +791,8 @@ class Histogram(Builtin): (:WMA link: https://reference.wolfram.com/language/ref/ColorDataFunction.html)
    -
    'Histogram[{$x1$, $x2$ ...}]' -
    plots a histogram using the values $x1$, $x2$, .... +
    'Histogram'[{$x_1$, $x_2$ ...}] +
    plots a histogram using the values $x_1$, $x_2$, ....
    >> Histogram[{3, 8, 10, 100, 1000, 500, 300, 200, 10, 20, 200, 100, 200, 300, 500}] @@ -1044,13 +1044,13 @@ class ListPlot(_ListPlot): """ :WMA link: https://reference.wolfram.com/language/ref/ListPlot.html
    -
    'ListPlot[{$y_1$, $y_2$, ...}]' +
    'ListPlot'[{$y_1$, $y_2$, ...}]
    plots a list of y-values, assuming integer x-values 1, 2, 3, ... -
    'ListPlot[{{$x_1$, $y_1$}, {$x_2$, $y_2$}, ...}]' +
    'ListPlot'[{{$x_1$, $y_1$}, {$x_2$, $y_2$}, ...}]
    plots a list of $x$, $y$ pairs. -
    'ListPlot[{$list_1$, $list_2$, ...}]' +
    'ListPlot'[{$list_1$, $list_2$, ...}]
    plots several lists of points.
    @@ -1058,7 +1058,7 @@ class ListPlot(_ListPlot): >> ListPlot[Prime[Range[30]]] = -Graphics- - seems very roughly to fit a table of quadradic numbers: + seems very roughly to fit a table of quadratic numbers: >> ListPlot[Table[n ^ 2 / 8, {n, 30}]] = -Graphics- @@ -1098,13 +1098,13 @@ class ListLinePlot(_ListPlot): :WMA link: https://reference.wolfram.com/language/ref/ListLinePlot.html
    -
    'ListLinePlot[{$y_1$, $y_2$, ...}]' +
    'ListLinePlot'[{$y_1$, $y_2$, ...}]
    plots a line through a list of $y$-values, assuming integer $x$-values 1, 2, 3, ... -
    'ListLinePlot[{{$x_1$, $y_1$}, {$x_2$, $y_2$}, ...}]' +
    'ListLinePlot'[{{$x_1$, $y_1$}, {$x_2$, $y_2$}, ...}]
    plots a line through a list of $x$, $y$ pairs. -
    'ListLinePlot[{$list_1$, $list_2$, ...}]' +
    'ListLinePlot'[{$list_1$, $list_2$, ...}]
    plots several lines.
    @@ -1140,13 +1140,13 @@ class ListStepPlot(_ListPlot): :WMA link: https://reference.wolfram.com/language/ref/ListStepPlot.html
    -
    'ListStepPlot[{$y_1$, $y_2$, ...}]' +
    'ListStepPlot'[{$y_1$, $y_2$, ...}]
    plots a line through a list of $y$-values, assuming integer $x$-values 1, 2, 3, ... -
    'ListStepPlot[{{$x_1$, $y_1$}, {$x_2$, $y_2$}, ...}]' +
    'ListStepPlot'[{{$x_1$, $y_1$}, {$x_2$, $y_2$}, ...}]
    plots a line through a list of $x$, $y$ pairs. -
    'ListStepPlot[{$list_1$, $list_2$, ...}]' +
    'ListStepPlot'[{$list_1$, $list_2$, ...}]
    plots several lines.
    @@ -1187,13 +1187,13 @@ class ListLogPlot(_ListPlot): """ :WMA link: https://reference.wolfram.com/language/ref/ListLogPlot.html
    -
    'ListLogPlot[{$y_1$, $y_2$, ...}]' +
    'ListLogPlot'[{$y_1$, $y_2$, ...}]
    log plots a list of y-values, assuming integer x-values 1, 2, 3, ... -
    'ListLogPlot[{{$x_1$, $y_1$}, {$x_2$, $y_2$}, ...}]' +
    'ListLogPlot'[{{$x_1$, $y_1$}, {$x_2$, $y_2$}, ...}]
    log plots a list of $x$, $y$ pairs. -
    'ListLogPlot[{$list_1$, $list_2$, ...}]' +
    'ListLogPlot'[{$list_1$, $list_2$, ...}]
    log plots several lists of points.
    @@ -1234,11 +1234,11 @@ class LogPlot(_Plot): :WMA link: https://reference.wolfram.com/language/ref/LogPlot.html)
    -
    'LogPlot[$f$, {$x$, $xmin$, $xmax$}]' -
    log plots $f$ with $x$ ranging from $xmin$ to $xmax$. +
    'LogPlot'[$f$, {$x$, $x_{min}$, $x_{max}$}] +
    log plots $f$ with $x$ ranging from $x_{min}$ to $x_{max}$. -
    'Plot[{$f1$, $f2$, ...}, {$x$, $xmin$, $xmax$}]' -
    log plots several functions $f1$, $f2$, ... +
    'Plot'[{$f_1$, $f_2$, ...}, {$x$, $x_{min}$, $x_{max}$}] +
    log plots several functions $f_1$, $f_2$, ...
    @@ -1260,7 +1260,7 @@ class NumberLinePlot(_ListPlot): :WMA link: https://reference.wolfram.com/language/ref/NumberLinePlot.html
    -
    'NumberLinePlot[{$v_1$, $v_2$, ...}]' +
    'NumberLinePlot'[{$v_1$, $v_2$, ...}]
    plots a list of values along a line.
    @@ -1312,8 +1312,8 @@ class PieChart(_Chart): :Pie Chart: https://en.wikipedia.org/wiki/Pie_chart \ (:WMA link: https://reference.wolfram.com/language/ref/PieChart.html)
    -
    'PieChart[{$a1$, $a2$ ...}]' -
    draws a pie chart with sector angles proportional to $a1$, $a2$, .... +
    'PieChart'[{$a_1$, $a_2$ ...}] +
    draws a pie chart with sector angles proportional to $a_1$, $a_2$, ....
    Drawing options include - @@ -1501,11 +1501,11 @@ class Plot(_Plot): """ :WMA link: https://reference.wolfram.com/language/ref/Plot.html
    -
    'Plot[$f$, {$x$, $xmin$, $xmax$}]' -
    plots $f$ with $x$ ranging from $xmin$ to $xmax$. +
    'Plot'[$f$, {$x$, $x_{min}$, $x_{max}$}] +
    plots $f$ with $x$ ranging from $x_{min}$ to $x_{max}$. -
    'Plot[{$f1$, $f2$, ...}, {$x$, $xmin$, $xmax$}]' -
    plots several functions $f1$, $f2$, ... +
    'Plot'[{$f_1$, $f_2$, ...}, {$x$, $x_{min}$, $x_{max}$}] +
    plots several functions $f_1$, $f_2$, ...
    @@ -1544,19 +1544,19 @@ def _apply_fn(self, f: Callable, x_value): class ParametricPlot(_Plot): """ - :WMA link - : https://reference.wolfram.com/language/ref/ParametricPlot.html + :WMA link:\ + https://reference.wolfram.com/language/ref/ParametricPlot.html
    -
    'ParametricPlot[{$f_x$, $f_y$}, {$u$, $umin$, $umax$}]' -
    plots a parametric function $f$ with the parameter $u$ ranging from $umin$ to $umax$. +
    'ParametricPlot'[{$f_x$, $f_y$}, {$u$, $u_{min}$, $u_{max}$}] +
    plots a parametric function $f$ with the parameter $u$ ranging from $u_{min}$ to $u_{max}$. -
    'ParametricPlot[{{$f_x$, $f_y$}, {$g_x$, $g_y$}, ...}, {$u$, $umin$, $umax$}]' +
    'ParametricPlot'[{{$f_x$, $f_y$}, {$g_x$, $g_y$}, ...}, {$u$, $u_{min}$, $u_{max}$}]
    plots several parametric functions $f$, $g$, ... -
    'ParametricPlot[{$f_x$, $f_y$}, {$u$, $umin$, $umax$}, {$v$, $vmin$, $vmax$}]' +
    'ParametricPlot'[{$f_x$, $f_y$}, {$u$, $u_{min}$, $u_{max}$}, {$v$, $v_{min}$, $v_{max}$}]
    plots a parametric area. -
    'ParametricPlot[{{$f_x$, $f_y$}, {$g_x$, $g_y$}, ...}, {$u$, $umin$, $umax$}, {$v$, $vmin$, $vmax$}]' +
    'ParametricPlot'[{{$f_x$, $f_y$}, {$g_x$, $g_y$}, ...}, {$u$, $u_{min}$, $u_{max}$}, {$v$, $v_{min}$, $v_{max}$}]
    plots several parametric areas.
    @@ -1614,9 +1614,9 @@ class PolarPlot(_Plot): """ :WMA link: https://reference.wolfram.com/language/ref/PolarPlot.html
    -
    'PolarPlot[$r$, {$t$, $t_min$, $t_max$}]' +
    'PolarPlot'[$r$, {$t$, $t_{min}$, $t_{max}$}]
    creates a polar plot of curve with radius $r$ as a function of angle $t$ \ - ranging from $t_min$ to $t_max$. + ranging from $t_{min}$ to $t_{max}$.
    In a Polar Plot, a :polar coordinate system: @@ -1692,9 +1692,9 @@ class Plot3D(_Plot3D): """ :WMA link: https://reference.wolfram.com/language/ref/Plot3D.html
    -
    'Plot3D[$f$, {$x$, $xmin$, $xmax$}, {$y$, $ymin$, $ymax$}]' -
    creates a three-dimensional plot of $f$ with $x$ ranging from $xmin$ to \ - $xmax$ and $y$ ranging from $ymin$ to $ymax$. +
    'Plot3D'[$f$, {$x$, $x_{min}$, $x_{max}$}, {$y$, $y_{min}$, $y_{max}$}] +
    creates a three-dimensional plot of $f$ with $x$ ranging from $x_{min}$ to \ + $x_{max}$ and $y$ ranging from $y_{min}$ to $y_{max}$. See :Drawing Option and Option Values: /doc/reference-of-built-in-symbols/graphics-and-drawing/drawing-options-and-option-values diff --git a/mathics/builtin/drawing/splines.py b/mathics/builtin/drawing/splines.py index 99281cac6..92fed08d1 100644 --- a/mathics/builtin/drawing/splines.py +++ b/mathics/builtin/drawing/splines.py @@ -26,7 +26,7 @@ class BernsteinBasis(Builtin): 'BernsteinBasis[d,n,x]' equals 'Binomial[d, n] x^n (1-x)^(d-n)' in the interval [0, 1] and zero elsewhere.
    -
    'BernsteinBasis[$d$,$n$,$x$]' +
    'BernsteinBasis'[$d$,$n$,$x$]
    returns the $n$th Bernstein basis of degree $d$ at $x$.
    @@ -46,7 +46,7 @@ class BezierFunction(Builtin): """ :WMA link:https://reference.wolfram.com/language/ref/BezierFunction.html
    -
    'BezierFunction[{$pt_1$, $pt_2$, ...}]' +
    'BezierFunction'[{$pt_1$, $pt_2$, ...}]
    returns a BĂŠzier function for the curve defined by points $pt_i$. The embedding dimension for the curve represented by 'BezierFunction[{$pt_1$,$pt_2$,...}]' is given by the length of the lists $pt_i$.
    @@ -78,7 +78,7 @@ class BezierCurve(Builtin): :WMA link:https://reference.wolfram.com/language/ref/BezierCurve.html
    -
    'BezierCurve[{$pt_1$, $pt_2$ ...}]' +
    'BezierCurve'[{$pt_1$, $pt_2$ ...}]
    represents a BĂŠzier curve with control points $p_i$.
    The result is a curve by combining the BĂŠzier curves when points are taken triples at a time.
    diff --git a/mathics/builtin/drawing/uniform_polyhedra.py b/mathics/builtin/drawing/uniform_polyhedra.py index fafa36b37..1cdab44a7 100644 --- a/mathics/builtin/drawing/uniform_polyhedra.py +++ b/mathics/builtin/drawing/uniform_polyhedra.py @@ -7,32 +7,70 @@ and regular star polyhedra. """ +from mathics.core.builtin import Builtin +from mathics.core.evaluation import Evaluation + # This tells documentation how to sort this module # Here we are also hiding "drawing" since this can erroneously appear at the top level. sort_order = "mathics.builtin.uniform-polyhedra" -from mathics.core.builtin import Builtin -from mathics.core.evaluation import Evaluation - -uniform_polyhedra_names = "tetrahedron, octahedron, dodecahedron, icosahedron" +uniform_polyhedra_names = "cube, tetrahedron, octahedron, dodecahedron, icosahedron" uniform_polyhedra_set = frozenset(uniform_polyhedra_names.split(", ")) +class Cube(Builtin): + """ + + :Cube: + https://en.wikipedia.org/wiki/Cube (:WMA: + https://reference.wolfram.com/language/ref/Cube.html) + +
    +
    'Cube[]' +
    represents a regular cube centered at the origin with unit edge length. + +
    'Cube'[$l$] +
    represents a cube centered at the origin with edge length $l$. + +
    'Cube'[{$x$, $y$, $z$}, ...] +
    represents a cube centered at {$x$ $y$, $z$}. +
    + + >> Graphics3D[Cube[]] + = -Graphics3D- + """ + + summary_text = "produce a cube" + rules = { + "Cube[]": """UniformPolyhedron["cube"]""", + "Cube[l_?NumberQ]": """UniformPolyhedron["cube", {{0, 0, 0}}, l]""", + "Cube[positions_List, l_?NumberQ]": """UniformPolyhedron["cube", positions, l]""", + } + + class Dodecahedron(Builtin): """ - :WMA link: - https://reference.wolfram.com/language/ref/Dodecahedron.html + + :Dodecahedron: + https://en.wikipedia.org/wiki/Dodecahedron (:WMA: + https://reference.wolfram.com/language/ref/Dodecahedron.html)
    'Dodecahedron[]'
    a regular dodecahedron centered at the origin with unit edge length. + +
    'Dodecahedron'[$l$] +
    a regular dodecahedron centered at the origin with edge length $l$. + +
    'Dodecahedron'[{$x$, $y$, $z$}, ...] +
    a regular dodecahedron centered at {$x$ $y$, $z$}.
    >> Graphics3D[Dodecahedron[]] = -Graphics3D- """ - summary_text = "a dodecahedron" + summary_text = "produce a dodecahedron" rules = { "Dodecahedron[]": """UniformPolyhedron["dodecahedron"]""", "Dodecahedron[l_?NumberQ]": """UniformPolyhedron["dodecahedron", {{0, 0, 0}}, l]""", @@ -42,12 +80,21 @@ class Dodecahedron(Builtin): class Icosahedron(Builtin): """ - :WMA link: - https://reference.wolfram.com/language/ref/Icosahedron.html + :Icosahedron: + https://en.wikipedia.org/wiki/Icosahedron (:WMA: + :WMA: + https://reference.wolfram.com/language/ref/Icosahedron.html)
    'Icosahedron[]'
    a regular Icosahedron centered at the origin with unit edge length. + +
    'Icosahedron'[$l$] +
    a regular icosahedron centered at the origin with edge length $l$. + +
    'Icosahedron'[{$x$, $y$, $z$}, ...] +
    a regular icosahedron centered at {$x$ $y$, $z$}. +
    >> Graphics3D[Icosahedron[]] @@ -59,17 +106,25 @@ class Icosahedron(Builtin): "Icosahedron[l_?NumberQ]": """UniformPolyhedron["icosahedron", {{0, 0, 0}}, l]""", "Icosahedron[positions_List, l_?NumberQ]": """UniformPolyhedron["icosahedron", positions, l]""", } - summary_text = "an icosahedron" + summary_text = "produce an icosahedron" class Octahedron(Builtin): """ - :WMA link - :https://reference.wolfram.com/language/ref/Octahedron.html + :Octahedron: + https://en.wikipedia.org/wiki/Octahedron (:WMA: + :https://reference.wolfram.com/language/ref/Octahedron.html)
    'Octahedron[]'
    a regular octahedron centered at the origin with unit edge length. + +
    'Octahedron[$l$]' +
    a regular octahedron centered at the origin with edge length $l$. + +
    'Octahedron[{$x$, $y$, $z$}, ...]' +
    a regular octahedron centered at {$x$ $y$, $z$}. +
    >> Graphics3D[{Red, Octahedron[]}] @@ -81,17 +136,26 @@ class Octahedron(Builtin): "Octahedron[l_?NumberQ]": """UniformPolyhedron["octahedron", {{0, 0, 0}}, l]""", "Octahedron[positions_List, l_?NumberQ]": """UniformPolyhedron["octahedron", positions, l]""", } - summary_text = "an octahedron" + summary_text = "produce an octahedron" class Tetrahedron(Builtin): """ - :WMA link - :https://reference.wolfram.com/language/ref/Tetrahedron.html + :Tetrahedron: + https://en.wikipedia.org/wiki/Tetrahedron ( + :WMA: + https://reference.wolfram.com/language/ref/Tetrahedron.html)
    'Tetrahedron[]'
    a regular tetrahedron centered at the origin with unit edge length. + +
    'Tetrahedron'[$l$] +
    a regular tetrahedron centered at the origin with edge length $l$. + +
    'Tetrahedron'[{$x$, $y$, $z$}, ...] +
    a regular tetrahedron centered at {$x$ $y$, $z$}. +
    >> Graphics3D[Tetrahedron[{{0,0,0}, {1,1,1}}, 2], Axes->True] @@ -103,7 +167,7 @@ class Tetrahedron(Builtin): "Tetrahedron[l_?NumberQ]": """UniformPolyhedron["tetrahedron", {{0, 0, 0}}, l]""", "Tetrahedron[positions_List, l_?NumberQ]": """UniformPolyhedron["tetrahedron", positions, l]""", } - summary_text = "a tetrahedron" + summary_text = "produce a tetrahedron" def eval_with_length(self, length, evaluation: Evaluation): "Tetrahedron[l_?Numeric]" @@ -111,13 +175,14 @@ def eval_with_length(self, length, evaluation: Evaluation): class UniformPolyhedron(Builtin): """ - :WMA link: - https://reference.wolfram.com/language/ref/UniformPolyhedron.html + :Uniform polyhedron: + https://en.wikipedia.org/wiki/Uniform_polyhedron (:WMA link: + https://reference.wolfram.com/language/ref/UniformPolyhedron.html)
    -
    'UniformPolyhedron["name"]' +
    'UniformPolyhedron'["$name$"]
    return a uniform polyhedron with the given name. -
    Names are "tetrahedron", "octahedron", "dodecahedron", or "icosahedron". +
    Names are "$tetrahedron$", "$octahedron$", "$dodecahedron$", or "$icosahedron$".
    >> Graphics3D[UniformPolyhedron["octahedron"]] @@ -137,7 +202,7 @@ class UniformPolyhedron(Builtin): rules = { "UniformPolyhedron[name_String]": "UniformPolyhedron[name, {{0, 0, 0}}, 1]", } - summary_text = "platonic polyhedra by name" + summary_text = "produce platonic polyhedra by name" def eval(self, name, positions, edgelength, evaluation: Evaluation): "UniformPolyhedron[name_String, positions_List, edgelength_?NumberQ]" diff --git a/mathics/builtin/evaluation.py b/mathics/builtin/evaluation.py index 80d96bd60..b1e7c0cb3 100644 --- a/mathics/builtin/evaluation.py +++ b/mathics/builtin/evaluation.py @@ -14,18 +14,18 @@ class RecursionLimit(Predefined): - """ + r""" :WMA link: - https://reference.wolfram.com/language/ref/$RecursionLimit.html + https://reference.wolfram.com/language/ref/\$RecursionLimit.html
    -
    '$RecursionLimit' +
    '\$RecursionLimit'
    specifies the maximum allowable recursion depth after which a \ calculation is terminated.
    - Calculations terminated by '$RecursionLimit' return '$Aborted': + Calculations terminated by '\$RecursionLimit' return '\$Aborted': >> a = a + a : Recursion depth of 200 exceeded. = $Aborted @@ -71,17 +71,17 @@ def evaluate(self, evaluation) -> Integer: class IterationLimit(Predefined): - """ - :WMA link:https://reference.wolfram.com/language/ref/$IterationLimit.html + r""" + :WMA link:https://reference.wolfram.com/language/ref/\$IterationLimit.html
    -
    '$IterationLimit' +
    '\$IterationLimit'
    specifies the maximum number of times a reevaluation of an expression may happen.
    - Calculations terminated by '$IterationLimit' return '$Aborted': + Calculations terminated by '\$IterationLimit' return '\$Aborted': >> $IterationLimit = 1000 @@ -116,7 +116,7 @@ class Hold(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Hold.html
    -
    'Hold[$expr$]' +
    'Hold'[$expr$]
    prevents $expr$ from being evaluated.
    @@ -133,7 +133,7 @@ class HoldComplete(Builtin): :WMA link:https://reference.wolfram.com/language/ref/HoldComplete.html
    -
    'HoldComplete[$expr$]' +
    'HoldComplete'[$expr$]
    prevents $expr$ from being evaluated, and also prevents \ 'Sequence' objects from being spliced into argument lists.
    @@ -151,7 +151,7 @@ class HoldForm(Builtin): :WMA link:https://reference.wolfram.com/language/ref/HoldForm.html
    -
    'HoldForm[$expr$]' +
    'HoldForm'[$expr$]
    is equivalent to 'Hold[$expr$]', but prints as $expr$.
    @@ -176,7 +176,7 @@ class Evaluate(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Evaluate.html
    -
    'Evaluate[$expr$]' +
    'Evaluate'[$expr$]
    forces evaluation of $expr$, even if it occurs inside a held argument or a 'Hold' form.
    @@ -211,7 +211,7 @@ class Unevaluated(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Unevaluated.html
    -
    'Unevaluated[$expr$]' +
    'Unevaluated'[$expr$]
    temporarily leaves $expr$ in an unevaluated form when it appears as a function argument.
    @@ -251,7 +251,7 @@ class ReleaseHold(Builtin): :WMA link:https://reference.wolfram.com/language/ref/ReleaseHold.html
    -
    'ReleaseHold[$expr$]' +
    'ReleaseHold'[$expr$]
    removes any 'Hold', 'HoldForm', 'HoldPattern' or 'HoldComplete' head from $expr$.
    @@ -277,7 +277,7 @@ class Sequence(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Sequence.html
    -
    'Sequence[$x1$, $x2$, ...]' +
    'Sequence'[$x_1$, $x_2$, ...]
    represents a sequence of arguments to a function.
    diff --git a/mathics/builtin/exp_structure/general.py b/mathics/builtin/exp_structure/general.py index b1462f492..c1f42f5c4 100644 --- a/mathics/builtin/exp_structure/general.py +++ b/mathics/builtin/exp_structure/general.py @@ -21,7 +21,7 @@ class MapApply(InfixOperator): https://reference.wolfram.com/language/ref/MapApply.html
    -
    'MapApply[$f$, $expr$]' +
    'MapApply'[$f$, $expr$]
    '$f$ @@@ $expr$'
    is equivalent to 'Apply[$f$, $expr$, {1}]'. @@ -45,7 +45,7 @@ class Depth(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Depth.html
    -
    'Depth[$expr$]' +
    'Depth'[$expr$]
    gives the depth of $expr$.
    @@ -84,7 +84,7 @@ class FreeQ(Builtin): https://reference.wolfram.com/language/ref/FreeQ.html
    -
    'FreeQ[$expr$, $x$]' +
    'FreeQ'[$expr$, $x$]
    returns 'True' if $expr$ does not contain the expression $x$.
    @@ -127,7 +127,7 @@ class Level(Builtin): https://reference.wolfram.com/language/ref/Level.html
    -
    'Level[$expr$, $levelspec$]' +
    'Level'[$expr$, $levelspec$]
    gives a list of all subexpressions of $expr$ at the level(s) specified by $levelspec$.
    @@ -232,14 +232,14 @@ class SortBy(Builtin): https://reference.wolfram.com/language/ref/SortBy.html
    -
    'SortBy[$list$, $f$]' +
    'SortBy'[$list$, $f$]
    sorts $list$ (or the elements of any other expression) according to \ canonical ordering of the keys that are extracted from the $list$'s \ - elements using $f. Chunks of elements that appear the same under $f \ - are sorted according to their natural order (without applying $f). + elements using $f$. Chunks of elements that appear the same under $f$ \ + are sorted according to their natural order (without applying $f$). -
    'SortBy[$f$]' -
    creates an operator function that, when applied, sorts by $f. +
    'SortBy'[$f$] +
    creates an operator function that, when applied, sorts by $f$.
    >> SortBy[{{5, 1}, {10, -1}}, Last] diff --git a/mathics/builtin/exp_structure/head_related.py b/mathics/builtin/exp_structure/head_related.py index 740da2725..ba3b71208 100644 --- a/mathics/builtin/exp_structure/head_related.py +++ b/mathics/builtin/exp_structure/head_related.py @@ -15,10 +15,10 @@ class Operate(Builtin): https://reference.wolfram.com/language/ref/Operate.html
    -
    'Operate[$p$, $expr$]' +
    'Operate'[$p$, $expr$]
    applies $p$ to the head of $expr$. -
    'Operate[$p$, $expr$, $n$]' +
    'Operate'[$p$, $expr$, $n$]
    applies $p$ to the $n$th head of $expr$.
    @@ -81,7 +81,7 @@ class Through(Builtin): https://reference.wolfram.com/language/ref/Through.html
    -
    'Through[$p$[$f$][$x$]]' +
    'Through'[$p$[$f$][$x$]]
    gives $p$[$f$[$x$]].
    diff --git a/mathics/builtin/exp_structure/size_and_sig.py b/mathics/builtin/exp_structure/size_and_sig.py index f0538933c..0d6babb9f 100644 --- a/mathics/builtin/exp_structure/size_and_sig.py +++ b/mathics/builtin/exp_structure/size_and_sig.py @@ -43,7 +43,7 @@ class ByteCount(Builtin): https://reference.wolfram.com/language/ref/ByteCount.html
    -
    'ByteCount[$expr$]' +
    'ByteCount'[$expr$]
    gives the internal memory space used by $expr$, in bytes.
    @@ -66,15 +66,15 @@ class Hash(Builtin): (:WMA link:https://reference.wolfram.com/language/ref/Hash.html)
    -
    'Hash[$expr$]' +
    'Hash'[$expr$]
    returns an integer hash for the given $expr$. -
    'Hash[$expr$, $type$]' +
    'Hash'[$expr$, $type$]
    returns an integer hash of the specified $type$ for the given $expr$.
    The types supported are "MD5", "Adler32", "CRC32", "SHA", "SHA224", \ "SHA256", "SHA384", and "SHA512". -
    'Hash[$expr$, $type$, $format$]' +
    'Hash'[$expr$, $type$, $format$]
    Returns the hash in the specified format.
    @@ -147,7 +147,7 @@ class LeafCount(Builtin): https://reference.wolfram.com/language/ref/LeafCount.html
    -
    'LeafCount[$expr$]' +
    'LeafCount'[$expr$]
    returns the total number of indivisible subexpressions in $expr$.
    diff --git a/mathics/builtin/file_operations/file_properties.py b/mathics/builtin/file_operations/file_properties.py index 3451c6088..74c340704 100644 --- a/mathics/builtin/file_operations/file_properties.py +++ b/mathics/builtin/file_operations/file_properties.py @@ -4,21 +4,18 @@ import os import os.path as osp -import time +from datetime import datetime from mathics.builtin.exp_structure.size_and_sig import Hash from mathics.builtin.files_io.files import MathicsOpen -from mathics.core.atoms import Real, String +from mathics.core.atoms import String from mathics.core.attributes import A_PROTECTED, A_READ_PROTECTED from mathics.core.builtin import Builtin, MessageException from mathics.core.convert.expression import to_expression -from mathics.core.convert.python import from_python from mathics.core.evaluation import Evaluation -from mathics.core.expression import Expression from mathics.core.streams import path_search from mathics.core.symbols import Symbol, SymbolNull -from mathics.core.systemsymbols import SymbolAbsoluteTime, SymbolFailed, SymbolNone -from mathics.eval.nevaluator import eval_N +from mathics.core.systemsymbols import SymbolFailed, SymbolNone sort_order = "mathics.builtin.file-operations.file_properties" @@ -29,7 +26,7 @@ class FileDate(Builtin): :WMA link:https://reference.wolfram.com/language/ref/FileDate.html
    -
    'FileDate[$file$, $types$]' +
    'FileDate'[$file$, $types$]
    returns the time and date at which the file was last modified.
    @@ -103,17 +100,17 @@ def eval(self, path, timetype, evaluation): evaluation.message("FileDate", "datetype") return - # Offset for system epoch - epochtime_expr = Expression( - SymbolAbsoluteTime, String(time.strftime("%Y-%m-%d %H:%M", time.gmtime(0))) + dt_object = datetime.fromtimestamp(result) + # Extract the year, month, day, hour, and minute into a tuple + datetime_tuple = ( + dt_object.year, + dt_object.month, + dt_object.day, + dt_object.hour, + dt_object.minute, + dt_object.second, ) - epochtime_N = eval_N(epochtime_expr, evaluation) - if epochtime_N is None: - return None - epochtime = epochtime_N.to_python() - result += epochtime - - return to_expression("DateList", Real(result)) + return to_expression("DateList", datetime_tuple) def eval_default(self, path, evaluation): "FileDate[path_]" @@ -126,15 +123,15 @@ class FileHash(Builtin): https://reference.wolfram.com/language/ref/FileHash.html
    -
    'FileHash[$file$]' +
    'FileHash'[$file$]
    returns an integer hash for the given $file$. -
    'FileHash[$file$, $type$]' +
    'FileHash'[$file$, $type$]
    returns an integer hash of the specified $type$ for the given $file$.
    The types supported are "MD5", "Adler32", "CRC32", "SHA", "SHA224", "SHA256", \ "SHA384", and "SHA512". -
    'FileHash[$file$, $type$, $format$]' +
    'FileHash'[$file$, $type$, $format$]
    gives a hash code in the specified format.
    @@ -186,7 +183,7 @@ class FileType(Builtin): https://reference.wolfram.com/language/ref/FileType.html
    -
    'FileType["$file$"]' +
    'FileType'["$file$"]
    gives the type of a file, a string. This is typically 'File', 'Directory' \ or 'None'.
    @@ -229,11 +226,11 @@ class SetFileDate(Builtin): :WMA link:https://reference.wolfram.com/language/ref/SetFileDate.html
    -
    'SetFileDate["$file$"]' +
    'SetFileDate'["$file$"]
    set the file access and modification dates of $file$ to the current date. -
    'SetFileDate["$file$", $date$]' +
    'SetFileDate'["$file$", $date$]
    set the file access and modification dates of $file$ to the specified date list. -
    'SetFileDate["$file$", $date$, "$type$"]' +
    'SetFileDate'["$file$", $date$, "$type$"]
    set the file date of $file$ to the specified date list. The "$type$" can be one of "$Access$", "$Creation$", "$Modification$", or 'All'.
    @@ -299,7 +296,7 @@ def eval(self, filename, datelist, attribute, evaluation): # Check datelist if not ( - isinstance(py_datelist, list) + isinstance(py_datelist, (list, tuple)) and len(py_datelist) == 6 and all(isinstance(d, int) for d in py_datelist[:-1]) and isinstance(py_datelist[-1], float) @@ -311,25 +308,13 @@ def eval(self, filename, datelist, attribute, evaluation): evaluation.message("SetFileDate", "datetype") return - epochtime = ( - to_expression( - "AbsoluteTime", time.strftime("%Y-%m-%d %H:%M", time.gmtime(0)) - ) - .evaluate(evaluation) - .to_python() - ) - - stattime = to_expression("AbsoluteTime", from_python(py_datelist)) - stattime_N = eval_N(stattime, evaluation) - if stattime_N is None: - return - - stattime = stattime_N.to_python() - epochtime + file_timestamp = datetime(*py_datelist[:4]).timestamp() try: os.stat(py_filename) if py_attr == '"Access"': - os.utime(py_filename, (stattime, osp.getatime(py_filename))) + os.utime(py_filename, (file_timestamp, osp.getatime(py_filename))) + return SymbolNull if py_attr == '"Creation"': if os.name == "posix": evaluation.message("SetFileDate", "nocreationunix") @@ -338,9 +323,9 @@ def eval(self, filename, datelist, attribute, evaluation): # TODO: Note: This is windows only return SymbolFailed if py_attr == '"Modification"': - os.utime(py_filename, (osp.getatime(py_filename), stattime)) - if py_attr == "All": - os.utime(py_filename, (stattime, stattime)) + os.utime(py_filename, (osp.getatime(py_filename), file_timestamp)) + elif py_attr == "All": + os.utime(py_filename, (file_timestamp, file_timestamp)) except OSError: # evaluation.message(...) return SymbolFailed diff --git a/mathics/builtin/file_operations/file_utilities.py b/mathics/builtin/file_operations/file_utilities.py index dd19c17c8..fa7bfc03b 100644 --- a/mathics/builtin/file_operations/file_utilities.py +++ b/mathics/builtin/file_operations/file_utilities.py @@ -17,14 +17,14 @@ class FindList(Builtin): :WMA link:https://reference.wolfram.com/language/ref/FindList.html
    -
    'FindList[$file$, $text$]' +
    'FindList'[$file$, $text$]
    returns a list of all lines in $file$ that contain $text$. -
    'FindList[$file$, {$text1$, $text2$, ...}]' +
    'FindList'[$file$, {$text_1$, $text_2$, ...}]
    returns a list of all lines in $file$ that contain any of the specified \ string. -
    'FindList[{$file1$, $file2$, ...}, ...]' +
    'FindList'[{$file_1$, $file_2$, ...}, ...]
    returns a list of all lines in any of the $filei$ that contain the specified \ strings.
    diff --git a/mathics/builtin/file_operations/path_operations.py b/mathics/builtin/file_operations/path_operations.py index f9f2b265d..5fbc32963 100644 --- a/mathics/builtin/file_operations/path_operations.py +++ b/mathics/builtin/file_operations/path_operations.py @@ -21,16 +21,16 @@ class FileNameDrop(Builtin): https://reference.wolfram.com/language/ref/FileNameDrop.html
    -
    'FileNameDrop["$path$", $n$]' +
    'FileNameDrop'["$path$", $n$]
    drops the first $n$ path elements in the file name $path$. -
    'FileNameDrop["$path$", -$n$]' +
    'FileNameDrop'["$path$", -$n$]
    drops the last $n$ path elements in the file name $path$. -
    'FileNameDrop["$path$", {$m$, $n$}]' +
    'FileNameDrop'["$path$", {$m$, $n$}]
    drops elements $m$ through $n$ path elements in the file name $path$. -
    'FileNameDrop["$path$"]' +
    'FileNameDrop'["$path$"]
    drops the last path elements in the file name $path$.
    diff --git a/mathics/builtin/fileformats/xmlformat.py b/mathics/builtin/fileformats/xmlformat.py index a93dfb39c..d5a2dd758 100644 --- a/mathics/builtin/fileformats/xmlformat.py +++ b/mathics/builtin/fileformats/xmlformat.py @@ -246,7 +246,7 @@ class XMLElement(Builtin): :WMA link:https://reference.wolfram.com/language/ref/XMLElement.html
    -
    'XMLElement[$tag$, {$attr_1$, $val_1$, ...}, {$data$, ...}]' +
    'XMLElement'[$tag$, {$attr_1$, $val_1$, ...}, {$data$, ...}]
    represents an element in symbolic XML.
    """ diff --git a/mathics/builtin/files_io/files.py b/mathics/builtin/files_io/files.py index c45f6c49d..a14da432d 100644 --- a/mathics/builtin/files_io/files.py +++ b/mathics/builtin/files_io/files.py @@ -40,7 +40,7 @@ SymbolOutputStream, ) from mathics.eval.directories import TMP_DIR -from mathics.eval.files_io.files import eval_Close, eval_Get, eval_Read +from mathics.eval.files_io.files import eval_Close, eval_Get, eval_Open, eval_Read from mathics.eval.files_io.read import ( MathicsOpen, channel_to_stream, @@ -52,11 +52,11 @@ class Input_(Predefined): - """ - :WMA link:https://reference.wolfram.com/language/ref/$Input.html + r""" + :WMA link:https://reference.wolfram.com/language/ref/\$Input.html
    -
    '$Input' +
    '\$Input'
    is the name of the stream from which input is currently being read.
    @@ -95,6 +95,7 @@ class _OpenAction(Builtin): } mode = "r" # A default; this is changed in subclassing. + stream_type = "unknown" def eval_empty(self, evaluation: Evaluation, options: dict): "%(name)s[OptionsPattern[]]" @@ -119,48 +120,23 @@ def eval_name(self, name, evaluation: Evaluation, options: dict): # Options # BinaryFormat - mode = self.mode - if options["System`BinaryFormat"] is SymbolTrue: - if not self.mode.endswith("b"): - mode += "b" - if not (isinstance(name, String) and len(name.to_python()) > 2): evaluation.message(self.__class__.__name__, "fstr", name) return - name_string = name.get_string_value() + mode = self.mode - tmp, is_temporary_file = path_search(name_string) - if tmp is None: - if mode in ["r", "rb"]: - evaluation.message("General", "noopen", name) - return - path_string = name_string - else: - path_string = tmp + if options.get("System`BinaryFormat") is SymbolTrue: + if not mode.endswith("b"): + mode += "b" - try: - encoding = self.get_option(options, "CharacterEncoding", evaluation) - if not isinstance(encoding, String): - return + stream_type = self.stream_type - opener = MathicsOpen( - path_string, - mode=mode, - name=name_string, - encoding=encoding.value, - is_temporary_file=is_temporary_file, - ) - opener.__enter__(is_temporary_file=is_temporary_file) - n = opener.n - except IOError: - evaluation.message("General", "noopen", name) - return - except MessageException as e: - e.message(evaluation) + encoding = self.get_option(options, "CharacterEncoding", evaluation) + if not isinstance(encoding, String): return - return Expression(Symbol(self.stream_type), name, Integer(n)) + return eval_Open(name, mode, stream_type, encoding.value, evaluation) class Character(Builtin): @@ -185,7 +161,7 @@ class Close(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Close.html
    -
    'Close[$obj$]' +
    'Close'[$obj$]
    Closes a stream or socket. $obj$ can be an 'InputStream', or an 'OutputStream' object, or a 'String'. \ @@ -284,16 +260,15 @@ class FilePrint(Builtin): :WMA link:https://reference.wolfram.com/language/ref/FilePrint.html
    -
    'FilePrint[$file$]' +
    'FilePrint'[$file$]
    prints the raw contents of $file$.
    """ messages = { - "fstr": ( - "File specification `1` is not a string of " "one or more characters." - ), + "zstr": ("The file name cannot be an empty string."), + "badfile": ("The specified argument, `1`, should be a valid string."), } options = { @@ -305,33 +280,35 @@ class FilePrint(Builtin): def eval(self, path, evaluation: Evaluation, options: dict): "FilePrint[path_, OptionsPattern[FilePrint]]" + + if not isinstance(path, String): + evaluation.message("FilePrint", "badfile", path) + return + pypath = path.to_python() + if not ( isinstance(pypath, str) and pypath[0] == pypath[-1] == '"' and len(pypath) > 2 ): - evaluation.message("FilePrint", "fstr", path) + evaluation.message("FilePrint", "zstr", path) return - pypath, _ = path_search(pypath[1:-1]) + resolved_pypath, _ = path_search(pypath[1:-1]) # Options record_separators = options["System`RecordSeparators"].to_python() - assert isinstance(record_separators, list) - assert all( - isinstance(s, str) and s[0] == s[-1] == '"' for s in record_separators - ) - record_separators = [s[1:-1] for s in record_separators] + assert isinstance(record_separators, tuple) - if pypath is None: + if resolved_pypath is None: evaluation.message("General", "noopen", path) return - if not osp.isfile(pypath): + if not osp.isfile(resolved_pypath): return SymbolFailed try: - with MathicsOpen(pypath, "r") as f: + with MathicsOpen(resolved_pypath, "r") as f: result = f.read() except IOError: evaluation.message("General", "noopen", path) @@ -361,10 +338,10 @@ class Get(PrefixOperator):
    '<<$name$'
    reads a file and evaluates each expression, returning only the last one. -
    'Get[$name$, Trace->True]' +
    'Get'[$name$, Trace->True]
    Runs Get tracing each line before it is evaluated. - 'Settings`$TraceGet' can be also used to trace lines on all 'Get[]' calls. + 'Settings`\$TraceGet' can be also used to trace lines on all 'Get[]' calls.
    @@ -409,17 +386,17 @@ def eval(self, path: String, evaluation: Evaluation, options: dict): class InputFileName_(Predefined): - """ + r""" :WMA link: - https://reference.wolfram.com/language/ref/$InputFileName.html + https://reference.wolfram.com/language/ref/\$InputFileName.html
    -
    '$InputFileName' +
    '\$InputFileName'
    is the name of the file from which input is currently being read.
    - While in interactive mode, '$InputFileName' is "". + While in interactive mode, '\$InputFileName' is "". X> $InputFileName """ @@ -437,7 +414,7 @@ class InputStream(Builtin): :WMA link:https://reference.wolfram.com/language/ref/InputStream.html
    -
    'InputStream[$name$, $n$]' +
    'InputStream'[$name$, $n$]
    represents an input stream for functions such as 'Read' or 'Find'.
    @@ -542,7 +519,7 @@ class Put(InfixOperator):
    '$expr$ >> $filename$'
    write $expr$ to a file. -
    'Put[$expr1$, $expr2$, ..., $filename$]' +
    'Put'[$expr_1$, $expr_2$, ..., "$filename$"]
    write a sequence of expressions to a file.
    @@ -648,7 +625,7 @@ class PutAppend(InfixOperator):
    '$expr$ >>> $filename$'
    append $expr$ to a file. -
    'PutAppend[$expr1$, $expr2$, ..., $"filename"$]' +
    'PutAppend'[$expr_1$, $expr_2$, ..., "$filename$"]
    write a sequence of expressions to a file.
    @@ -766,13 +743,13 @@ class Read(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Read.html
    -
    'Read[$stream$]' +
    'Read'[$stream$]
    reads the input stream and returns one expression. -
    'Read[$stream$, $type$]' +
    'Read'[$stream$, $type$]
    reads the input stream and returns an object of the given type. -
    'Read[$stream$, $type$]' +
    'Read'[$stream$, $type$]
    reads the input stream and returns an object of the given type.
    'Read[$stream$, Hold[Expression]]' @@ -937,13 +914,13 @@ class ReadList(Read): https://reference.wolfram.com/language/ref/ReadList.html
    -
    'ReadList["$file$"]' +
    'ReadList'["$file$"]
    Reads all the expressions until the end of file. -
    'ReadList["$file$", $type$]' +
    'ReadList'["$file$", $type$]
    Reads objects of a specified type until the end of file. -
    'ReadList["$file$", {$type1$, $type2$, ...}]' +
    'ReadList'["$file$", {$type_1$, $type_2$, ...}]
    Reads a sequence of specified types until the end of file.
    @@ -1002,7 +979,7 @@ class ReadList(Read): See :RecordSeparators: https://reference.wolfram.com/language/ref/RecordSeprators.html \ - works analgously for records as 'WordSeparators' does for words. + works analogously for records as 'WordSeparators' does for words. To allow both periods and newlines as record separators: @@ -1126,7 +1103,7 @@ def eval_n(self, file, types, n: Integer, evaluation: Evaluation, options: dict) py_n = n.get_int_value() if py_n < 0: evaluation.message( - "ReadList", "intnm", to_expression("ReadList", file, types, m) + "ReadList", "intnm", to_expression("ReadList", file, types, n) ) return @@ -1150,7 +1127,7 @@ class StreamPosition(Builtin): https://reference.wolfram.com/language/ref/StreamPosition.html
    -
    'StreamPosition[$stream$]' +
    'StreamPosition'[$stream$]
    returns the current position in a stream as an integer.
    @@ -1193,7 +1170,7 @@ class SetStreamPosition(Builtin): https://reference.wolfram.com/language/ref/SetStreamPosition.html
    -
    'SetStreamPosition[$stream$, $n$]' +
    'SetStreamPosition'[$stream$, $n$]
    sets the current position in a stream.
    @@ -1273,10 +1250,10 @@ class Skip(Read): https://reference.wolfram.com/language/ref/Skip.html
    -
    'Skip[$stream$, $type$]' +
    'Skip'[$stream$, $type$]
    skips ahead in an input steream by one object of the specified $type$. -
    'Skip[$stream$, $type$, $n$]' +
    'Skip'[$stream$, $type$, $n$]
    skips ahead in an input steream by $n$ objects of the specified $type$.
    @@ -1350,7 +1327,7 @@ class Find(Read): :WMA link:https://reference.wolfram.com/language/ref/Find.html
    -
    'Find[$stream$, $text$]' +
    'Find'[$stream$, $text$]
    find the first line in $stream$ that contains $text$.
    @@ -1398,18 +1375,26 @@ def eval(self, name, n, text, evaluation: Evaluation, options: dict): stream = to_expression("InputStream", name, n) - if not isinstance(py_text, list): + if not isinstance(py_text, (list, tuple)): py_text = [py_text] - if not all(isinstance(t, str) and t[0] == t[-1] == '"' for t in py_text): + if not all(isinstance(t, str) for t in py_text): evaluation.message("Find", "unknown", to_expression("Find", stream, text)) return - py_text = [t[1:-1] for t in py_text] + # If py_text comes from a (literal) value, then there are no + # leading/trailing quotes around strings. If it is still + # possible that py_text can be a list, then there could be + # leading/traling quotes. + if isinstance(py_text, list): + py_text = [t[1:-1] if t[0] == t[-1] == '"' else t for t in py_text] while True: tmp = super(Find, self).eval(stream, Symbol("Record"), evaluation, options) - py_tmp = tmp.to_python()[1:-1] + if not isinstance(tmp, String): + return SymbolFailed + + py_tmp = tmp.value if py_tmp == "System`EndOfFile": evaluation.message( @@ -1429,7 +1414,7 @@ class OutputStream(Builtin): https://reference.wolfram.com/language/ref/OutputStream.html
    -
    'OutputStream[$name$, $n$]' +
    'OutputStream'[$name$, $n$]
    represents an output stream.
    @@ -1448,7 +1433,7 @@ class StringToStream(Builtin): https://reference.wolfram.com/language/ref/StringToStream.html
    -
    'StringToStream[$string$]' +
    'StringToStream'[$string$]
    converts a $string$ to an open input stream.
    @@ -1548,7 +1533,7 @@ class Write(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Write.html
    -
    'Write[$channel$, $expr1$, $expr2$, ...]' +
    'Write'[$channel$, $expr_1$, $expr_2$, ...]
    writes the expressions to the output channel followed by a newline.
    @@ -1599,7 +1584,7 @@ class WriteString(Builtin): https://reference.wolfram.com/language/ref/WriteString.html
    -
    'WriteString[$stream$, $str1, $str2$, ... ]' +
    'WriteString'[$stream$, $str_1$, $str_2$, ... ]
    writes the strings to the output stream.
    diff --git a/mathics/builtin/files_io/filesystem.py b/mathics/builtin/files_io/filesystem.py index bfc31ba5f..503becbcf 100644 --- a/mathics/builtin/files_io/filesystem.py +++ b/mathics/builtin/files_io/filesystem.py @@ -30,7 +30,6 @@ ) from mathics.core.systemsymbols import ( SymbolFailed, - SymbolGet, SymbolMemberQ, SymbolNeeds, SymbolPackages, @@ -47,7 +46,7 @@ class AbsoluteFileName(Builtin): https://reference.wolfram.com/language/ref/AbsoluteFileName.html
    -
    'AbsoluteFileName["$name$"]' +
    'AbsoluteFileName'["$name$"]
    returns the absolute version of the given filename.
    @@ -67,10 +66,12 @@ def eval(self, name, evaluation): py_name = name.to_python() - if not (isinstance(py_name, str) and py_name[0] == py_name[-1] == '"'): + if not isinstance(py_name, str): evaluation.message("AbsoluteFileName", "fstr", name) return - py_name = py_name[1:-1] + + if py_name[0] == py_name[-1] == '"': + py_name = py_name[1:-1] result, _ = path_search(py_name) @@ -89,8 +90,8 @@ class CopyDirectory(Builtin): https://reference.wolfram.com/language/ref/CopyDirectory.html
    -
    'CopyDirectory["$dir1$", "$dir2$"]' -
    copies directory $dir1$ to $dir2$. +
    'CopyDirectory'["$dir_1$", "$dir_2$"] +
    copies directory $dir_1$ to $dir_2$.
    """ @@ -110,7 +111,7 @@ def eval(self, dirs, evaluation): if len(seq) != 2: evaluation.message("CopyDirectory", "argr", "CopyDirectory", 2) return - (dir1, dir2) = (s.to_python() for s in seq) + dir1, dir2 = (s.to_python() for s in seq) if not (isinstance(dir1, str) and dir1[0] == dir1[-1] == '"'): evaluation.message("CopyDirectory", "fstr", seq[0]) @@ -140,8 +141,8 @@ class CopyFile(Builtin): https://reference.wolfram.com/language/ref/CopyFile.html
    -
    'CopyFile["$file1$", "$file2$"]' -
    copies $file1$ to $file2$. +
    'CopyFile'["$file_1$", "$file_2$"] +
    copies $file_1$ to $file_2$.
    X> CopyFile["ExampleData/sunflowers.jpg", "MathicsSunflowers.jpg"] @@ -165,15 +166,18 @@ def eval(self, source, dest, evaluation): py_dest = dest.to_python() # Check filenames - if not (isinstance(py_source, str) and py_source[0] == py_source[-1] == '"'): + if not (isinstance(py_source, str)): evaluation.message("CopyFile", "fstr", source) return - if not (isinstance(py_dest, str) and py_dest[0] == py_dest[-1] == '"'): + if not (isinstance(py_dest, str)): evaluation.message("CopyFile", "fstr", dest) return - py_source = py_source[1:-1] - py_dest = py_dest[1:-1] + if py_source[0] == py_source[-1] == '"': + py_source = py_source[1:-1] + + if py_dest[0] == py_dest[-1] == '"': + py_dest = py_dest[1:-1] py_source, _ = path_search(py_source) @@ -263,10 +267,10 @@ class DeleteFile(Builtin): https://reference.wolfram.com/language/ref/DeleteFile.html
    -
    'Delete["$file$"]' +
    'Delete'["$file$"]
    deletes $file$. -
    'Delete[{"$file1$", "$file2$", ...}]' +
    'Delete'[{"$file_1$", "$file_2$", ...}]
    deletes a list of files.
    @@ -291,13 +295,13 @@ def eval(self, filename, evaluation): "DeleteFile[filename_]" py_path = filename.to_python() - if not isinstance(py_path, list): + if not isinstance(py_path, (list, tuple)): py_path = [py_path] py_paths = [] for path in py_path: # Check filenames - if not (isinstance(path, str) and path[0] == path[-1] == '"'): + if not isinstance(path, str): evaluation.message( "DeleteFile", "strs", @@ -306,7 +310,8 @@ def eval(self, filename, evaluation): ) return - path = path[1:-1] + if path[0] == path[-1] == '"': + path = path[1:-1] path, _ = path_search(path) if path is None: @@ -373,7 +378,7 @@ class ExpandFileName(Builtin): :WMA link:https://reference.wolfram.com/language/ref/ExpandFileName.html
    -
    'ExpandFileName["$name$"]' +
    'ExpandFileName'["$name$"]
    expands $name$ to an absolute filename for your system.
    @@ -408,7 +413,7 @@ class File(Builtin): https://reference.wolfram.com/language/ref/File.html
    -
    'File["$file$"]' +
    'File'["$file$"]
    is a symbolic representation of an element in the local file system.
    """ @@ -423,7 +428,7 @@ class FileBaseName(Builtin): https://reference.wolfram.com/language/ref/FileBaseName.html
    -
    'FileBaseName["$file$"]' +
    'FileBaseName'["$file$"]
    gives the base name for the specified file name.
    @@ -452,7 +457,7 @@ class FileByteCount(Builtin): :WMA link:https://reference.wolfram.com/language/ref/FileByteCount.html
    -
    'FileByteCount[$file$]' +
    'FileByteCount'[$file$]
    returns the number of bytes in $file$.
    @@ -498,7 +503,7 @@ class FileExistsQ(Builtin): :WMA link:https://reference.wolfram.com/language/ref/FileExistsQ.html
    -
    'FileExistsQ["$file$"]' +
    'FileExistsQ'["$file$"]
    returns 'True' if $file$ exists and 'False' otherwise.
    @@ -536,7 +541,7 @@ class FileExtension(Builtin): https://reference.wolfram.com/language/ref/FileExtension.html
    -
    'FileExtension["$file$"]' +
    'FileExtension'["$file$"]
    gives the extension for the specified file name.
    @@ -565,7 +570,7 @@ class FileInformation(Builtin): :WMA link:https://reference.wolfram.com/language/ref/FileInformation.html
    -
    'FileInformation["$file$"]' +
    'FileInformation'["$file$"]
    returns information about $file$.
    @@ -582,12 +587,12 @@ class FileInformation(Builtin): class FindFile(Builtin): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/FileFind.html
    -
    'FindFile[$name$]' -
    searches '$Path' for the given filename. +
    'FindFile'[$name$] +
    searches '\$Path' for the given filename.
    >> FindFile["ExampleData/sunflowers.jpg"] @@ -633,21 +638,21 @@ class FileNames(Builtin):
    'FileNames[]'
    Returns a list with the filenames in the current working folder. -
    'FileNames[$form$]' +
    'FileNames'[$form$]
    Returns a list with the filenames in the current working folder that \ matches with $form$. -
    'FileNames[{$form_1$, $form_2$, ...}]' +
    'FileNames'[{$form_1$, $form_2$, ...}]
    Returns a list with the filenames in the current working folder that \ matches with one of $form_1$, $form_2$, .... -
    'FileNames[{$form_1$, $form_2$, ...},{$dir_1$, $dir_2$, ...}]' +
    'FileNames'[{$form_1$, $form_2$, ...},{$dir_1$, $dir_2$, ...}]
    Looks into the directories $dir_1$, $dir_2$, .... -
    'FileNames[{$form_1$, $form_2$, ...},{$dir_1$, $dir_2$, ...}]' +
    'FileNames'[{$form_1$, $form_2$, ...},{$dir_1$, $dir_2$, ...}]
    Looks into the directories $dir_1$, $dir_2$, .... -
    'FileNames[{$forms$, $dirs$, $n$]' +
    'FileNames'[{$forms$, $dirs$, $n$]
    Look for files up to the level $n$.
    @@ -794,13 +799,13 @@ class FileNameTake(Builtin): :WMA link:https://reference.wolfram.com/language/ref/FileNameTake.html
    -
    'FileNameTake["$file$"]' +
    'FileNameTake'["$file$"]
    returns the last path element in the file name $name$. -
    'FileNameTake["$file$", $n$]' +
    'FileNameTake'["$file$", $n$]
    returns the first $n$ path elements in the file name $name$. -
    'FileNameTake["$file$", $-n$]' +
    'FileNameTake'["$file$", $-n$]
    returns the last $n$ path elements in the file name $name$.
    @@ -836,12 +841,12 @@ def eval_n(self, filename, n, evaluation: Evaluation, options: dict): class Needs(Builtin): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/Needs.html
    'Needs["context`"]' -
    loads the specified context if not already in '$Packages'. +
    loads the specified context if not already in '\$Packages'.
    >> Needs["VectorAnalysis`"] @@ -884,12 +889,12 @@ def eval(self, context, evaluation): class OperatingSystem(Predefined): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/OperatingSystem.html
    -
    '$OperatingSystem' +
    '\$OperatingSystem'
    gives the type of operating system running Mathics.
    @@ -913,13 +918,13 @@ def evaluate(self, evaluation): class PathnameSeparator(Predefined): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/$PathnameSeparator.html
    -
    '$PathnameSeparator' +
    '\$PathnameSeparator'
    returns a string for the separator in paths.
    @@ -940,8 +945,8 @@ class RenameFile(Builtin): https://reference.wolfram.com/language/ref/RenameFile.html
    -
    'RenameFile["$file1$", "$file2$"]' -
    renames $file1$ to $file2$. +
    'RenameFile'["$file_1$", "$file_2$"] +
    renames $file_1$ to $file_2$.
    >> CopyFile["ExampleData/sunflowers.jpg", "MathicsSunflowers.jpg"] @@ -1033,7 +1038,7 @@ class SetDirectory(Builtin): https://reference.wolfram.com/language/ref/SetDirectory.html
    -
    'SetDirectory[$dir$]' +
    'SetDirectory'[$dir$]
    sets the current working directory to $dir$.
    @@ -1080,7 +1085,7 @@ class ToFileName(Builtin): https://reference.wolfram.com/language/ref/ToFileName.html
    -
    'ToFileName[{"$dir_1$", "$dir_2$", ...}]' +
    'ToFileName'[{"$dir_1$", "$dir_2$", ...}]
    joins the $dir_i$ together into one path.
    @@ -1113,7 +1118,7 @@ class URLSave(Builtin):
    'URLSave["url"]'
    Save "url" in a temporary file. -
    'URLSave["url", $filename$]' +
    'URLSave'["url", $filename$]
    Save "url" in $filename$.
    """ @@ -1124,11 +1129,13 @@ class URLSave(Builtin): } summary_text = "save the content of an URL" - def eval_1(self, url, evaluation, **options): + def eval_with_url(self, url, evaluation: Evaluation, **options): "URLSave[url_String, OptionsPattern[URLSave]]" - return self.eval_2(url, None, evaluation, **options) + return self.eval_with_url_and_filename(url, None, evaluation, **options) - def eval_2(self, url, filename, evaluation, **options): + def eval_with_url_and_filename( + self, url, filename, evaluation: Evaluation, **options + ): "URLSave[url_String, filename_, OptionsPattern[URLSave]]" url = url.value if filename is None: diff --git a/mathics/builtin/files_io/importexport.py b/mathics/builtin/files_io/importexport.py index e91f20179..c76ea6dd0 100644 --- a/mathics/builtin/files_io/importexport.py +++ b/mathics/builtin/files_io/importexport.py @@ -1,17 +1,17 @@ # -*- coding: utf-8 -*- -""" +r""" Importing and Exporting Many kinds data formats can be read into \\Mathics. Variable -:$ExportFormats: -/doc/reference-of-built-in-symbols/inputoutput-files-and-filesystem/importing-and-exporting/$exportformats \ +:\$ExportFormats: +/doc/reference-of-built-in-symbols/inputoutput-files-and-filesystem/importing-and-exporting/\$exportformats
    \ contains a list of file formats that are supported by :Export: /doc/reference-of-built-in-symbols/inputoutput-files-and-filesystem/importing-and-exporting/export, \ while -:$ImportFormats: -/doc/reference-of-built-in-symbols/inputoutput-files-and-filesystem/importing-and-exporting/$importformats \ +:\$ImportFormats: +/doc/reference-of-built-in-symbols/inputoutput-files-and-filesystem/importing-and-exporting/\$importformats \ does the corresponding thing for :Import: /doc/reference-of-built-in-symbols/inputoutput-files-and-filesystem/importing-and-exporting/import. @@ -42,6 +42,7 @@ SymbolRule, SymbolToString, ) +from mathics.eval.files_io.files import eval_Close, eval_Open # This tells documentation how to sort this module # Here we are also hiding "file_io" since this can erroneously appear at the top level. @@ -49,12 +50,10 @@ mimetypes.add_type("application/vnd.wolfram.mathematica.package", ".m") -SymbolClose = Symbol("Close") SymbolDeleteFile = Symbol("DeleteFile") SymbolFileExtension = Symbol("FileExtension") SymbolFileFormat = Symbol("FileFormat") SymbolFindFile = Symbol("FindFile") -SymbolOpenRead = Symbol("OpenRead") SymbolOpenWrite = Symbol("OpenWrite") SymbolOutputStream = Symbol("OutputStream") SymbolStringToStream = Symbol("StringToStream") @@ -67,19 +66,19 @@ # TODO: Add more file formats mimetype_dict = { - "application/dicom": "DICOM", "application/dbase": "DBF", "application/dbf": "DBF", + "application/dicom": "DICOM", "application/eps": "EPS", "application/fits": "FITS", "application/json": "JSON", "application/mathematica": "NB", - "application/mdb": "MDB", "application/mbox": "MBOX", + "application/mdb": "MDB", "application/msaccess": "MDB", "application/octet-stream": "OBJ", - "application/pdf": "PDF", "application/pcx": "PCX", + "application/pdf": "PDF", "application/postscript": "EPS", "application/rss+xml": "RSS", "application/rtf": "RTF", @@ -88,15 +87,13 @@ "application/vnd.google-earth.kml+xml": "KML", "application/vnd.ms-excel": "XLS", "application/vnd.ms-pki.stl": "STL", + "application/vnd.msaccess": "MDB", "application/vnd.oasis.opendocument.spreadsheet": "ODS", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "XLSX", # nopep8 "application/vnd.sun.xml.calc": "SXC", - "application/vnd.msaccess": "MDB", "application/vnd.wolfram.cdf": "CDF", "application/vnd.wolfram.cdf.text": "CDF", "application/vnd.wolfram.mathematica.package": "Package", - "application/xhtml+xml": "XHTML", - "application/xml": "XML", "application/x-3ds": "3DS", "application/x-cdf": "NASACDF", "application/x-eps": "EPS", @@ -107,6 +104,8 @@ "application/x-netcdf": "NetCDF", "application/x-shockwave-flash": "SWF", "application/x-tex": "TeX", # Also TeX + "application/xhtml+xml": "XHTML", + "application/xml": "XML", "audio/aiff": "AIFF", "audio/basic": "AU", # Also SND "audio/midi": "MIDI", @@ -114,10 +113,10 @@ "audio/x-aiff": "AIFF", "audio/x-flac": "FLAC", "audio/x-wav": "WAV", - "chemical/seq-na-genbank": "GenBank", "chemical/seq-aa-fasta": "FASTA", "chemical/seq-na-fasta": "FASTA", "chemical/seq-na-fastq": "FASTQ", + "chemical/seq-na-genbank": "GenBank", "chemical/seq-na-sff": "SFF", "chemical/x-cif": "CIF", "chemical/x-daylight-smiles": "SMILES", @@ -158,10 +157,10 @@ "image/x-portable-graymap": "PGM", "image/x-portable-pixmap": "PPM", "image/x-xbitmap": "XBM", - "model/x3d+xml": "X3D", "model/vrml": "VRML", "model/x-lwo": "LWO", "model/x-pov": "POV", + "model/x3d+xml": "X3D", "text/calendar": "ICS", "text/comma-separated-values": "CSV", "text/csv": "CSV", @@ -173,6 +172,7 @@ "text/tab-separated-values": "TSV", "text/texmacs": "Text", "text/vnd.graphviz": "DOT", + "text/x-comma-separated-values": "CSV", "text/x-csrc": "C", "text/x-tex": "TeX", "text/x-vcalendar": "VCS", @@ -919,9 +919,9 @@ def _importer_exporter_options( py_name = None if py_name: - value = get_option(remaining_options, py_name, evaluation, pop=True) - if value is not None: - expr = Expression(SymbolRule, String(py_name), value) + option = get_option(remaining_options, py_name, evaluation, pop=True) + if option is not None: + expr = Expression(SymbolRule, String(py_name), option) if py_name == "CharacterEncoding": stream_options.append(expr) else: @@ -942,11 +942,11 @@ def _importer_exporter_options( class ConverterDumpsExtensionMappings(Predefined): - """ + r""" ## :internal native symbol:
    -
    'System`ConvertersDump`$ExtensionMappings' +
    'System`ConvertersDump`\$ExtensionMappings'
    Returns a list of associations between file extensions and file types.
    @@ -966,11 +966,11 @@ def evaluate(self, evaluation: Evaluation): class ConverterDumpsFormatMappings(Predefined): - """ + r""" ## :internal native symbol:
    -
    'System`ConverterDump$FormatMappings' +
    'System`ConverterDump\$FormatMappings'
    Returns a list of associations between file extensions and file types.
    @@ -992,11 +992,11 @@ def evaluate(self, evaluation: Evaluation): class ExportFormats(Predefined): - """ - :WMA link:https://reference.wolfram.com/language/ref/$ExportFormats.html + r""" + :WMA link:https://reference.wolfram.com/language/ref/\$ExportFormats.html
    -
    '$ExportFormats' +
    '\$ExportFormats'
    returns a list of file formats supported by Export.
    @@ -1012,11 +1012,11 @@ def evaluate(self, evaluation: Evaluation): class ImportFormats(Predefined): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/$ImportFormats.html
    -
    '$ImportFormats' +
    '\$ImportFormats'
    returns a list of file formats supported by Import.
    @@ -1036,19 +1036,19 @@ class RegisterImport(Builtin): ## :internal native symbol:
    -
    'RegisterImport["$format$", $defaultFunction$]' +
    'RegisterImport'["$format$", $defaultFunction$]
    register '$defaultFunction$' as the default function used when \ importing from a file of type '"$format$"'. -
    'RegisterImport["$format$", {"$elem1$" :> $conditionalFunction1$, \ - "$elem2$" :> $conditionalFunction2$, ..., $defaultFunction$}]' -
    registers multiple elements ($elem1$, ...) and their corresponding \ - converter functions ($conditionalFunction1$, ...) in addition to the $defaultFunction$. +
    'RegisterImport["$format$", {"$elem_1$" :> $conditionalFunction_1$, \ + "$elem_2$" :> $conditionalFunction_2$, ..., $defaultFunction$}]' +
    registers multiple elements ($elem_1$, ...) and their corresponding \ + converter functions ($conditionalFunction_1$, ...) in addition to the $defaultFunction$.
    'RegisterImport["$format$", {"$conditionalFunctions$, $defaultFunction$, \ - "$elem3$" :> $postFunction3$, "$elem4$" :> $postFunction4$, ...}]' -
    also registers additional elements ($elem3$, ...) whose converters \ - ($postFunction3$, ...) act on output from the low-level functions. + "$elem_3$" :> $postFunction_3$, "$elem_4$" :> $postFunction_4$, ...}]' +
    also registers additional elements ($elem_3$, ...) whose converters \ + ($postFunction_3$, ...) act on output from the low-level functions.
    First, define the default function used to import the data. @@ -1060,16 +1060,16 @@ class RegisterImport(Builtin): >> FilePrint["ExampleData/ExampleData.txt"] | Example File Format | Created by Angus - | 0.629452 0.586355 - | 0.711009 0.687453 - | 0.246540 0.433973 - | 0.926871 0.887255 - | 0.825141 0.940900 - | 0.847035 0.127464 - | 0.054348 0.296494 - | 0.838545 0.247025 - | 0.838697 0.436220 - | 0.309496 0.833591 + | 0.629452 0.586355 + | 0.711009 0.687453 + | 0.246540 0.433973 + | 0.926871 0.887255 + | 0.825141 0.940900 + | 0.847035 0.127464 + | 0.054348 0.296494 + | 0.838545 0.247025 + | 0.838697 0.436220 + | 0.309496 0.833591 >> Import["ExampleData/ExampleData.txt", {"ExampleFormat1", "Elements"}] = {Data, Header} @@ -1156,7 +1156,7 @@ def eval(self, formatname, function, posts, evaluation: Evaluation, options): conditionals = { elem.get_string_value(): expr - for (elem, expr) in (x.get_elements() for x in elements[:-1]) + for elem, expr in (x.get_elements() for x in elements[:-1]) } default = elements[-1] posts = {} @@ -1176,7 +1176,7 @@ class RegisterExport(Builtin): ## :internal native symbol:
    -
    'RegisterExport["$format$", $func$]' +
    'RegisterExport'["$format$", $func$]
    register '$func$' as the default function used when exporting from a file of \ type '"$format$"'.
    @@ -1238,7 +1238,7 @@ class URLFetch(Builtin): https://reference.wolfram.com/language/ref/URLFetch.html
    -
    'URLFetch[$URL$]' +
    'URLFetch'[$URL$]
    Returns the content of $URL$ as a string.
    """ @@ -1263,11 +1263,7 @@ def eval(self, url: String, elements, evaluation: Evaluation, options={}): f = request.build_opener(request.HTTPCookieProcessor).open(py_url) try: - if sys.version_info >= (3, 0): - content_type = f.info().get_content_type() - else: - content_type = f.headers["content-type"] - + content_type = f.info().get_content_type() os.write(temp_handle, f.read()) finally: f.close() @@ -1317,19 +1313,19 @@ class Import(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Import.html
    -
    'Import["$file$"]' +
    'Import'["$file$"]
    imports data from a file. -
    'Import["$file$", "$fmt$"]' +
    'Import'["$file$", "$fmt$"]
    imports file assuming the specified file format. -
    'Import["$file$", $elements$]' +
    'Import'["$file$", $elements$]
    imports the specified elements from a file. -
    'Import["$file$", {"$fmt$", $elements$}]' +
    'Import'["$file$", {"$fmt$", $elements$}]
    imports the specified elements from a file assuming the specified file format. -
    'Import["http://$url$", ...]' and 'Import["ftp://$url$", ...]' +
    'Import'["http://$url$", ...] and 'Import'["ftp://$url$", ...]
    imports from a URL.
    @@ -1432,7 +1428,7 @@ def _import(findfile, determine_filetype, elements, evaluation, options, data=No return SymbolFailed # Load the importer - (conditionals, default_function, posts, importer_options) = IMPORTERS[filetype] + conditionals, default_function, posts, importer_options = IMPORTERS[filetype] stream_options, custom_options = _importer_exporter_options( importer_options.get("System`Options"), options, "System`Import", evaluation @@ -1467,7 +1463,7 @@ def get_results(tmp_function, findfile): Expression(SymbolWriteString, data).evaluate(evaluation) else: Expression(SymbolWriteString, String("")).evaluate(evaluation) - Expression(SymbolClose, stream).evaluate(evaluation) + eval_Close(stream, evaluation) stream = None import_expression = Expression(tmp_function, findfile, *joined_options) tmp = import_expression.evaluate(evaluation) @@ -1479,9 +1475,27 @@ def get_results(tmp_function, findfile): if findfile is None: stream = Expression(SymbolStringToStream, data).evaluate(evaluation) else: - stream = Expression( - SymbolOpenRead, findfile, *stream_options - ).evaluate(evaluation) + mode = "r" + if options.get("System`BinaryFormat") is SymbolTrue: + if not mode.endswith("b"): + mode += "b" + + encoding_option = options.get("System`CharacterEncoding") + encoding = ( + encoding_option.value + if isinstance(encoding_option, String) + else None + ) + + stream = eval_Open( + name=findfile, + mode=mode, + stream_type="InputStream", + encoding=encoding, + evaluation=evaluation, + ) + if stream is None: + return if stream.get_head_name() != "System`InputStream": evaluation.message("Import", "nffil") evaluation.predetermined_out = current_predetermined_out @@ -1489,7 +1503,7 @@ def get_results(tmp_function, findfile): tmp = Expression(tmp_function, stream, *custom_options).evaluate( evaluation ) - Expression(SymbolClose, stream).evaluate(evaluation) + eval_Close(stream, evaluation) else: # TODO message evaluation.predetermined_out = current_predetermined_out @@ -1499,12 +1513,10 @@ def get_results(tmp_function, findfile): evaluation.predetermined_out = current_predetermined_out return None - # return {a.get_string_value() : b for (a,b) in map(lambda x: + # return {a.get_string_value() : b for a,b in map(lambda x: # x.get_elements(), tmp)} evaluation.predetermined_out = current_predetermined_out - return dict( - (a.get_string_value(), b) for (a, b) in [x.get_elements() for x in tmp] - ) + return {a.get_string_value(): b for a, b in (x.get_elements() for x in tmp)} # Perform the import defaults = None @@ -1535,7 +1547,7 @@ def get_results(tmp_function, findfile): evaluation.predetermined_out = current_predetermined_out return result else: - assert len(elements) == 1 + assert len(elements) >= 1 el = elements[0] if el == "Elements": defaults = get_results(default_function, findfile) @@ -1592,13 +1604,13 @@ class ImportString(Import): https://reference.wolfram.com/language/ref/ImportString.html
    -
    'ImportString["$data$", "$format$"]' +
    'ImportString'["$data$", "$format$"]
    imports data in the specified format from a string. -
    'ImportString["$file$", $elements$]' +
    'ImportString'["$file$", $elements$]
    imports the specified elements from a string. -
    'ImportString["$data$"]' +
    'ImportString'["$data$"]
    attempts to determine the format of the string from its content.
    @@ -1677,13 +1689,13 @@ class Export(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Export.html
    -
    'Export["$file$.$ext$", $expr$]' +
    'Export'["$file$.$ext$", $expr$]
    exports $expr$ to a file, using the extension $ext$ to determine the format. -
    'Export["$file$", $expr$, "$format$"]' +
    'Export'["$file$", $expr$, "$format$"]
    exports $expr$ to a file in the specified format. -
    'Export["$file$", $exprs$, $elems$]' +
    'Export'["$file$", $exprs$, $elems$]
    exports $exprs$ to a file as elements specified by $elems$.
    """ @@ -1843,7 +1855,7 @@ def eval_elements(self, filename, expr, elems, evaluation, options={}): *list(chain(stream_options, custom_options)), ) res = exporter_function.evaluate(evaluation) - Expression(SymbolClose, stream).evaluate(evaluation) + eval_Close(stream, evaluation) if res is SymbolNull: evaluation.predetermined_out = current_predetermined_out return filename @@ -1856,10 +1868,10 @@ class ExportString(Builtin): :WMA link:https://reference.wolfram.com/language/ref/ExportString.html
    -
    'ExportString[$expr$, $form$]' +
    'ExportString'[$expr$, $form$]
    exports $expr$ to a string, in the format $form$. -
    'Export["$file$", $exprs$, $elems$]' +
    'Export'["$file$", $exprs$, $elems$]
    exports $exprs$ to a string as elements specified by $elems$.
    @@ -2025,7 +2037,7 @@ def eval_elements(self, expr, elems, evaluation: Evaluation, **options): res = String(str(pystream.getvalue())) else: res = Symbol("$Failed") - Expression(SymbolClose, outstream).evaluate(evaluation) + eval_Close(outstream, evaluation) else: evaluation.message("ExportString", "emptyfch") evaluation.predetermined_out = current_predetermined_out @@ -2040,7 +2052,7 @@ class FileFormat(Builtin): :WMA link:https://reference.wolfram.com/language/ref/FileFormat.html
    -
    'FileFormat["$name$"]' +
    'FileFormat'["$name$"]
    attempts to determine what format 'Import' should use to import specified file.
    @@ -2111,7 +2123,7 @@ class B64Decode(Builtin): """ :WMA link:https://reference.wolfram.com/language/ref/B64Decode.html
    -
    'System`Convert`B64Dump`B64Decode[$string$]' +
    'System`Convert`B64Dump`B64Decode'[$string$]
    Decode $string$ in Base64 coding to an expression.
    @@ -2148,7 +2160,7 @@ class B64Encode(Builtin): :https://reference.wolfram.com/language/ref/B64Encode.html
    -
    'System`Convert`B64Dump`B64Encode[$expr$]' +
    'System`Convert`B64Dump`B64Encode'[$expr$]
    Encodes $expr$ in Base64 coding
    diff --git a/mathics/builtin/forms/__init__.py b/mathics/builtin/forms/__init__.py index 08079cc3c..4e034b9d1 100644 --- a/mathics/builtin/forms/__init__.py +++ b/mathics/builtin/forms/__init__.py @@ -1,11 +1,11 @@ -""" +r""" Forms of Input and Output A Form format specifies the way Mathics Expression input is read or output \ written. -The variable :$OutputForms': -/doc/reference-of-built-in-symbols/forms-of-input-and-output/form-variables/$outputforms/ \ +The variable :\$OutputForms': +/doc/reference-of-built-in-symbols/forms-of-input-and-output/form-variables/\$outputforms/ \ has a list of Forms defined. See also :WMA link: diff --git a/mathics/builtin/forms/other.py b/mathics/builtin/forms/other.py index a89bc08ac..a17a30619 100644 --- a/mathics/builtin/forms/other.py +++ b/mathics/builtin/forms/other.py @@ -1,5 +1,5 @@ -""" -Forms which are not in '$OutputForms' +r""" +Forms which are not in '\$OutputForms' """ import re @@ -13,13 +13,13 @@ class SequenceForm(FormBaseClass): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/SequenceForm.html
    -
    'SequenceForm[$expr1$, $expr2$, ..]' +
    'SequenceForm'[$expr_1$, $expr_2$, ..]
    format the textual concatenation of the printed forms of $expi$.
    'SequenceForm' has been superseded by :Row: @@ -56,13 +56,13 @@ def eval_makeboxes(self, args, form, evaluation, options: dict): class StringForm(FormBaseClass): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/StringForm.html
    -
    'StringForm[$str$, $expr1$, $expr2$, ...]' +
    'StringForm'[$str$, $expr_1$, $expr_2$, ...]
    displays the string $str$, replacing placeholders in $str$ with the corresponding expressions.
    diff --git a/mathics/builtin/forms/output.py b/mathics/builtin/forms/output.py index 7ec5d1d48..021440fc4 100644 --- a/mathics/builtin/forms/output.py +++ b/mathics/builtin/forms/output.py @@ -50,7 +50,7 @@ class BaseForm(FormBaseClass): https://reference.wolfram.com/language/ref/BaseForm.html
    -
    'BaseForm[$expr$, $n$]' +
    'BaseForm'[$expr$, $n$]
    prints numbers in $expr$ in base $n$.
    @@ -108,7 +108,7 @@ class FullForm(FormBaseClass): https://reference.wolfram.com/language/ref/FullForm.html
    -
    'FullForm[$expr$]' +
    'FullForm'[$expr$]
    displays the underlying form of $expr$.
    @@ -132,7 +132,7 @@ class MathMLForm(FormBaseClass): https://reference.wolfram.com/language/ref/MathMLForm.html
    -
    'MathMLForm[$expr$]' +
    'MathMLForm'[$expr$]
    displays $expr$ as a MathML expression.
    @@ -169,7 +169,7 @@ class InputForm(FormBaseClass): https://reference.wolfram.com/language/ref/InputForm.html
    -
    'InputForm[$expr$]' +
    'InputForm'[$expr$]
    displays $expr$ in an unambiguous form suitable for input.
    @@ -319,10 +319,10 @@ class NumberForm(_NumberForm): https://reference.wolfram.com/language/ref/NumberForm.html
    -
    'NumberForm[$expr$, $n$]' +
    'NumberForm'[$expr$, $n$]
    prints a real number $expr$ with $n$-digits of precision. -
    'NumberForm[$expr$, {$n$, $f$}]' +
    'NumberForm'[$expr$, {$n$, $f$}]
    prints with $n$-digits and $f$ digits to the right of the decimal point.
    @@ -472,7 +472,7 @@ class OutputForm(FormBaseClass): https://reference.wolfram.com/language/ref/OutputForm.html
    -
    'OutputForm[$expr$]' +
    'OutputForm'[$expr$]
    displays $expr$ in a plain-text form.
    @@ -496,7 +496,7 @@ class OutputForm(FormBaseClass): class PythonForm(FormBaseClass): """
    -
    'PythonForm[$expr$]' +
    'PythonForm'[$expr$]
    returns an approximate equivalent of $expr$ in Python, when that is possible. We assume that Python has SymPy imported. No explicit import will be include in the result.
    @@ -508,7 +508,7 @@ class PythonForm(FormBaseClass): >> E // PythonForm = sympy.E >> {1, 2, 3} // PythonForm - = [1, 2, 3] + = (1, 2, 3) """ in_outputforms = True @@ -539,7 +539,7 @@ def eval(self, expr, evaluation) -> Expression: class SympyForm(FormBaseClass): """
    -
    'SympyForm[$expr$]' +
    'SympyForm'[$expr$]
    returns an Sympy $expr$ in Python. Sympy is used internally to implement a number of Mathics functions, like Simplify.
    @@ -575,7 +575,7 @@ class StandardForm(FormBaseClass): https://reference.wolfram.com/language/ref/StandardForm.html
    -
    'StandardForm[$expr$]' +
    'StandardForm'[$expr$]
    displays $expr$ in the default form.
    @@ -599,7 +599,7 @@ class TraditionalForm(FormBaseClass): https://reference.wolfram.com/language/ref/TraditionalForm.html
    -
    'TraditionalForm[$expr$]' +
    'TraditionalForm'[$expr$]
    displays $expr$ in a format similar to the traditional mathematical notation, where function evaluations are represented by brackets instead of square brackets.
    @@ -622,7 +622,7 @@ class TeXForm(FormBaseClass): https://reference.wolfram.com/language/ref/TeXForm.html
    -
    'TeXForm[$expr$]' +
    'TeXForm'[$expr$]
    displays $expr$ using TeX math mode commands.
    @@ -646,7 +646,7 @@ class TableForm(FormBaseClass): https://reference.wolfram.com/language/ref/TableForm.html
    -
    'TableForm[$expr$]' +
    'TableForm'[$expr$]
    displays $expr$ as a table.
    @@ -696,7 +696,7 @@ class MatrixForm(TableForm): https://reference.wolfram.com/language/ref/MatrixForm.html
    -
    'MatrixForm[$m$]' +
    'MatrixForm'[$m$]
    displays a matrix $m$, hiding the underlying list structure.
    diff --git a/mathics/builtin/forms/variables.py b/mathics/builtin/forms/variables.py index b02500f0d..853f904d0 100644 --- a/mathics/builtin/forms/variables.py +++ b/mathics/builtin/forms/variables.py @@ -11,21 +11,21 @@ class PrintForms_(Predefined): r"""
    -
    '$PrintForms' +
    '\$PrintForms'
    contains the list of basic print forms. It is updated automatically when new 'PrintForms' are defined by setting format values.
    >> $PrintForms = ... - Suppose now that we want to add a new format 'MyForm'. Initially, it does not belong to '$PrintForms': + Suppose now that we want to add a new format 'MyForm'. Initially, it does not belong to '\$PrintForms': >> MemberQ[$PrintForms, MyForm] = False Now, let's define a format rule: >> Format[F[x_], MyForm] := "F<<" <> ToString[x] <> ">>" - Now, the new format belongs to the '$PrintForms' list + Now, the new format belongs to the '\$PrintForms' list >> MemberQ[$PrintForms, MyForm] = True @@ -42,7 +42,7 @@ def evaluate(self, evaluation): class OutputForms_(Predefined): r"""
    -
    '$OutputForms' +
    '\$OutputForms'
    contains the list of all output forms. It is updated automatically when new 'OutputForms' are defined by setting format values.
    diff --git a/mathics/builtin/functional/application.py b/mathics/builtin/functional/application.py index 336056fb5..9be292fe0 100644 --- a/mathics/builtin/functional/application.py +++ b/mathics/builtin/functional/application.py @@ -27,14 +27,14 @@ class Function(PostfixOperator, SympyFunction): https://reference.wolfram.com/language/ref/Function.html
    -
    'Function[$body$]' +
    'Function'[$body$]
    '$body$ &'
    represents a pure function with parameters '#1', '#2', etc. -
    'Function[{$x1$, $x2$, ...}, $body$]' -
    represents a pure function with parameters $x1$, $x2$, etc. +
    'Function'[{$x_1$, $x_2$, ...}, $body$] +
    represents a pure function with parameters $x_1$, $x_2$, etc. -
    'Function[{$x1$, $x2$, ...}, $body$, $attr$]' +
    'Function'[{$x_1$, $x_2$, ...}, $body$, $attr$]
    assume that the function has the attributes $attr$.
    @@ -172,7 +172,7 @@ class Slot(SympyFunction, PrefixOperator):
    '#$n$' -
    represents the $n$th argument to a pure function. +
    represents the $n$-th argument to a pure function.
    '#'
    is short-hand for '#1'. @@ -220,7 +220,7 @@ class SlotSequence(PrefixOperator, Builtin):
    is the sequence of arguments supplied to a pure function.
    '##$n$' -
    starts with the $n$th argument. +
    starts with the $n$-th argument.
    >> Plus[##]& [1, 2, 3] diff --git a/mathics/builtin/functional/apply_fns_to_lists.py b/mathics/builtin/functional/apply_fns_to_lists.py index 9fc0733de..ebc6cb917 100644 --- a/mathics/builtin/functional/apply_fns_to_lists.py +++ b/mathics/builtin/functional/apply_fns_to_lists.py @@ -34,12 +34,12 @@ class Apply(InfixOperator):
    -
    'Apply[$f$, $expr$]' +
    'Apply'[$f$, $expr$]
    '$f$ @@ $expr$'
    replaces the head of $expr$ with $f$. -
    'Apply[$f$, $expr$, $levelspec$]' +
    'Apply'[$f$, $expr$, $levelspec$]
    applies $f$ on the parts specified by $levelspec$.
    @@ -108,10 +108,10 @@ class Map(InfixOperator): https://reference.wolfram.com/language/ref/Map.html
    -
    'Map[$f$, $expr$]' or '$f$ /@ $expr$' +
    'Map'[$f$, $expr$] or '$f$ /@ $expr$'
    applies $f$ to each part on the first level of $expr$. -
    'Map[$f$, $expr$, $levelspec$]' +
    'Map'[$f$, $expr$, $levelspec$]
    applies $f$ to each level specified by $levelspec$ of $expr$.
    @@ -166,13 +166,13 @@ class MapAt(Builtin): https://reference.wolfram.com/language/ref/MapAt.html
    -
    'MapAt[$f$, $expr$, $n$]' +
    'MapAt'[$f$, $expr$, $n$]
    applies $f$ to the element at position $n$ in $expr$. If $n$ is negative, the position is counted from the end. -
    'MapAt[f, $expr$, {$i$, $j$ ...}]' +
    'MapAt'[f, $expr$, {$i$, $j$ ...}]
    applies $f$ to the part of $expr$ at position {$i$, $j$, ...}. -
    'MapAt[$f$, $pos$]' +
    'MapAt'[$f$, $pos$]
    represents an operator form of 'MapAt' that can be applied to an expression.
    @@ -231,10 +231,10 @@ class MapIndexed(Builtin): https://reference.wolfram.com/language/ref/MapIndexed.html
    -
    'MapIndexed[$f$, $expr$]' +
    'MapIndexed'[$f$, $expr$]
    applies $f$ to each part on the first level of $expr$, including the part positions in the call to $f$. -
    'MapIndexed[$f$, $expr$, $levelspec$]' +
    'MapIndexed'[$f$, $expr$, $levelspec$]
    applies $f$ to each level specified by $levelspec$ of $expr$.
    @@ -303,10 +303,10 @@ class MapThread(Builtin): https://reference.wolfram.com/language/ref/MapThread.html
    -
    'MapThread[$f$, {{$a1$, $a2$, ...}, {$b1$, $b2$, ...}, ...}] -
    returns '{$f$[$a1$, $b1$, ...], $f$[$a2$, $b2$, ...], ...}'. +
    'MapThread[$f$, {{$a_1$, $a_2$, ...}, {$b_1$, $b_2$, ...}, ...}] +
    returns '{$f$[$a_1$, $b_1$, ...], $f$[$a_2$, $b_2$, ...], ...}'. -
    'MapThread[$f$, {$expr1$, $expr2$, ...}, $n$]' +
    'MapThread'[$f$, {$expr_1$, $expr_2$, ...}, $n$]
    applies $f$ at level $n$.
    @@ -393,10 +393,10 @@ class Scan(Builtin): https://reference.wolfram.com/language/ref/Scan.html
    -
    'Scan[$f$, $expr$]' +
    'Scan'[$f$, $expr$]
    applies $f$ to each element of $expr$ and returns 'Null'. -
    'Scan[$f$, $expr$, $levelspec$]' +
    'Scan'[$f$, $expr$, $levelspec$]
    applies $f$ to each level specified by $levelspec$ of $expr$.
    @@ -446,10 +446,10 @@ class Thread(Builtin): https://reference.wolfram.com/language/ref/Thread.html
    -
    'Thread[$f$[$args$]]' +
    'Thread[$f$'[$args$]]
    threads $f$ over any lists that appear in $args$. -
    'Thread[$f$[$args$], $h$]' +
    'Thread[$f$'[$args$], $h$]
    threads over any parts with head $h$.
    diff --git a/mathics/builtin/functional/composition.py b/mathics/builtin/functional/composition.py index 9d9c969f9..f73a15073 100644 --- a/mathics/builtin/functional/composition.py +++ b/mathics/builtin/functional/composition.py @@ -34,7 +34,7 @@ class Composition(Builtin): https://reference.wolfram.com/language/ref/Composition.html
    -
    'Composition[$f$, $g$]' +
    'Composition'[$f$, $g$]
    returns the composition of two functions $f$ and $g$.
    @@ -76,7 +76,7 @@ class Identity(Builtin): :WMA link: https://reference.wolfram.com/language/ref/Identity.html
    -
    'Identity[$x$]' +
    'Identity'[$x$]
    is the identity function, which returns $x$ unchanged.
    diff --git a/mathics/builtin/functional/functional_iteration.py b/mathics/builtin/functional/functional_iteration.py index 4794545a7..a60738ed7 100644 --- a/mathics/builtin/functional/functional_iteration.py +++ b/mathics/builtin/functional/functional_iteration.py @@ -23,10 +23,10 @@ class FixedPoint(Builtin): https://reference.wolfram.com/language/ref/FixedPoint.html
    -
    'FixedPoint[$f$, $expr$]' +
    'FixedPoint'[$f$, $expr$]
    starting with $expr$, iteratively applies $f$ until the result no longer changes. -
    'FixedPoint[$f$, $expr$, $n$]' +
    'FixedPoint'[$f$, $expr$, $n$]
    performs at most $n$ iterations. The same that using $MaxIterations->n$
    @@ -91,11 +91,11 @@ class FixedPointList(Builtin): https://reference.wolfram.com/language/ref/FixedPointList.html
    -
    'FixedPointList[$f$, $expr$]' +
    'FixedPointList'[$f$, $expr$]
    starting with $expr$, iteratively applies $f$ until the result no longer changes, \ and returns a list of all intermediate results. -
    'FixedPointList[$f$, $expr$, $n$]' +
    'FixedPointList'[$f$, $expr$, $n$]
    performs at most $n$ iterations.
    @@ -159,10 +159,10 @@ class Fold(Builtin): https://reference.wolfram.com/language/ref/Fold.html
    -
    'Fold[$f$, $x$, $list$]' +
    'Fold'[$f$, $x$, $list$]
    returns the result of iteratively applying the binary operator $f$ to each element of $list$, starting with $x$. -
    'Fold[$f$, $list$]' +
    'Fold'[$f$, $list$]
    is equivalent to 'Fold[$f$, First[$list$], Rest[$list$]]'.
    @@ -185,11 +185,11 @@ class FoldList(Builtin): https://reference.wolfram.com/language/ref/FoldList.html
    -
    'FoldList[$f$, $x$, $list$]' +
    'FoldList'[$f$, $x$, $list$]
    returns a list starting with $x$, where each element is the result of applying the binary operator $f$ to the previous result and the next element of $list$. -
    'FoldList[$f$, $list$]' +
    'FoldList'[$f$, $list$]
    is equivalent to 'FoldList[$f$, First[$list$], Rest[$list$]]'.
    @@ -212,7 +212,7 @@ class Nest(Builtin): https://reference.wolfram.com/language/ref/Nest.html
    -
    'Nest[$f$, $expr$, $n$]' +
    'Nest'[$f$, $expr$, $n$]
    starting with $expr$, iteratively applies $f$ $n$ times and returns the final result.
    @@ -244,7 +244,7 @@ class NestList(Builtin): https://reference.wolfram.com/language/ref/NestList.html
    -
    'NestList[$f$, $expr$, $n$]' +
    'NestList'[$f$, $expr$, $n$]
    starting with $expr$, iteratively applies $f$ $n$ times and \ returns a list of all intermediate results.
    @@ -287,14 +287,14 @@ class NestWhile(Builtin): https://reference.wolfram.com/language/ref/NestWhile.html
    -
    'NestWhile[$f$, $expr$, $test$]' +
    'NestWhile'[$f$, $expr$, $test$]
    applies a function $f$ repeatedly on an expression $expr$, until \ applying $test$ on the result no longer yields 'True'. -
    'NestWhile[$f$, $expr$, $test$, $m$]' +
    'NestWhile'[$f$, $expr$, $test$, $m$]
    supplies the last $m$ results to $test$ (default value: 1). -
    'NestWhile[$f$, $expr$, $test$, All]' +
    'NestWhile'[$f$, $expr$, $test$, All]
    supplies all results gained so far to $test$.
    diff --git a/mathics/builtin/graphics.py b/mathics/builtin/graphics.py index 313c6fec9..e458c1ac1 100644 --- a/mathics/builtin/graphics.py +++ b/mathics/builtin/graphics.py @@ -194,7 +194,7 @@ class Show(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Show.html
    -
    'Show[$graphics$, $options$]' +
    'Show'[$graphics$, $options$]
    shows a list of graphics with the specified options added.
    @@ -235,7 +235,7 @@ class Graphics(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Graphics.html
    -
    'Graphics[$primitives$, $options$]' +
    'Graphics'[$primitives$, $options$]
    represents a graphic.
    @@ -431,7 +431,7 @@ class AbsoluteThickness(_Thickness): https://reference.wolfram.com/language/ref/AbsoluteThickness.html
    -
    'AbsoluteThickness[$p$]' +
    'AbsoluteThickness'[$p$]
    sets the line thickness for subsequent graphics primitives to $p$ \ points.
    @@ -451,9 +451,9 @@ class Point(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Point.html
    -
    'Point[{$point_1$, $point_2$ ...}]' +
    'Point'[{$point_1$, $point_2$ ...}]
    represents the point primitive. -
    'Point[{{$p_11$, $p_12$, ...}, {$p_21$, $p_22$, ...}, ...}]' +
    'Point'[{{$p_11$, $p_12$, ...}, {$p_21$, $p_22$, ...}, ...}]
    represents a number of point primitives.
    @@ -482,7 +482,7 @@ class PointSize(_Size): :WMA link:https://reference.wolfram.com/language/ref/PointSize.html
    -
    'PointSize[$t$]' +
    'PointSize'[$t$]
    sets the diameter of points to $t$, which is relative to the overall width.
    @@ -514,10 +514,10 @@ class Line(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Line.html
    -
    'Line[{$point_1$, $point_2$ ...}]' +
    'Line'[{$point_1$, $point_2$ ...}]
    represents the line primitive. -
    'Line[{{$p_11$, $p_12$, ...}, {$p_21$, $p_22$, ...}, ...}]' +
    'Line'[{{$point_{11}$, $point_{12}$, ...}, {$point_{21}$, $point_{22}$, ...}, ...}]
    represents a number of line primitives.
    @@ -571,7 +571,7 @@ class FilledCurve(Builtin): https://reference.wolfram.com/language/ref/FilledCurve.html
    -
    'FilledCurve[{$segment1$, $segment2$ ...}]' +
    'FilledCurve'[{$segment_1$, $segment_2$ ...}]
    represents a filled curve.
    @@ -590,10 +590,10 @@ class Polygon(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Polygon.html
    -
    'Polygon[{$point_1$, $point_2$ ...}]' +
    'Polygon'[{$point_1$, $point_2$ ...}]
    represents the filled polygon primitive. -
    'Polygon[{{$p_11$, $p_12$, ...}, {$p_21$, $p_22$, ...}, ...}]' +
    'Polygon'[{{$p_11$, $p_12$, ...}, {$p_21$, $p_22$, ...}, ...}]
    represents a number of filled polygon primitives.
    @@ -616,21 +616,21 @@ class Polygon(Builtin): class RegularPolygon(Builtin): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/RegularPolygon.html
    -
    'RegularPolygon[$n$]' +
    'RegularPolygon'[$n$]
    gives the regular polygon with $n$ edges. -
    'RegularPolygon[$r$, $n$]' +
    'RegularPolygon'[$r$, $n$]
    gives the regular polygon with $n$ edges and radius $r$. -
    'RegularPolygon[{$r$, $phi$}, $n$]' -
    gives the regular polygon with radius $r$ with one vertex drawn at angle $phi$. -
    'RegularPolygon[{$x, $y}, $r$, $n$]' -
    gives the regular polygon centered at the position {$x, $y}. +
    'RegularPolygon'[{$r$, $\phi$}, $n$] +
    gives the regular polygon with radius $r$ with one vertex drawn at angle $\phi$. +
    'RegularPolygon'[{$x$, $y$}, $r$, $n$] +
    gives the regular polygon centered at the position {$x$, $y$}.
    >> Graphics[RegularPolygon[5]] @@ -650,19 +650,19 @@ class Arrow(Builtin): https://reference.wolfram.com/language/ref/Arrow.html
    -
    'Arrow[{$p1$, $p2$}]' -
    represents a line from $p1$ to $p2$ that ends with an arrow at $p2$. +
    'Arrow'[{$p_1$, $p_2$}] +
    represents a line from $p_1$ to $p_2$ that ends with an arrow at $p_2$. -
    'Arrow[{$p1$, $p2$}, $s$]' -
    represents a line with arrow that keeps a distance of $s$ from $p1$ and $p2$. +
    'Arrow'[{$p_1$, $p_2$}, $s$] +
    represents a line with arrow that keeps a distance of $s$ from $p_1$ and $p_2$. -
    'Arrow[{$point_1$, $point_2$}, {$s1$, $s2$}]' -
    represents a line with arrow that keeps a distance of $s1$ from $p1$ and a \ - distance of $s2$ from $p2$. +
    'Arrow'[{$point_1$, $point_2$}, {$s_1$, $s_2$}] +
    represents a line with arrow that keeps a distance of $s_1$ from $p_1$ and a \ + distance of $s_2$ from $p_2$. -
    'Arrow[{$point_1$, $point_2$}, {$s1$, $s2$}]' -
    represents a line with arrow that keeps a distance of $s1$ from $p1$ and a \ - distance of $s2$ from $p2$. +
    'Arrow'[{$point_1$, $point_2$}, {$s_1$, $s_2$}] +
    represents a line with arrow that keeps a distance of $s_1$ from $p_1$ and a \ + distance of $s_2$ from $p_2$.
    >> Graphics[Arrow[{{0,0}, {1,1}}]] @@ -693,23 +693,23 @@ class Arrowheads(_GraphicsDirective): https://reference.wolfram.com/language/ref/Arrowheads.html
    -
    'Arrowheads[$s$]' +
    'Arrowheads'[$s$]
    specifies that Arrow[] draws one arrow of size $s$ (relative to width of \ image, defaults to 0.04). -
    'Arrowheads[{$spec1$, $spec2$, ..., $specn$}]' -
    specifies that Arrow[] draws n arrows as defined by $spec1$, $spec2$, \ - ... $specn$. +
    'Arrowheads'[{$spec_1$, $spec_2$, ..., $spec_n$}] +
    specifies that Arrow[] draws n arrows as defined by $spec_1$, $spec_2$, \ + ... $spec_n$. -
    'Arrowheads[{{$s$}}]' +
    'Arrowheads'[{{$s$}}]
    specifies that one arrow of size $s$ should be drawn. -
    'Arrowheads[{{$s$, $pos$}}]' +
    'Arrowheads'[{{$s$, $pos$}}]
    specifies that one arrow of size $s$ should be drawn at position $pos$ (for \ the arrow to be on the line, $pos$ has to be between 0, i.e. the start for \ the line, and 1, i.e. the end of the line). -
    'Arrowheads[{{$s$, $pos$, $g$}}]' +
    'Arrowheads'[{{$s$, $pos$, $g$}}]
    specifies that one arrow of size $s$ should be drawn at position $pos$ \ using Graphics $g$.
    @@ -1252,13 +1252,13 @@ class Circle(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Circle.html
    -
    'Circle[{$cx$, $cy$}, $r$]' -
    draws a circle with center '($cx$, $cy$)' and radius $r$. +
    'Circle'[{$c_x$, $c_y$}, $r$] +
    draws a circle with center '($c_x$, $c_y$)' and radius $r$. -
    'Circle[{$cx$, $cy$}, {$rx$, $ry$}]' +
    'Circle'[{$c_x$, $c_y$}, {$r_x$, $r_y$}]
    draws an ellipse. -
    'Circle[{$cx$, $cy$}]' +
    'Circle'[{$c_x$, $c_y$}]
    chooses radius 1.
    'Circle[]' @@ -1284,20 +1284,20 @@ class Disk(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Disk.html
    -
    'Disk[{$cx$, $cy$}, $r$]' -
    fills a circle with center '($cx$, $cy$)' and radius $r$. +
    'Disk'[{$c_x$, $c_y$}, $r$] +
    fills a circle with center ($c_x$, $c_y$) and radius $r$. -
    'Disk[{$cx$, $cy$}, {$rx$, $ry$}]' +
    'Disk'[{$c_x$, $c_y$}, {$r_x$, $r_y$}]
    fills an ellipse. -
    'Disk[{$cx$, $cy$}]' +
    'Disk'[{$c_x$, $c_y$}]
    chooses radius 1.
    'Disk[]' -
    chooses center '(0, 0)' and radius 1. +
    chooses center $(0, 0)$' and radius 1. -
    'Disk[{$x$, $y$}, ..., {$t1$, $t2$}]' -
    is a sector from angle $t1$ to $t2$. +
    'Disk'[{$x$, $y$}, ..., {$t_1$, $t_2$}] +
    is a sector from angle $t_1$ to $t_2$.
    >> Graphics[{Blue, Disk[{0, 0}, {2, 1}]}] @@ -1336,7 +1336,7 @@ class EdgeForm(Builtin): :WMA link:https://reference.wolfram.com/language/ref/EdgeForm.html
    -
    'EdgeForm[$g$]' +
    'EdgeForm'[$g$]
    is a graphics directive that specifies that edges of filled graphics objects are to be drawn using the graphics directive or list of directives $g$.
    @@ -1356,7 +1356,7 @@ class FaceForm(Builtin): :https://reference.wolfram.com/language/ref/FaceForm.html
    -
    'FaceForm[$g$]' +
    'FaceForm'[$g$]
    is a graphics directive that specifies that faces of filled graphics\ objects are to be drawn using the graphics directive or list of \ directives $g$. @@ -1387,13 +1387,13 @@ class Inset(Builtin): https://reference.wolfram.com/language/ref/Inset.html
    -
    'Text[$obj$]' +
    'Text'[$obj$]
    represents an object $obj$ inset in a graphic. -
    'Text[$obj$, $pos$]' +
    'Text'[$obj$, $pos$]
    represents an object $obj$ inset in a graphic at position $pos$. -
    'Text[$obj$, $pos$, $$]' +
    'Text'[$obj$, $pos$, $opos$]
    represents an object $obj$ inset in a graphic at position $pos$, \ in away that the position $opos$ of $obj$ coincides with $pos$ \ in the enclosing graphic. @@ -1434,8 +1434,8 @@ class Offset(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Offset.html
    -
    'Offset[{$dx$, $dy$}, $position$]' -
    gives the position of a graphical object obtained by starting at the specified $position$ and then moving by absolute offset {$dx$,$dy$}. +
    'Offset'[{$d_x$, $d_y$}, $position$] +
    gives the position of a graphical object obtained by starting at the specified $position$ and then moving by absolute offset {$d_x$,$d_y$}.
    """ @@ -1447,11 +1447,10 @@ class Rectangle(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Rectangle.html
    -
    'Rectangle[{$xmin$, $ymin$}]' -
    represents a unit square with bottom-left corner at {$xmin$, $ymin$}. - -
    'Rectangle[{$xmin$, $ymin$}, {$xmax$, $ymax$}] -
    is a rectangle extending from {$xmin$, $ymin$} to {$xmax$, $ymax$}. +
    'Rectangle'[{$x_{min}$, $y_{min}$}] +
    represents a unit square with bottom-left corner at {$x_{min}$, $y_{min}$}. +
    'Rectangle[{$x_{min}$, $y_{min}$}, {$x_{max}$, $y_{max}$}] +
    is a rectangle extending from {$x_{min}$, $y_{min}$} to {$x_{max}$, $y_{max}$}.
    >> Graphics[Rectangle[]] @@ -1483,8 +1482,8 @@ class Text(Inset): :WMA link:https://reference.wolfram.com/language/ref/Text.html
    -
    'Text["$text$", {$x$, $y$}]' -
    draws $text$ centered on position '{$x$, $y$}'. +
    'Text'["$text$", {$x$, $y$}] +
    draws $text$ centered on position {$x$, $y$}.
    >> Graphics[{Text["First", {0, 0}], Text["Second", {1, 1}]}, Axes->True, PlotRange->{{-2, 2}, {-2, 2}}] @@ -1527,7 +1526,7 @@ class Thickness(_Thickness): :WMA link:https://reference.wolfram.com/language/ref/Thickness.html
    -
    'Thickness[$t$]' +
    'Thickness'[$t$]
    sets the line thickness for subsequent graphics primitives to $t$ times the size of the plot area.
    diff --git a/mathics/builtin/image/basic.py b/mathics/builtin/image/basic.py index bf283591e..5ed65bf63 100644 --- a/mathics/builtin/image/basic.py +++ b/mathics/builtin/image/basic.py @@ -32,10 +32,10 @@ class Blur(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Blur.html
    -
    'Blur[$image$]' +
    'Blur'[$image$]
    gives a blurred version of $image$. -
    'Blur[$image$, $r$]' +
    'Blur'[$image$, $r$]
    blurs $image$ with a kernel of size $r$.
    @@ -63,16 +63,16 @@ class ImageAdjust(Builtin): https://reference.wolfram.com/language/ref/ImageAdjust.html
    -
    'ImageAdjust[$image$]' +
    'ImageAdjust'[$image$]
    adjusts the levels in $image$. -
    'ImageAdjust[$image$, $c$]' +
    'ImageAdjust'[$image$, $c$]
    adjusts the contrast in $image$ by $c$. -
    'ImageAdjust[$image$, {$c$, $b$}]' +
    'ImageAdjust'[$image$, {$c$, $b$}]
    adjusts the contrast $c$, and brightness $b$ in $image$. -
    'ImageAdjust[$image$, {$c$, $b$, $g$}]' +
    'ImageAdjust'[$image$, {$c$, $b$, $g$}]
    adjusts the contrast $c$, brightness $b$, and gamma $g$ in $image$.
    @@ -178,10 +178,10 @@ class ImagePartition(Builtin): :WMA link:https://reference.wolfram.com/language/ref/ImagePartition.html
    -
    'ImagePartition[$image$, $s$]' +
    'ImagePartition'[$image$, $s$]
    Partitions an image into an array of $s$ x $s$ pixel subimages. -
    'ImagePartition[$image$, {$w$, $h$}]' +
    'ImagePartition'[$image$, {$w$, $h$}]
    Partitions an image into an array of $w$ x $h$ pixel subimages.
    @@ -227,10 +227,10 @@ class Sharpen(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Sharpen.html
    -
    'Sharpen[$image$]' +
    'Sharpen'[$image$]
    gives a sharpened version of $image$. -
    'Sharpen[$image$, $r$]' +
    'Sharpen'[$image$, $r$]
    sharpens $image$ with a kernel of size $r$.
    @@ -272,7 +272,7 @@ class Threshold(Builtin): https://reference.wolfram.com/language/ref/Threshold.html
    -
    'Threshold[$image$]' +
    'Threshold'[$image$]
    gives a value suitable for binarizing $image$.
    diff --git a/mathics/builtin/image/colors.py b/mathics/builtin/image/colors.py index b275f18ef..0fdd74e57 100644 --- a/mathics/builtin/image/colors.py +++ b/mathics/builtin/image/colors.py @@ -32,14 +32,14 @@ class Binarize(Builtin): https://reference.wolfram.com/language/ref/Binarize.html
    -
    'Binarize[$image$]' +
    'Binarize'[$image$]
    gives a binarized version of $image$, in which each pixel is either 0 or 1. -
    'Binarize[$image$, $t$]' +
    'Binarize'[$image$, $t$]
    map values $x$ > $t$ to 1, and values $x$ <= $t$ to 0. -
    'Binarize[$image$, {$t1$, $t2$}]' -
    map $t1$ < $x$ < $t2$ to 1, and all other values to 0. +
    'Binarize'[$image$, {$t_1$, $t_2$}] +
    map $t_1$ < $x$ < $t_2$ to 1, and all other values to 0.
    >> hedy = Import["ExampleData/hedy.tif"]; @@ -118,7 +118,7 @@ def eval_with_t1_t2(self, image, t1, t2, evaluation: Evaluation): # :WMA link:https://reference.wolfram.com/language/ref/ColorCombine.html #
    -#
    'ColorCombine[$channels$, $colorspace$]' +#
    'ColorCombine'[$channels$, $colorspace$] #
    Gives an image with $colorspace$ and the respective components described by the given channels. #
    @@ -157,7 +157,7 @@ class ColorQuantize(Builtin): https://reference.wolfram.com/language/ref/ColorQuantize.html
    -
    'ColorQuantize[$image$, $n$]' +
    'ColorQuantize'[$image$, $n$]
    gives a version of $image$ using only $n$ colors.
    @@ -201,7 +201,7 @@ class ColorSeparate(Builtin): https://reference.wolfram.com/language/ref/ColorSeparate.html
    -
    'ColorSeparate[$image$]' +
    'ColorSeparate'[$image$]
    Gives each channel of $image$ as a separate grayscale image.
    @@ -236,13 +236,13 @@ class Colorize(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Colorize.html
    -
    'Colorize[$values$]' +
    'Colorize'[$values$]
    returns an image where each number in the rectangular matrix \ $values$ is a pixel and each occurrence of the same number is \ displayed in the same unique color, which is different from the \ colors of all non-identical numbers. -
    'Colorize[$image$]' +
    'Colorize'[$image$]
    gives a colorized version of $image$.
    @@ -308,7 +308,7 @@ class ImageColorSpace(Builtin): https://reference.wolfram.com/language/ref/ImageColorSpace.html
    -
    'ImageColorSpace[$image$]' +
    'ImageColorSpace'[$image$]
    gives $image$'s color space, e.g. "RGB" or "CMYK".
    diff --git a/mathics/builtin/image/composition.py b/mathics/builtin/image/composition.py index 6a4dd3628..b5051425e 100644 --- a/mathics/builtin/image/composition.py +++ b/mathics/builtin/image/composition.py @@ -66,7 +66,7 @@ class ImageAdd(_ImageArithmetic): https://reference.wolfram.com/language/ref/ImageAdd.html
    -
    'ImageAdd[$image$, $expr_1$, $expr_2$, ...]' +
    'ImageAdd'[$image$, $expr_1$, $expr_2$, ...]
    adds all $expr_i$ to $image$ where each $expr_i$ must be an image \ or a real number.
    @@ -98,7 +98,7 @@ class ImageMultiply(_ImageArithmetic): :WMA link:https://reference.wolfram.com/language/ref/ImageMultiply.html
    -
    'ImageMultiply[$image$, $expr_1$, $expr_2$, ...]' +
    'ImageMultiply'[$image$, $expr_1$, $expr_2$, ...]
    multiplies all $expr_i$ with $image$ where each $expr_i$ must be an image or a real number.
    @@ -122,7 +122,7 @@ class ImageSubtract(_ImageArithmetic): https://reference.wolfram.com/language/ref/ImageSubtract.html
    -
    'ImageSubtract[$image$, $expr_1$, $expr_2$, ...]' +
    'ImageSubtract'[$image$, $expr_1$, $expr_2$, ...]
    subtracts all $expr_i$ from $image$ where each $expr_i$ must be an \ image or a real number.
    @@ -146,16 +146,16 @@ class WordCloud(Builtin): https://reference.wolfram.com/language/ref/WordCloud.html
    -
    'WordCloud[{$word1$, $word2$, ...}]' +
    'WordCloud'[{$word_1$, $word_2$, ...}]
    Gives a word cloud with the given list of words. -
    'WordCloud[{$weight1$ -> $word1$, $weight2$ -> $word2$, ...}]' +
    'WordCloud'[{$weight_1$ -> $word_1$, $weight_2$ -> $word_2$, ...}]
    Gives a word cloud with the words weighted using the given weights. -
    'WordCloud[{$weight1$, $weight2$, ...} -> {$word1$, $word2$, ...}]' +
    'WordCloud'[{$weight_1$, $weight_2$, ...} -> {$word_1$, $word_2$, ...}]
    Also gives a word cloud with the words weighted using the given weights. -
    'WordCloud[{{$word1$, $weight1$}, {$word2$, $weight2$}, ...}]' +
    'WordCloud'[{{$word_1$, $weight_1$}, {$word_2$, $weight_2$}, ...}]
    Gives a word cloud with the words weighted using the given weights.
    diff --git a/mathics/builtin/image/filters.py b/mathics/builtin/image/filters.py index 2eec05881..ea036f888 100644 --- a/mathics/builtin/image/filters.py +++ b/mathics/builtin/image/filters.py @@ -31,7 +31,7 @@ class GaussianFilter(Builtin): https://reference.wolfram.com/language/ref/GaussianFilter.html
    -
    'GaussianFilter[$image$, $r$]' +
    'GaussianFilter'[$image$, $r$]
    blurs $image$ using a Gaussian blur filter of radius $r$.
    @@ -79,7 +79,7 @@ class ImageConvolve(Builtin): https://reference.wolfram.com/language/ref/ImageConvolve.html
    -
    'ImageConvolve[$image$, $kernel$]' +
    'ImageConvolve'[$image$, $kernel$]
    Computes the convolution of $image$ using $kernel$.
    @@ -113,7 +113,7 @@ class MaxFilter(_PillowImageFilter): https://reference.wolfram.com/language/ref/MaxFilter.html
    -
    'MaxFilter[$image$, $r$]' +
    'MaxFilter'[$image$, $r$]
    gives $image$ with a maximum filter of radius $r$ applied on it. This always \ picks the largest value in the filter's area.
    @@ -137,7 +137,7 @@ class MedianFilter(_PillowImageFilter): https://reference.wolfram.com/language/ref/MedianFilter.html
    -
    'MedianFilter[$image$, $r$]' +
    'MedianFilter'[$image$, $r$]
    gives $image$ with a median filter of radius $r$ applied on it. This always \ picks the median value in the filter's area.
    @@ -161,7 +161,7 @@ class MinFilter(_PillowImageFilter): https://reference.wolfram.com/language/ref/MinFilter.html
    -
    'MinFilter[$image$, $r$]' +
    'MinFilter'[$image$, $r$]
    gives $image$ with a minimum filter of radius $r$ applied on it. This always \ picks the smallest value in the filter's area.
    diff --git a/mathics/builtin/image/geometric.py b/mathics/builtin/image/geometric.py index 6f96b306c..c590c4144 100644 --- a/mathics/builtin/image/geometric.py +++ b/mathics/builtin/image/geometric.py @@ -27,10 +27,10 @@ class ImageResize(Builtin): https://reference.wolfram.com/language/ref/ImageResize.html
    -
    'ImageResize[$image$, $width$]' +
    'ImageResize'[$image$, $width$]
    -
    'ImageResize[$image$, {$width$, $height$}]' +
    'ImageResize'[$image$, {$width$, $height$}]
    @@ -139,13 +139,13 @@ class ImageReflect(Builtin): :WMA link: https://reference.wolfram.com/language/ref/ImageReflect.html
    -
    'ImageReflect[$image$]' +
    'ImageReflect'[$image$]
    Flips $image$ top to bottom. -
    'ImageReflect[$image$, $side$]' +
    'ImageReflect'[$image$, $side$]
    Flips $image$ so that $side$ is interchanged with its opposite. -
    'ImageReflect[$image$, $side_1$ -> $side_2$]' +
    'ImageReflect'[$image$, $side_1$ -> $side_2$]
    Flips $image$ so that $side_1$ is interchanged with $side_2$.
    @@ -208,9 +208,9 @@ class ImageRotate(Builtin): https://reference.wolfram.com/language/ref/ImageRotate.html
    -
    'ImageRotate[$image$]' +
    'ImageRotate'[$image$]
    Rotates $image$ 90 degrees counterclockwise. -
    'ImageRotate[$image$, $theta$]' +
    'ImageRotate'[$image$, $theta$]
    Rotates $image$ by a given angle $theta$
    diff --git a/mathics/builtin/image/misc.py b/mathics/builtin/image/misc.py index a336a0b87..0418152f5 100644 --- a/mathics/builtin/image/misc.py +++ b/mathics/builtin/image/misc.py @@ -29,7 +29,7 @@ class ImageExport(Builtin): """
    -
    'ImageExport["path", $image$]' +
    'ImageExport'["path", $image$]
    export $image$ as file in "path".
    """ @@ -107,13 +107,13 @@ class RandomImage(Builtin): :WMA link:https://reference.wolfram.com/language/ref/RandomImage.html
    -
    'RandomImage[$max$]' +
    'RandomImage'[$max$]
    creates an image of random pixels with values 0 to $max$. -
    'RandomImage[{$min$, $max$}]' +
    'RandomImage'[{$min$, $max$}]
    creates an image of random pixels with values $min$ to $max$. -
    'RandomImage[..., $size$]' +
    'RandomImage'[..., $size$]
    creates an image of the given $size$.
    @@ -173,7 +173,7 @@ class EdgeDetect(Builtin): https://reference.wolfram.com/language/ref/EdgeDetect.html
    -
    'EdgeDetect[$image$]' +
    'EdgeDetect'[$image$]
    returns an image showing the edges in $image$.
    @@ -218,7 +218,7 @@ class TextRecognize(Builtin): https://reference.wolfram.com/language/ref/TextRecognize.html
    -
    'TextRecognize[$image$]' +
    'TextRecognize'[$image$]
    Recognizes text in $image$ and returns it as a 'String'.
    diff --git a/mathics/builtin/image/morph.py b/mathics/builtin/image/morph.py index d11f17ae1..d60cafddc 100644 --- a/mathics/builtin/image/morph.py +++ b/mathics/builtin/image/morph.py @@ -42,7 +42,7 @@ class Closing(_MorphologyFilter): :https://reference.wolfram.com/language/ref/Closing.html
    -
    'Closing[$image$, $ker$]' +
    'Closing'[$image$, $ker$]
    Gives the morphological closing of $image$ with respect to structuring element $ker$.
    @@ -61,7 +61,7 @@ class Dilation(_MorphologyFilter): https://reference.wolfram.com/language/ref/Dilation.html
    -
    'Dilation[$image$, $ker$]' +
    'Dilation'[$image$, $ker$]
    Gives the morphological dilation of $image$ with respect to structuring element $ker$.
    @@ -80,7 +80,7 @@ class Erosion(_MorphologyFilter): https://reference.wolfram.com/language/ref/Erosion.html
    -
    'Erosion[$image$, $ker$]' +
    'Erosion'[$image$, $ker$]
    Gives the morphological erosion of $image$ with respect to structuring element $ker$.
    @@ -99,12 +99,12 @@ class MorphologicalComponents(Builtin): https://reference.wolfram.com/language/ref/MorphologicalComponents.html
    -
    'MorphologicalComponents[$image$]' +
    'MorphologicalComponents'[$image$]
    Builds a 2-D array in which each pixel of $image$ is replaced \ by an integer index representing the connected foreground image \ component in which the pixel lies. -
    'MorphologicalComponents[$image$, $threshold$]' +
    'MorphologicalComponents'[$image$, $threshold$]
    consider any pixel with a value above $threshold$ as the foreground.
    """ @@ -132,7 +132,7 @@ class Opening(_MorphologyFilter): https://reference.wolfram.com/language/ref/Opening.html
    -
    'Opening[$image$, $ker$]' +
    'Opening'[$image$, $ker$]
    Gives the morphological opening of $image$ with respect to structuring element $ker$.
    diff --git a/mathics/builtin/image/pixel.py b/mathics/builtin/image/pixel.py index 2d0144f30..b7b58573b 100644 --- a/mathics/builtin/image/pixel.py +++ b/mathics/builtin/image/pixel.py @@ -19,7 +19,7 @@ class PixelValue(Builtin): https://reference.wolfram.com/language/ref/PixelValue.html
    -
    'PixelValue[$image$, {$x$, $y$}]' +
    'PixelValue'[$image$, {$x$, $y$}]
    gives the value of the pixel at position {$x$, $y$} in $image$.
    @@ -53,7 +53,7 @@ class PixelValuePositions(Builtin): :WMA link:https://reference.wolfram.com/language/ref/PixelValuePositions.html
    -
    'PixelValuePositions[$image$, $val$]' +
    'PixelValuePositions'[$image$, $val$]
    gives the positions of all pixels in $image$ that have value $val$.
    diff --git a/mathics/builtin/image/properties.py b/mathics/builtin/image/properties.py index 50313a205..7ae37b4be 100644 --- a/mathics/builtin/image/properties.py +++ b/mathics/builtin/image/properties.py @@ -25,7 +25,7 @@ class ImageAspectRatio(Builtin): https://reference.wolfram.com/language/ref/ImageAspectRatio.html
    -
    'ImageAspectRatio[$image$]' +
    'ImageAspectRatio'[$image$]
    gives the aspect ratio of $image$.
    @@ -51,7 +51,7 @@ class ImageChannels(Builtin): https://reference.wolfram.com/language/ref/ImageChannels.html
    -
    'ImageChannels[$image$]' +
    'ImageChannels'[$image$]
    gives the number of channels in $image$.
    @@ -77,10 +77,10 @@ class ImageData(Builtin): https://reference.wolfram.com/language/ref/ImageData.html
    -
    'ImageData[$image$]' +
    'ImageData'[$image$]
    gives a list of all color values of $image$ as a matrix. -
    'ImageData[$image$, $stype$]' +
    'ImageData'[$image$, $stype$]
    gives a list of color values in type $stype$.
    @@ -125,7 +125,7 @@ class ImageDimensions(Builtin): https://reference.wolfram.com/language/ref/ImageDimensions.html
    -
    'ImageDimensions[$image$]' +
    'ImageDimensions'[$image$]
    Returns the dimensions {$width$, $height$} of $image$ in pixels.
    @@ -150,7 +150,7 @@ class ImageType(Builtin): :WMA link:https://reference.wolfram.com/language/ref/ImageType.html
    -
    'ImageType[$image$]' +
    'ImageType'[$image$]
    gives the interval storage type of $image$, e.g. "Real", "Bit32", or "Bit".
    diff --git a/mathics/builtin/image/structure.py b/mathics/builtin/image/structure.py index ff12ef6f4..95cd65548 100644 --- a/mathics/builtin/image/structure.py +++ b/mathics/builtin/image/structure.py @@ -22,16 +22,16 @@ class ImageTake(Builtin): Extract Image parts :WMA link: https://reference.wolfram.com/language/ref/ImageTake.html
    -
    'ImageTake[$image$, $n$]' +
    'ImageTake'[$image$, $n$]
    gives the first $n$ rows of $image$. -
    'ImageTake[$image$, -$n$]' +
    'ImageTake'[$image$, -$n$]
    gives the last $n$ rows of $image$. -
    'ImageTake[$image$, {$r1$, $r2$}]' -
    gives rows $r1$, ..., $r2$ of $image$. +
    'ImageTake'[$image$, {$r_1$, $r_2$}] +
    gives rows $r_1$, ..., $r_2$ of $image$. -
    'ImageTake[$image$, {$r1$, $r2$}, {$c1$, $c2$}]' +
    'ImageTake'[$image$, {$r_1$, $r_2$}, {$c_1$, $c_2$}]
    gives a cropped version of $image$.
    diff --git a/mathics/builtin/image/test.py b/mathics/builtin/image/test.py index 86254e8a2..62945df64 100644 --- a/mathics/builtin/image/test.py +++ b/mathics/builtin/image/test.py @@ -14,8 +14,8 @@ class BinaryImageQ(Test): https://reference.wolfram.com/language/ref/BinaryImageQ.html
    -
    'BinaryImageQ[$image]' -
    returns True if the pixels of $image are binary bit values, and False otherwise. +
    'BinaryImageQ'[$image$] +
    returns 'True' if the pixels of $image$ are binary bit values, and 'False' otherwise.
    S> img = Import["ExampleData/hedy.tif"]; @@ -40,8 +40,8 @@ class ImageQ(Test): :WMA link:https://reference.wolfram.com/language/ref/ImageQ.html
    -
    'ImageQ[Image[$pixels]]' -
    returns True if $pixels has dimensions from which an Image can be constructed, and False otherwise. +
    'ImageQ[Image'[$pixels$]] +
    returns 'True' if $pixels$ has dimensions from which an Image can be constructed, and 'False' otherwise.
    >> ImageQ[Image[{{0, 1}, {1, 0}}]] diff --git a/mathics/builtin/inout.py b/mathics/builtin/inout.py index 607fc9c06..035e3a213 100644 --- a/mathics/builtin/inout.py +++ b/mathics/builtin/inout.py @@ -43,7 +43,7 @@ class Print(Builtin): https://reference.wolfram.com/language/ref/Print.html
    -
    'Print[$expr$, ...]' +
    'Print'[$expr$, ...]
    prints each $expr$ in string form.
    diff --git a/mathics/builtin/intfns/combinatorial.py b/mathics/builtin/intfns/combinatorial.py index ae3c4df0e..7a137cad7 100644 --- a/mathics/builtin/intfns/combinatorial.py +++ b/mathics/builtin/intfns/combinatorial.py @@ -11,7 +11,7 @@ biology to computer science, etc. """ - +from abc import ABC from itertools import combinations from mathics.core.atoms import Integer, Integer1 @@ -48,11 +48,11 @@ class BellB(SympyFunction): :SymPy: https://docs.sympy.org/latest/modules/functions/combinatorial.html#sympy.functions.combinatorial.numbers.bell, :WMA: https://reference.wolfram.com/language/ref/BellB.html)
    -
    'BellB[$n$]' -
    Bell number $B$_$n$. +
    'BellB'[$n$] +
    Bell number $B_n$. -
    'BellB[$n$, $x$]' -
    Bell polynomial $B$_$n$($x$). +
    'BellB'[$n$, $x$] +
    Bell polynomial $B_n(x)$.
    >> BellB[10] @@ -71,7 +71,7 @@ def eval(self, z, evaluation: Evaluation): return super().eval(z, evaluation) -class _BooleanDissimilarity(Builtin): +class _BooleanDissimilarity(Builtin, ABC): @staticmethod def _to_bool_vector(u): def generate(): @@ -97,7 +97,10 @@ def generate(): except _NoBoolVector: return None - def eval(self, u, v, evaluation): + def _compute(self, n, c_ff, c_ft, c_tf, c_tt) -> Expression: + raise NotImplementedError + + def eval(self, u, v, evaluation: Evaluation): "%(name)s[u_List, v_List]" if len(u.elements) != len(v.elements): return @@ -129,7 +132,7 @@ class Binomial(MPMathFunction): https://reference.wolfram.com/language/ref/Binomial.html)
    -
    'Binomial[$n$, $k$]' +
    'Binomial'[$n$, $k$]
    gives the binomial coefficient $n$ choose $k$.
    @@ -167,8 +170,8 @@ class CatalanNumber(SympyFunction): https://reference.wolfram.com/language/ref/CatalanNumber.html)
    -
    'CatalanNumber[$n$]' -
    gives the $n$th Catalan number. +
    'CatalanNumber'[$n$] +
    gives the $n$-th Catalan number.
    A list of the first five Catalan numbers: @@ -198,10 +201,10 @@ class DiceDissimilarity(_BooleanDissimilarity): :DiceDissimilarity: https://reference.wolfram.com/language/ref/DiceDissimilarity.html)
    -
    'DiceDissimilarity[$u$, $v$]' -
    returns the Dice dissimilarity between the two boolean 1-D lists $u$ and $v$. - This is defined as ($c_tf$ + $c_ft$) / (2 * $c_tt$ + $c_ft$ + c_tf). - $n$ is len($u$) and $c_ij$ is the number of occurrences of $u$[$k$]=$i$ and $v$[$k$]=$j$ for $k$ < $n$. +
    'DiceDissimilarity'[$u$, $v$] +
    returns the Dice dissimilarity between the two Boolean 1-D lists $u$ and $v$. + This is defined as ($c_{tf}$ + $c_{ft}$) / (2 * $c_{tt}$ + $c_{ft}$ + $c_{tf}$). + $n$ is len($u$) and $c_{ij}$ is the number of occurrences of $u[k]=i$ and $v[k]=j$ for $k < n$.
    >> DiceDissimilarity[{1, 0, 1, 1, 0, 1, 1}, {0, 1, 1, 0, 0, 0, 1}] @@ -210,7 +213,7 @@ class DiceDissimilarity(_BooleanDissimilarity): summary_text = "Dice dissimilarity" - def _compute(self, n, c_ff, c_ft, c_tf, c_tt): + def _compute(self, n, c_ff, c_ft, c_tf, c_tt) -> Expression: return Expression( SymbolDivide, Integer(c_tf + c_ft), Integer(2 * c_tt + c_ft + c_tf) ) @@ -223,11 +226,11 @@ class EulerE(SympyFunction): :SymPy: https://docs.sympy.org/latest/modules/functions/combinatorial.html#sympy.functions.combinatorial.numbers.euler, :WMA: https://reference.wolfram.com/language/ref/EulerE.html)
    -
    'EulerE[$n$]' -
    Euler number $E$_$n$. +
    'EulerE'[$n$] +
    Euler number $E_n$. -
    'EulerE[$n$, $x$]' -
    Euler polynomial $E$_$n$($x$). +
    'EulerE'[$n$, $x$] +
    Euler polynomial $E_n(x)$.
    Odd-index Euler numbers are zero: @@ -261,12 +264,12 @@ class JaccardDissimilarity(_BooleanDissimilarity): :WMA: https://reference.wolfram.com/language/ref/JaccardDissimilarity.html)
    -
    'JaccardDissimilarity[$u$, $v$]' -
    returns the Jaccard-Needham dissimilarity between the two boolean \ +
    'JaccardDissimilarity'[$u$, $v$] +
    returns the Jaccard-Needham dissimilarity between the two Boolean \ 1-D lists $u$ and $v$, which is defined as \ - ($c_tf$ + $c_ft$) / ($c_tt$ + $c_ft$ + $c_tf$), where $n$ is \ - len($u$) and $c_ij$ is the number of occurrences of \ - $u$[$k$]=$i$ and $v$[$k$]=$j$ for $k$ < $n$. + $(c_{tf} + c_{ft}) / (c_{tt} + c_{ft} + c_{tf})$, where $n$ is \ + len($u$) and $c_{ij}$ is the number of occurrences of \ + $u[k]=i$ and $v[k]=j$ for $k < n$.
    >> JaccardDissimilarity[{1, 0, 1, 1, 0, 1, 1}, {0, 1, 1, 0, 0, 0, 1}] @@ -293,11 +296,11 @@ class LucasL(SympyFunction): https://reference.wolfram.com/language/ref/LucasL.html)
    -
    'LucasL[$n$]' +
    'LucasL'[$n$]
    gives the $n$th Lucas number. -
    'LucasL[$n$, $x$]' -
    gives the $n$th Lucas polynomial $L$_($x$). +
    'LucasL'[$n$, $x$] +
    gives the $n$th Lucas polynomial $L_(x)$.
    A list of the first five Lucas numbers: @@ -331,11 +334,11 @@ class MatchingDissimilarity(_BooleanDissimilarity): :WMA link:https://reference.wolfram.com/language/ref/MatchingDissimilarity.html
    -
    'MatchingDissimilarity[$u$, $v$]' -
    returns the Matching dissimilarity between the two boolean \ - 1-D lists $u$ and $v$, which is defined as ($c_tf$ + $c_ft$) / $n$, \ - where $n$ is len($u$) and $c_ij$ is the number of occurrences of \ - $u$[$k$]=$i$ and $v$[$k$]=$j$ for $k$ < $n$. +
    'MatchingDissimilarity'[$u$, $v$] +
    returns the Matching dissimilarity between the two Boolean \ + 1-D lists $u$ and $v$, which is defined as $(c_{tf} + c_{ft}) / n$, \ + where $n$ is len($u$) and $c_{ij}$ is the number of occurrences of \ + $u[k]=i$ and $v[k]=j$ for $k < n$.
    >> MatchingDissimilarity[{1, 0, 1, 1, 0, 1, 1}, {0, 1, 1, 0, 0, 0, 1}] @@ -355,8 +358,8 @@ class Multinomial(Builtin): https://en.wikipedia.org/wiki/Multinomial_distribution (\ :WMA: https://reference.wolfram.com/language/ref/Multinomial.html)
    -
    'Multinomial[$n1$, $n2$, ...]' -
    gives the multinomial coefficient '($n1$+$n2$+...)!/($n1$!$n2$!...)'. +
    'Multinomial'[$n_1$, $n_2$, ...] +
    gives the multinomial coefficient $(n_1+n_2+...)!/(n_1!n_2!...)$.
    >> Multinomial[2, 3, 4, 5] @@ -366,9 +369,13 @@ class Multinomial(Builtin): Multinomial is expressed in terms of 'Binomial': >> Multinomial[a, b, c] = Binomial[a, a] Binomial[a + b, b] Binomial[a + b + c, c] - 'Multinomial[$n$-$k$, $k$]' is equivalent to 'Binomial[$n$, $k$]'. + 'Multinomial'[$n$-$k$, $k$] is equivalent to 'Binomial'[$n$, $k$]: >> Multinomial[2, 3] = 10 + + See also + :'Binomial': + /doc/reference-of-built-in-symbols/integer-functions/combinatorial-functions/binomial/. """ attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_ORDERLESS | A_PROTECTED @@ -394,11 +401,11 @@ class PolygonalNumber(Builtin): :Polygonal number: https://en.wikipedia.org/wiki/Polygonal_number ( :WMA: https://reference.wolfram.com/language/ref/PolygonalNumber.html)
    -
    'PolygonalNumber[$n$]' -
    gives the $n$th triangular number. +
    'PolygonalNumber'[$n$] +
    gives the $n$-th triangular number. -
    'PolygonalNumber[$r$, $n$]' -
    gives the $n$th $r$-gonal number. +
    'PolygonalNumber'[$r$, $n$] +
    gives the $n$-th $r$-gonal number.
    >> Table[PolygonalNumber[n], {n, 10}] @@ -416,9 +423,9 @@ class PolygonalNumber(Builtin): See also :Binomial: - doc/reference-of-built-in-symbols/integer-functions/combinatorial-functions/binomial/, and + /doc/reference-of-built-in-symbols/integer-functions/combinatorial-functions/binomial/, and :RegularPolygon: - doc/reference-of-built-in-symbols/drawing-graphics/regularpolygon/. + /doc/reference-of-built-in-symbols/drawing-graphics/regularpolygon/. """ attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED @@ -431,17 +438,19 @@ class PolygonalNumber(Builtin): class RogersTanimotoDissimilarity(_BooleanDissimilarity): """ - - :WMA link: - https://reference.wolfram.com/language/ref/RogersTanimotoDissimilarity.html + :Rogers Tanimoto coefficient: + https://en.wikipedia.org/wiki/Qualitative_variation#Rogers%E2%80%93Tanimoto_coefficient + ( + :WMA: + https://reference.wolfram.com/language/ref/RogersTanimotoDissimilarity.html)
    -
    'RogersTanimotoDissimilarity[$u$, $v$]' -
    returns the Rogers-Tanimoto dissimilarity between the two boolean \ +
    'RogersTanimotoDissimilarity'[$u$, $v$] +
    returns the Rogers-Tanimoto dissimilarity between the two Boolean \ 1-D lists $u$ and $v$, which is defined as \ - $R$ / (c_tt + c_ff + $R$) where $n$ is len($u$), c_ij is \ - the number of occurrences of $u$[$k$]=$i$ and $v$[$k]$=$j$ for $k$ >> RogersTanimotoDissimilarity[{1, 0, 1, 1, 0, 1, 1}, {0, 1, 1, 0, 0, 0, 1}] @@ -457,16 +466,17 @@ def _compute(self, n, c_ff, c_ft, c_tf, c_tt): class RussellRaoDissimilarity(_BooleanDissimilarity): """ - - :WMA link: - https://reference.wolfram.com/language/ref/RusselRaoDissimilarity.html + :Russel-Rao coefficient: + https://en.wikipedia.org/wiki/Qualitative_variation#Russel%E2%80%93Rao_coefficient ( + :WMA: + https://reference.wolfram.com/language/ref/RusselRaoDissimilarity.html)
    -
    'RussellRaoDissimilarity[$u$, $v$]' -
    returns the Russell-Rao dissimilarity between the two boolean \ - 1-D lists $u$ and $v$, which is defined as ($n$ - $c_tt$) / $c_tt$ \ - where $n$ is len($u$) and $c_ij$ is \ - the number of occurrences of $u$[k]=i and $v$[$k$]=$j$ for $k$ < $n$. +
    'RussellRaoDissimilarity'[$u$, $v$] +
    returns the Russell-Rao dissimilarity between the two Boolean \ + 1-D lists $u$ and $v$, which is defined as $(n - c_{tt}) / c_{tt}$ \ + where $n$ is $len(u)$, $c_{ij}$ is \ + the number of occurrences of $u[k]=i$ and $v[k]=j$ for $k < n$.
    >> RussellRaoDissimilarity[{1, 0, 1, 1, 0, 1, 1}, {0, 1, 1, 0, 0, 0, 1}] @@ -481,17 +491,19 @@ def _compute(self, n, c_ff, c_ft, c_tf, c_tt): class SokalSneathDissimilarity(_BooleanDissimilarity): """ - - :WMA link: - https://reference.wolfram.com/language/ref/SokalSneathDissimilarity.html + + :Snokal-Sneath coefficient: + https://en.wikipedia.org/wiki/Qualitative_variation#Sokal%E2%80%93Sneath_coefficient ( + :WMA: + https://reference.wolfram.com/language/ref/SokalSneathDissimilarity.html)
    -
    'SokalSneathDissimilarity[$u$, $v$]' -
    returns the Sokal-Sneath dissimilarity between the two boolean \ - 1-D lists $u$ and $v$, which is defined as $R$ / (c_tt + $R$) where \ - $n$ is len($u$), $c_ij$ is the number of occurrences of \ - $u$[$k$]=$i$ and $v$[k]=$j$ for $k$ < $n$, \ - and $R$ = 2 * ($c_tf$ + $c_ft$). +
    'SokalSneathDissimilarity'[$u$, $v$] +
    returns the Sokal-Sneath dissimilarity between the two Boolean \ + 1-D lists $u$ and $v$, which is defined as $R / (c_{tt} + R)$ where \ + $n$ is $len(u)$, $c_{ij}$ is the number of occurrences of \ + $u[k]=i$, $v[k]=j$ for $k < n$, \ + and $R = 2 (c_{tf} + c_{ft})$.
    >> SokalSneathDissimilarity[{1, 0, 1, 1, 0, 1, 1}, {0, 1, 1, 0, 0, 0, 1}] @@ -513,24 +525,24 @@ class Subsets(Builtin): https://reference.wolfram.com/language/ref/Subsets.html)
    -
    'Subsets[$list$]' +
    'Subsets'[$list$]
    finds a list of all possible subsets of $list$. -
    'Subsets[$list$, $n$]' +
    'Subsets'[$list$, $n$]
    finds a list of all possible subsets containing at most $n$ elements. -
    'Subsets[$list$, {$n$}]' +
    'Subsets'[$list$, {$n$}]
    finds a list of all possible subsets containing exactly $n$ elements. -
    'Subsets[$list$, {$min$, $max$}]' +
    'Subsets'[$list$, {$min$, $max$}]
    finds a list of all possible subsets containing between $min$ and \ $max$ elements. -
    'Subsets[$list$, $spec$, $n$]' +
    'Subsets'[$list$, $spec$, $n$]
    finds a list of the first $n$ possible subsets. -
    'Subsets[$list$, $spec$, {$n$}]' -
    finds the $n$th possible subset. +
    'Subsets'[$list$, $spec$, {$n$}] +
    finds the $n$-th possible subset.
    All possible subsets (power set): @@ -557,7 +569,7 @@ class Subsets(Builtin): >> Subsets[Range[5], All, {25}] = {{2, 4, 5}} - The odd-numbered subsets of {a,b,c,d} in reverse order: + The odd-numbered subsets of {$a$,$b$,$c$,$d$} in reverse order: >> Subsets[{a, b, c, d}, All, {15, 1, -2}] = {{b, c, d}, {a, b, d}, {c, d}, {b, c}, {a, c}, {d}, {b}, {}} """ @@ -701,12 +713,12 @@ class YuleDissimilarity(_BooleanDissimilarity): :WMA link:https://reference.wolfram.com/language/ref/YuleDissimilarity.html
    -
    'YuleDissimilarity[$u$, $v$]' -
    returns the Yule dissimilarity between the two boolean 1-D lists $u$ \ - and $v$, which is defined as $R$ / ($c_tt$ * $c_ff$ + $R$ / 2) \ - where $n$ is len($u$), $c_ij$ is the number of occurrences of \ - $u$[$k$]=$i$ and $v$[$k$]=$j$ for $k$<$n$, \ - and $R$ = 2 * $c_tf$ * $c_ft$. +
    'YuleDissimilarity'[$u$, $v$] +
    returns the Yule dissimilarity between the two Boolean 1-D lists $u$ \ + and $v$, which is defined as $R / (c_{tt} c_{ff} + R / 2)$ \ + where $n$ is $len(u)$, $c_{ij}$ is the number of occurrences of \ + $u[k]=i$, $v[k]=j$ for $k >> YuleDissimilarity[{1, 0, 1, 1, 0, 1, 1}, {0, 1, 1, 0, 0, 0, 1}] diff --git a/mathics/builtin/intfns/divlike.py b/mathics/builtin/intfns/divlike.py index 6bb29601c..feb6ca1cf 100644 --- a/mathics/builtin/intfns/divlike.py +++ b/mathics/builtin/intfns/divlike.py @@ -38,7 +38,7 @@ class CompositeQ(Builtin): https://reference.wolfram.com/language/ref/CompositeQ.html
    -
    'CompositeQ[$n$]' +
    'CompositeQ'[$n$]
    returns 'True' if $n$ is a composite number
    @@ -66,7 +66,7 @@ class Divisible(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Divisible.html
    -
    'Divisible[$n$, $m$]' +
    'Divisible'[$n$, $m$]
    returns 'True' if $n$ is divisible by $m$, and 'False' otherwise.
    @@ -97,7 +97,7 @@ class GCD(Builtin): https://reference.wolfram.com/language/ref/GCD.html
    -
    'GCD[$n1$, $n2$, ...]' +
    'GCD'[$n_1$, $n_2$, ...]
    computes the greatest common divisor of the given integers.
    @@ -134,7 +134,7 @@ class LCM(Builtin): :WMA link:https://reference.wolfram.com/language/ref/LCM.html
    -
    'LCM[$n1$, $n2$, ...]' +
    'LCM'[$n_1$, $n_2$, ...]
    computes the least common multiple of the given integers.
    @@ -165,7 +165,7 @@ class Mod(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Mod.html
    -
    'Mod[$x$, $m$]' +
    'Mod'[$x$, $m$]
    returns $x$ modulo $m$.
    @@ -203,7 +203,7 @@ class ModularInverse(SympyFunction): )
    -
    'ModularInverse[$k$, $n$]' +
    'ModularInverse'[$k$, $n$]
    returns the modular inverse $k$^(-1) mod $n$.
    @@ -239,11 +239,11 @@ def eval_k_n(self, k: Integer, n: Integer, evaluation: Evaluation): class PowerMod(Builtin): """ - Modular exponentiaion. + Modular exponentiation. See https://en.wikipedia.org/wiki/Modular_exponentiation.
    -
    'PowerMod[$x$, $y$, $m$]' +
    'PowerMod'[$x$, $y$, $m$]
    computes $x$^$y$ modulo $m$.
    diff --git a/mathics/builtin/intfns/misc.py b/mathics/builtin/intfns/misc.py index 9378d0dd9..bea98cf07 100644 --- a/mathics/builtin/intfns/misc.py +++ b/mathics/builtin/intfns/misc.py @@ -14,11 +14,11 @@ class BernoulliB(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/BernoulliB.html
    -
    'BernoulliB[$n$]' -
    represents the Bernoulli number B_$n$. +
    'BernoulliB'[$n$] +
    represents the Bernoulli number $B_n$. -
    'BernouilliB[$n$, $x$]' -
    represents the Bernoulli polynomial B_$n[x]$. +
    'BernouilliB'[$n$, $x$] +
    represents the Bernoulli polynomial $B_n(x)$.
    >> BernoulliB[42] diff --git a/mathics/builtin/intfns/recurrence.py b/mathics/builtin/intfns/recurrence.py index 0c98c9611..d377cfec0 100644 --- a/mathics/builtin/intfns/recurrence.py +++ b/mathics/builtin/intfns/recurrence.py @@ -30,10 +30,10 @@ class Fibonacci(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/Fibonacci.html)
    -
    'Fibonacci[$n$]' -
    computes the $n$th Fibonacci number. -
    'Fibonacci[$n$, $x$]' -
    computes the Fibonacci polynomial $F$_$n$($x$). +
    'Fibonacci'[$n$] +
    computes the $n$-th Fibonacci number. +
    'Fibonacci'[$n$, $x$] +
    computes the Fibonacci polynomial $F_n(x)$.
    >> Fibonacci[0] @@ -71,7 +71,7 @@ class HarmonicNumber(MPMathFunction):
    'HarmonicNumber[n]' -
    returns the $n$th harmonic number. +
    returns the $n$-th harmonic number.
    >> Table[HarmonicNumber[n], {n, 8}] @@ -96,13 +96,13 @@ class LinearRecurrence(Builtin): :WMA link:https://reference.wolfram.com/language/ref/LinearRecurrence.html
    -
    'LinearRecurrence[$ker$, $init$, $n$]' +
    'LinearRecurrence'[$ker$, $init$, $n$]
    computes $n$ terms of the linear recurrence with kernel $ker$ and initial values $init$. -
    'LinearRecurrence[$ker$, $init$, {$n$}]' -
    computes the $n$th term. +
    'LinearRecurrence'[$ker$, $init$, {$n$}] +
    computes the $n$-th term. -
    'LinearRecurrence[$ker$, $init$, {$n_min$, $n_max$}]' +
    'LinearRecurrence'[$ker$, $init$, {$n_{min}$, $n_{max}$}]
    computes $n$ terms of the linear recurrence with kernel $ker$ and initial values $init$.
    @@ -143,7 +143,7 @@ class StirlingS1(Builtin): https://reference.wolfram.com/language/ref/StirlingS1.html)
    -
    'StirlingS1[$n$, $m$]' +
    'StirlingS1'[$n$, $m$]
    gives the Stirling number of the first kind.
    @@ -177,7 +177,7 @@ class StirlingS2(Builtin): https://reference.wolfram.com/language/ref/StirlingS2.html)
    -
    'StirlingS2[$n$, $m$]' +
    'StirlingS2'[$n$, $m$]
    gives the Stirling number of the second kind. Returns the number of ways \ of partitioning a set of $n$ elements into $m$ non empty subsets.
    diff --git a/mathics/builtin/kernel_sessions.py b/mathics/builtin/kernel_sessions.py index 215f76514..64046bb56 100644 --- a/mathics/builtin/kernel_sessions.py +++ b/mathics/builtin/kernel_sessions.py @@ -8,11 +8,11 @@ class Out(Builtin): - """ - :WMA: https://reference.wolfram.com/language/ref/$Out + r""" + :WMA: https://reference.wolfram.com/language/ref/\$Out
    -
    '%$k$' or 'Out[$k$]' -
    gives the result of the $k$th input line. +
    '%$k$' or 'Out'[$k$] +
    gives the result of the $k$-th input line.
    '%'
    gives the last result. @@ -70,7 +70,7 @@ class Quit(Builtin):
    'Quit'[]
    Terminates the Mathics session. -
    'Quit[$n$]' +
    'Quit'[$n$]
    Terminates the mathics session with exit code $n$.
    @@ -95,7 +95,7 @@ class Exit(Quit):
    'Exit'[]
    Terminates the Mathics session. -
    'Exit[$n$]' +
    'Exit'[$n$]
    Terminates the mathics session with exit code $n$.
    diff --git a/mathics/builtin/layout.py b/mathics/builtin/layout.py index 358cd6289..f35c4c979 100644 --- a/mathics/builtin/layout.py +++ b/mathics/builtin/layout.py @@ -46,7 +46,7 @@ class Format(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Format.html
    -
    'Format[$expr$]' +
    'Format'[$expr$]
    holds values specifying how $expr$ should be printed.
    @@ -82,7 +82,7 @@ class Grid(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Grid.html
    -
    'Grid[{{$a1$, $a2$, ...}, {$b1$, $b2$, ...}, ...}]' +
    'Grid'[{{$a_1$, $a_2$, ...}, {$b_1$, $b_2$, ...}, ...}]
    formats several expressions inside a 'GridBox'.
    @@ -155,7 +155,7 @@ class Infix(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Infix.html
    -
    'Infix[$expr$, $oper$, $prec$, $assoc$]' +
    'Infix'[$expr$, $oper$, $prec$, $assoc$]
    displays $expr$ with the infix operator $oper$, with precedence $prec$ and associativity $assoc$.
    @@ -242,7 +242,7 @@ class Precedence(Builtin): on, logic, comparison, datentime, attributes and binary)
    -
    'Precedence[$op$]' +
    'Precedence'[$op$]
    returns the precedence of the built-in operator $op$.
    @@ -345,7 +345,7 @@ class Row(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Row.html
    -
    'Row[{$expr$, ...}]' +
    'Row'[{$expr$, ...}]
    formats several expressions inside a 'RowBox'.
    """ @@ -377,35 +377,35 @@ class Style(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Style.html
    -
    'Style[$expr$, options]' +
    'Style'[$expr$, options]
    displays $expr$ formatted using the specified option settings. -
    'Style[$expr$, "style"]' +
    'Style'[$expr$, "style"]
    uses the option settings for the specified style in the current notebook. -
    'Style[$expr$, $color$]' +
    'Style'[$expr$, $color$]
    displays using the specified color. -
    'Style[$expr$, $Bold$]' +
    'Style'[$expr$, $Bold$]
    displays with fonts made bold. -
    'Style[$expr$, $Italic$]' +
    'Style'[$expr$, $Italic$]
    displays with fonts made italic. -
    'Style[$expr$, $Underlined$]' +
    'Style'[$expr$, $Underlined$]
    displays with fonts underlined.
    'Style[$expr$, $Larger$]
    displays with fonts made larger. -
    'Style[$expr$, $Smaller$]' +
    'Style'[$expr$, $Smaller$]
    displays with fonts made smaller. -
    'Style[$expr$, $n$]' +
    'Style'[$expr$, $n$]
    displays with font size n. -
    'Style[$expr$, $Tiny$]' -
    'Style[$expr$, $Small$]', etc. +
    'Style'[$expr$, $Tiny$] +
    'Style'[$expr$, $Small$], etc.
    display with fonts that are tiny, small, etc.
    """ @@ -428,7 +428,7 @@ class Subscript(Builtin): https://reference.wolfram.com/language/ref/Subscript.html
    -
    'Subscript[$a$, $i$]' +
    'Subscript'[$a$, $i$]
    displays as $a_i$.
    @@ -456,7 +456,7 @@ class Subsuperscript(Builtin): https://reference.wolfram.com/language/ref/Subsuperscript.html
    -
    'Subsuperscript[$a$, $b$, $c$]' +
    'Subsuperscript'[$a$, $b$, $c$]
    displays as $a_b^c$.
    @@ -480,7 +480,7 @@ class Superscript(Builtin): https://reference.wolfram.com/language/ref/Superscript.html
    -
    'Superscript[$x$, $y$]' +
    'Superscript'[$x$, $y$]
    displays as $x$^$y$.
    diff --git a/mathics/builtin/list/associations.py b/mathics/builtin/list/associations.py index 7659adc6a..ebe90b410 100644 --- a/mathics/builtin/list/associations.py +++ b/mathics/builtin/list/associations.py @@ -28,8 +28,8 @@ class Association(Builtin): https://reference.wolfram.com/language/ref/Association.html
    -
    'Association[$key1$ -> $val1$, $key2$ -> $val2$, ...]' -
    '<|$key1$ -> $val1$, $key2$ -> $val2$, ...|>' +
    'Association'[$key_1$ -> $val_1$, $key_2$ -> $val_2$, ...] +
    '<|$key_1$ -> $val_1$, $key_2$ -> $val_2$, ...|>'
    represents an association between keys and values.
    @@ -134,7 +134,7 @@ class AssociationQ(Test): :WMA link:https://reference.wolfram.com/language/ref/AssociationQ.html
    -
    'AssociationQ[$expr$]' +
    'AssociationQ'[$expr$]
    return True if $expr$ is a valid Association object, and False otherwise.
    @@ -167,9 +167,9 @@ class Key(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Key.html
    -
    Key[$key$] +
    'Key'[$key$]
    represents a key used to access a value in an association. -
    Key[$key$][$assoc$] +
    'Key'[$key$][$assoc$]
    """ @@ -185,11 +185,11 @@ class Keys(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Keys.html
    -
    'Keys[<|$key1$ -> $val1$, $key2$ -> $val2$, ...|>]' +
    'Keys'['<|' $key_1$ '->' $val_1$, $key_2$ '->' $val_2$, ...'|>']
    return a list of the keys $keyi$ in an association. -
    'Keys[{$key1$ -> $val1$, $key2$ -> $val2$, ...}]' -
    return a list of the $keyi$ in a list of rules. +
    'Keys'[{$key_1$ '->' $val_1$, $key_2$ '->' $val_2$, ...}] +
    return a list of the $key_i$ in a list of rules.
    >> Keys[<|a -> x, b -> y|>] @@ -285,11 +285,11 @@ class Values(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Values.html
    -
    'Values[<|$key1$ -> $val1$, $key2$ -> $val2$, ...|>]' -
    return a list of the values $vali$ in an association. +
    'Values'['<|'$key_1$ '->' $val_1$, $key_2$ -> $val_2$, ...'|>'] +
    return a list of the values $val_i$ in an association. -
    'Values[{$key1$ -> $val1$, $key2$ -> $val2$, ...}]' -
    return a list of the $vali$ in a list of rules. +
    'Values'[{$key_1$ '->' $val_1$, $key_2$ '->' $val_2$, ...}] +
    return a list of the $val_i$ in a list of rules.
    >> Values[<|a -> x, b -> y|>] diff --git a/mathics/builtin/list/constructing.py b/mathics/builtin/list/constructing.py index 1d977117b..2704d4c54 100644 --- a/mathics/builtin/list/constructing.py +++ b/mathics/builtin/list/constructing.py @@ -34,17 +34,17 @@ class Array(Builtin): https://reference.wolfram.com/language/ref/Array.html
    -
    'Array[$f$, $n$]' +
    'Array'[$f$, $n$]
    returns the $n$-element list '{$f$[1], ..., $f$[$n$]}'. -
    'Array[$f$, $n$, $a$]' +
    'Array'[$f$, $n$, $a$]
    returns the $n$-element list '{$f$[$a$], ..., $f$[$a$ + $n$]}'. -
    'Array[$f$, {$n$, $m$}, {$a$, $b$}]' +
    'Array'[$f$, {$n$, $m$}, {$a$, $b$}]
    returns an $n$-by-$m$ matrix created by applying $f$ to indices \ ranging from '($a$, $b$)' to '($a$ + $n$, $b$ + $m$)'. -
    'Array[$f$, $dims$, $origins$, $h$]' +
    'Array'[$f$, $dims$, $origins$, $h$]
    returns an expression with the specified dimensions and index origins, \ with head $h$ (instead of 'List').
    @@ -117,7 +117,7 @@ class ConstantArray(Builtin): https://reference.wolfram.com/language/ref/ConstantArray.html
    -
    'ConstantArray[$expr$, $n$]' +
    'ConstantArray'[$expr$, $n$]
    returns a list of $n$ copies of $expr$.
    @@ -139,9 +139,9 @@ class List(Builtin): :WMA link:https://reference.wolfram.com/language/ref/List.html
    -
    'List[$e1$, $e2$, ..., $ei$]' -
    '{$e1$, $e2$, ..., $ei$}' -
    represents a list containing the elements $e1$...$ei$. +
    'List'[$e_1$, $e_2$, ..., $ei$] +
    '{$e_1$, $e_2$, ..., $ei$}' +
    represents a list containing the elements $e_1$...$ei$.
    'List' is the head of lists: @@ -219,13 +219,13 @@ class Range(Builtin): https://reference.wolfram.com/language/ref/Range.html
    -
    'Range[$n$]' +
    'Range'[$n$]
    returns a list of integers from 1 to $n$. -
    'Range[$a$, $b$]' +
    'Range'[$a$, $b$]
    returns a list of (Integer, Rational, Real) numbers from $a$ to $b$. -
    'Range[$a$, $b$, $di$]' +
    'Range'[$a$, $b$, $di$]
    returns a list of numbers from $a$ to $b$ using step $di$. More specifically, 'Range' starts from $a$ and successively adds \ increments of $di$ until the result is greater (if $di$ > 0) or \ @@ -309,13 +309,13 @@ class Permutations(Builtin): https://reference.wolfram.com/language/ref/Permutations.html
    -
    'Permutations[$list$]' +
    'Permutations'[$list$]
    gives all possible orderings of the items in $list$. -
    'Permutations[$list$, $n$]' +
    'Permutations'[$list$, $n$]
    gives permutations up to length $n$. -
    'Permutations[$list$, {$n$}]' +
    'Permutations'[$list$, {$n$}]
    gives permutations of length $n$.
    @@ -390,21 +390,21 @@ class Reap(Builtin): https://reference.wolfram.com/language/ref/Reap.html
    -
    'Reap[$expr$]' +
    'Reap'[$expr$]
    gives the result of evaluating $expr$, together with all values \ sown during this evaluation. Values sown with different tags \ are given in different lists. -
    'Reap[$expr$, $pattern$]' +
    'Reap'[$expr$, $pattern$]
    only yields values sown with a tag matching $pattern$. 'Reap[$expr$]' is equivalent to 'Reap[$expr$, _]'. -
    'Reap[$expr$, {$pattern1$, $pattern2$, ...}]' +
    'Reap'[$expr$, {$pattern_1$, $pattern_2$, ...}]
    uses multiple patterns. -
    'Reap[$expr$, $pattern$, $f$]' +
    'Reap'[$expr$, $pattern$, $f$]
    applies $f$ on each tag and the corresponding values sown \ - in the form '$f$[tag, {e1, e2, ...}]'. + in the form '$f$[$tag$, {$e_1$, $e_2$, ...}]'.
    >> Reap[Sow[3]; Sow[1]] @@ -481,13 +481,13 @@ class Sow(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Sow.html
    -
    'Sow[$e$]' +
    'Sow'[$e$]
    sends the value $e$ to the innermost 'Reap'. -
    'Sow[$e$, $tag$]' +
    'Sow'[$e$, $tag$]
    sows $e$ using $tag$. 'Sow[$e$]' is equivalent to 'Sow[$e$, Null]'. -
    'Sow[$e$, {$tag1$, $tag2$, ...}]' +
    'Sow'[$e$, {$tag_1$, $tag_2$, ...}]
    uses multiple tags.
    """ @@ -514,18 +514,18 @@ class Table(IterationFunction): https://reference.wolfram.com/language/ref/Table.html
    -
    'Table[$expr$, $n$]' +
    'Table'[$expr$, $n$]
    generates a list of $n$ copies of $expr$. -
    'Table[$expr$, {$i$, $n$}]' +
    'Table'[$expr$, {$i$, $n$}]
    generates a list of the values of expr when $i$ runs from 1 to $n$. -
    'Table[$expr$, {$i$, $start$, $stop$, $step$}]' +
    'Table'[$expr$, {$i$, $start$, $stop$, $step$}]
    evaluates $expr$ with $i$ ranging from $start$ to $stop$, \ incrementing by $step$. -
    'Table[$expr$, {$i$, {$e1$, $e2$, ..., $ei$}}]' -
    evaluates $expr$ with $i$ taking on the values $e1$, $e2$, \ +
    'Table'[$expr$, {$i$, {$e_1$, $e_2$, ..., $ei$}}] +
    evaluates $expr$ with $i$ taking on the values $e_1$, $e_2$, \ ..., $ei$.
    @@ -576,10 +576,10 @@ class Tuples(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Tuples.html
    -
    'Tuples[$list$, $n$]' +
    'Tuples'[$list$, $n$]
    returns a list of all $n$-tuples of elements in $list$. -
    'Tuples[{$list1$, $list2$, ...}]' +
    'Tuples'[{$list_1$, $list_2$, ...}]
    returns a list of tuples with elements from the given lists.
    diff --git a/mathics/builtin/list/eol.py b/mathics/builtin/list/eol.py index c9b778f29..c4dab5bc8 100644 --- a/mathics/builtin/list/eol.py +++ b/mathics/builtin/list/eol.py @@ -73,7 +73,7 @@ class Append(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Append.html
    -
    'Append[$expr$, $elem$]' +
    'Append'[$expr$, $elem$]
    returns $expr$ with $elem$ appended.
    @@ -114,7 +114,7 @@ class AppendTo(Builtin): https://reference.wolfram.com/language/ref/AppendTo.html
    -
    'AppendTo[$s$, $elem$]' +
    'AppendTo'[$s$, $elem$]
    append $elem$ to value of $s$ and sets $s$ to the result.
    @@ -159,13 +159,13 @@ class Cases(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Cases.html
    -
    'Cases[$list$, $pattern$]' +
    'Cases'[$list$, $pattern$]
    returns the elements of $list$ that match $pattern$. -
    'Cases[$list$, $pattern$, $ls$]' +
    'Cases'[$list$, $pattern$, $ls$]
    returns the elements matching at levelspec $ls$. -
    'Cases[$list$, $pattern$, Heads->$bool$]' +
    'Cases'[$list$, $pattern$, Heads->$bool$]
    Match including the head of the expression in the search.
    @@ -181,6 +181,10 @@ class Cases(Builtin): Also include the head of the expression in the previous search: >> Cases[{b, 6, \[Pi]}, _Symbol, Heads -> True] = {List, b, Pi} + + See also + :'MatchQ': + /doc/reference-of-built-in-symbols/testing-expressions/expression-tests/matchq/. """ rules = { @@ -245,10 +249,10 @@ class Count(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Count.html
    -
    'Count[$list$, $pattern$]' +
    'Count'[$list$, $pattern$]
    returns the number of times $pattern$ appears in $list$. -
    'Count[$list$, $pattern$, $ls$]' +
    'Count'[$list$, $pattern$, $ls$]
    counts the elements matching at levelspec $ls$.
    @@ -273,11 +277,11 @@ class Delete(Builtin): https://reference.wolfram.com/language/ref/Delete.html
    -
    'Delete[$expr$, $i$]' +
    'Delete'[$expr$, $i$]
    deletes the element at position $i$ in $expr$. The position is counted from the end if $i$ is negative. -
    'Delete[$expr$, {$m$, $n$, ...}]' +
    'Delete'[$expr$, {$m$, $n$, ...}]
    deletes the element at position {$m$, $n$, ...}. -
    'Delete[$expr$, {{$m1$, $n1$, ...}, {$m2$, $n2$, ...}, ...}]' +
    'Delete'[$expr$, {{$m_1$, $n_1$, ...}, {$m_2$, $n_2$, ...}, ...}]
    deletes the elements at several positions.
    @@ -420,13 +424,13 @@ class DeleteCases(Builtin): :WMA link:https://reference.wolfram.com/language/ref/DeleteCases.html
    -
    'DeleteCases[$list$, $pattern$]' +
    'DeleteCases'[$list$, $pattern$]
    returns the elements of $list$ that do not match $pattern$. -
    'DeleteCases[$list$, $pattern$, $levelspec$]' -
    removes all parts of $list on levels specified by $levelspec$ that match pattern (not fully implemented). +
    'DeleteCases'[$list$, $pattern$, $levelspec$] +
    removes all parts of $list$ on levels specified by $levelspec$ that match pattern (not fully implemented). -
    'DeleteCases[$list$, $pattern$, $levelspec$, $n$]' +
    'DeleteCases'[$list$, $pattern$, $levelspec$, $n$]
    removes the first $n$ parts of $list$ that match $pattern$.
    @@ -524,11 +528,11 @@ class Drop(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Drop.html
    -
    'Drop[$list$, $n$]' +
    'Drop'[$list$, $n$]
    returns $list$ with the first $n$ elements removed. -
    'Drop[$list$, -$n$]' +
    'Drop'[$list$, -$n$]
    returns $list$ with its last $n$ elements removed. -
    'Drop[$list$, {$m$, $n$}]' +
    'Drop'[$list$, {$m$, $n$}]
    returns $list$ with elements $m$ though $n$ removed.
    @@ -598,10 +602,10 @@ class Extract(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Extract.html
    -
    'Extract[$expr$, $list$]' +
    'Extract'[$expr$, $list$]
    extracts parts of $expr$ specified by $list$. -
    'Extract[$expr$, {$list1$, $list2$, ...}]' +
    'Extract'[$expr$, {$list_1$, $list_2$, ...}]
    extracts a list of parts.
    @@ -628,10 +632,10 @@ class First(Builtin): https://reference.wolfram.com/language/ref/First.html
    -
    'First[$expr$]' +
    'First'[$expr$]
    returns the first element in $expr$. -
    'First[$expr$, $def$]' +
    'First'[$expr$, $def$]
    returns the first element in $expr$ if it exists or $def$ otherwise.
    @@ -705,10 +709,10 @@ class FirstCase(Builtin): https://reference.wolfram.com/language/ref/FirstCase.html
    -
    FirstCase[{$e1$, $e2$, ...}, $pattern$] +
    FirstCase[{$e_1$, $e_2$, ...}, $pattern$]
    gives the first $ei$ to match $pattern$, or $Missing[\"NotFound\"]$ if none matching pattern is found. -
    FirstCase[{$e1$,$e2$, ...}, $pattern$ -> $rhs$] +
    FirstCase[{$e_1$,$e_2$, ...}, $pattern$ -> $rhs$]
    gives the value of $rhs$ corresponding to the first $ei$ to match pattern.
    FirstCase[$expr$, $pattern$, $default$]
    gives $default$ if no element matching $pattern$ is found. @@ -738,13 +742,13 @@ class FirstPosition(Builtin): https://reference.wolfram.com/language/ref/FirstPosition.html
    -
    'FirstPosition[$expr$, $pattern$]' +
    'FirstPosition'[$expr$, $pattern$]
    gives the position of the first element in $expr$ that matches $pattern$, or Missing["NotFound"] if no such element is found. -
    'FirstPosition[$expr$, $pattern$, $default$]' +
    'FirstPosition'[$expr$, $pattern$, $default$]
    gives default if no element matching $pattern$ is found. -
    'FirstPosition[$expr$, $pattern$, $default$, $levelspec$]' +
    'FirstPosition'[$expr$, $pattern$, $default$, $levelspec$]
    finds only objects that appear on levels specified by $levelspec$.
    @@ -871,7 +875,7 @@ class Insert(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Insert.html
    -
    'Insert[$list$, $elem$, $n$]' +
    'Insert'[$list$, $elem$, $n$]
    inserts $elem$ at position $n$ in $list$. When $n$ is negative, \ the position is counted from the end.
    @@ -901,10 +905,10 @@ class Last(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Last.html
    -
    'Last[$expr$]' +
    'Last'[$expr$]
    returns the last element in $expr$. -
    'Last[$expr$, $def$]' +
    'Last'[$expr$, $def$]
    returns the last element in $expr$ if it exists or $def$ otherwise.
    @@ -969,7 +973,7 @@ class Length(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Length.html
    -
    'Length[$expr$]' +
    'Length'[$expr$]
    returns the number of elements in $expr$.
    @@ -1013,7 +1017,7 @@ class Most(Builtin): https://reference.wolfram.com/language/ref/Most.html
    -
    'Most[$expr$]' +
    'Most'[$expr$]
    returns $expr$ with the last element removed.
    @@ -1044,7 +1048,7 @@ class Part(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Part.html
    -
    'Part[$expr$, $i$]' +
    'Part'[$expr$, $i$]
    returns part $i$ of $expr$.
    @@ -1194,10 +1198,10 @@ class Pick(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Pick.html
    -
    'Pick[$list$, $sel$]' +
    'Pick'[$list$, $sel$]
    returns those items in $list$ that are True in $sel$. -
    'Pick[$list$, $sel$, $patt$]' +
    'Pick'[$list$, $sel$, $patt$]
    returns those items in $list$ that match $patt$ in $sel$.
    @@ -1245,10 +1249,10 @@ class Position(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Position.html
    -
    'Position[$expr$, $patt$]' +
    'Position'[$expr$, $patt$]
    returns the list of positions for which $expr$ matches $patt$. -
    'Position[$expr$, $patt$, $ls$]' +
    'Position'[$expr$, $patt$, $ls$]
    returns the positions on levels specified by levelspec $ls$.
    @@ -1314,10 +1318,10 @@ class Prepend(Builtin): https://reference.wolfram.com/language/ref/Prepend.html
    -
    'Prepend[$expr$, $item$]' +
    'Prepend'[$expr$, $item$]
    returns $expr$ with $item$ prepended to its elements. -
    'Prepend[$expr$]' +
    'Prepend'[$expr$]
    'Prepend[$elem$][$expr$]' is equivalent to 'Prepend[$expr$,$elem$]'.
    @@ -1359,7 +1363,7 @@ class PrependTo(Builtin): :WMA link:https://reference.wolfram.com/language/ref/PrependTo.html
    -
    'PrependTo[$s$, $item$]' +
    'PrependTo'[$s$, $item$]
    prepends $item$ to value of $s$ and sets $s$ to the result.
    @@ -1410,11 +1414,11 @@ class ReplacePart(Builtin): :WMA link:https://reference.wolfram.com/language/ref/ReplacePart.html
    -
    'ReplacePart[$expr$, $i$ -> $new$]' +
    'ReplacePart'[$expr$, $i$ -> $new$]
    replaces part $i$ in $expr$ with $new$. -
    'ReplacePart[$expr$, {{$i$, $j$} -> $e1$, {$k$, $l$} -> $e2$}]' -
    replaces parts $i$ and $j$ with $e1$, and parts $k$ and $l$ with $e2$. +
    'ReplacePart'[$expr$, {{$i$, $j$} -> $e_1$, {$k$, $l$} -> $e_2$}] +
    replaces parts $i$ and $j$ with $e_1$, and parts $k$ and $l$ with $e_2$.
    >> ReplacePart[{a, b, c}, 1 -> t] @@ -1502,7 +1506,7 @@ class Rest(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Rest.html
    -
    'Rest[$expr$]' +
    'Rest'[$expr$]
    returns $expr$ with the first element removed.
    @@ -1543,9 +1547,9 @@ class Select(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Select.html
    -
    'Select[{$e1$, $e2$, ...}, $crit$]' +
    'Select'[{$e_1$, $e_2$, ...}, $crit$]
    returns a list of the elements $ei$ for which $crit$[$ei$] is 'True'. -
    'Select[{$e1$, $e2$, ...}, $crit$, n]' +
    'Select'[{$e_1$, $e_2$, ...}, $crit$, n]
    returns a list of the first $n$ elements $ei$ for which $crit$[$ei$] is 'True'.
    @@ -1632,11 +1636,11 @@ class Take(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Take.html
    -
    'Take[$expr$, $n$]' +
    'Take'[$expr$, $n$]
    returns $expr$ with all but the first $n$ elements removed. -
    'Take[$list$, -$n$]' +
    'Take'[$list$, -$n$]
    returns last $n$ elements of $list$. -
    'Take[$list$, {$m$, $n$}]' +
    'Take'[$list$, {$m$, $n$}]
    returns elements $m$ through $n$ of $list$.
    diff --git a/mathics/builtin/list/math.py b/mathics/builtin/list/math.py index a0452d37d..8f1d84c10 100644 --- a/mathics/builtin/list/math.py +++ b/mathics/builtin/list/math.py @@ -128,7 +128,7 @@ class TakeLargestBy(_RankedTakeLargest): :WMA link:https://reference.wolfram.com/language/ref/TakeLargestBy.html
    -
    'TakeLargestBy[$list$, $f$, $n$]' +
    'TakeLargestBy'[$list$, $f$, $n$]
    returns the a sorted list of the $n$ largest items in $list$ using $f$ to retrieve the items' keys to compare them.
    @@ -155,7 +155,7 @@ class TakeSmallestBy(_RankedTakeSmallest): https://reference.wolfram.com/language/ref/TakeSmallestBy.html
    -
    'TakeSmallestBy[$list$, $f$, $n$]' +
    'TakeSmallestBy'[$list$, $f$, $n$]
    returns the a sorted list of the $n$ smallest items in $list$ using $f$ to retrieve the items' keys to compare them.
    diff --git a/mathics/builtin/list/predicates.py b/mathics/builtin/list/predicates.py index d45f52fbb..f7b3a6b84 100644 --- a/mathics/builtin/list/predicates.py +++ b/mathics/builtin/list/predicates.py @@ -18,8 +18,8 @@ class ContainsOnly(Builtin): https://reference.wolfram.com/language/ref/ContainsOnly.html
    -
    'ContainsOnly[$list1$, $list2$]' -
    yields True if $list1$ contains only elements that appear in $list2$. +
    'ContainsOnly'[$list_1$, $list_2$] +
    yields True if $list_1$ contains only elements that appear in $list_2$.
    >> ContainsOnly[{b, a, a}, {a, b, c}] diff --git a/mathics/builtin/list/rearrange.py b/mathics/builtin/list/rearrange.py index 683ec4cf6..34aa11475 100644 --- a/mathics/builtin/list/rearrange.py +++ b/mathics/builtin/list/rearrange.py @@ -6,12 +6,18 @@ """ import functools +from abc import ABC from collections import defaultdict from itertools import chain from typing import Callable, Optional from mathics.core.atoms import Integer, Integer0, Integer1, Number -from mathics.core.attributes import A_FLAT, A_ONE_IDENTITY, A_PROTECTED +from mathics.core.attributes import ( + A_FLAT, + A_ONE_IDENTITY, + A_PROTECTED, + A_READ_PROTECTED, +) from mathics.core.builtin import Builtin, MessageException from mathics.core.element import BaseElement from mathics.core.evaluation import Evaluation @@ -19,7 +25,12 @@ from mathics.core.expression_predefined import MATHICS3_INFINITY from mathics.core.list import ListExpression from mathics.core.symbols import Atom, Symbol, SymbolTrue -from mathics.core.systemsymbols import SymbolMap, SymbolReverse, SymbolSplit +from mathics.core.systemsymbols import ( + SymbolMap, + SymbolReverse, + SymbolSameQ, + SymbolSplit, +) from mathics.eval.parts import walk_levels @@ -37,7 +48,7 @@ def _test_pair(test, a, b, evaluation, name): def _is_sameq(same_test): # System`SameQ is protected, so nobody should ever be able to change # it (see Set::wrsym). We just check for its name here thus. - return isinstance(same_test, Symbol) and same_test.get_name() == "System`SameQ" + return same_test is SymbolSameQ class _FastEquivalence: @@ -394,7 +405,7 @@ def eval(self, expr, n, evaluation: Evaluation): return self._rotate(expr, py_cycles, evaluation) -class _SetOperation(Builtin): +class _SetOperation(Builtin, ABC): messages = { "heads": ( "Heads `1` and `2` at positions `3` and `4` are expected " "to be the same." @@ -419,8 +430,12 @@ def _remove_duplicates(arg, same_test): result.append(a) return result - def eval(self, lists, evaluation, options={}): - "%(name)s[lists__, OptionsPattern[%(name)s]]" + def eval_empty(self, lists, evaluation): + "%(name)s[lists__]" + return self.eval(lists, evaluation, SymbolSameQ) + + def eval(self, lists, evaluation, sametest): + "%(name)s[lists__, SameTest->sametest_]" seq = lists.get_sequence() @@ -442,12 +457,11 @@ def eval(self, lists, evaluation, options={}): ) return - same_test = self.get_option(options, "SameTest", evaluation) operands = [li.elements for li in seq] - if not _is_sameq(same_test): + if not _is_sameq(sametest): def sameQ(a, b): - return _test_pair(same_test, a, b, evaluation, self.get_name()) + return _test_pair(sametest, a, b, evaluation, self.get_name()) operands = [self._remove_duplicates(op, sameQ) for op in operands] items = functools.reduce( @@ -478,8 +492,8 @@ class Catenate(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Catenate.html
    -
    'Catenate[{$l1$, $l2$, ...}]' -
    concatenates the lists $l1$, $l2$, ... +
    'Catenate'[{$l_1$, $l_2$, ...}] +
    concatenates the lists $l_1$, $l_2$, ...
    >> Catenate[{{1, 2, 3}, {4, 5}}] @@ -519,16 +533,16 @@ class Complement(_SetOperation): https://reference.wolfram.com/language/ref/Complement.html
    -
    'Complement[$all$, $e1$, $e2$, ...]' +
    'Complement'[$all$, $e_1$, $e_2$, ...]
    returns an expression containing the elements in the set $all$ \ - that are not in any of $e1$, $e2$, etc. + that are not in any of $e_1$, $e_2$, etc. -
    'Complement[$all$, $e1$, $e2$, ..., SameTest->$test$]' +
    'Complement'[$all$, $e_1$, $e_2$, ..., SameTest->$test$]
    applies $test$ to the elements in $all$ and each of the $ei$ to \ determine equality.
    - The sets $all$, $e1$, etc can have any head, which must all match. + The sets $all$, $e_1$, etc can have any head, which must all match. The returned expression has the same head as the input \ expressions. The expression will be sorted and each element will \ @@ -560,10 +574,10 @@ class DeleteDuplicates(_GatherOperation): https://reference.wolfram.com/language/ref/DeleteDuplicates.html
    -
    'DeleteDuplicates[$list$]' +
    'DeleteDuplicates'[$list$]
    deletes duplicates from $list$. -
    'DeleteDuplicates[$list$, $test$]' +
    'DeleteDuplicates'[$list$, $test$]
    deletes elements from $list$ based on whether the function $test$ yields \ 'True' on pairs of elements. @@ -588,10 +602,10 @@ class Gather(_GatherOperation): https://reference.wolfram.com/language/ref/Gather.html
    -
    'Gather[$list$, $test$]' +
    'Gather'[$list$, $test$]
    gathers elements of $list$ into sub lists of items that are the same according to $test$. -
    'Gather[$list$]' +
    'Gather'[$list$]
    gathers elements of $list$ into sub lists of items that are the same.
    @@ -615,13 +629,13 @@ class Flatten(Builtin): https://reference.wolfram.com/language/ref/Flatten.html
    -
    'Flatten[$expr$]' +
    'Flatten'[$expr$]
    flattens out nested lists in $expr$. -
    'Flatten[$expr$, $n$]' +
    'Flatten'[$expr$, $n$]
    stops flattening at level $n$. -
    'Flatten[$expr$, $n$, $h$]' +
    'Flatten'[$expr$, $n$, $h$]
    flattens expressions with head $h$ instead of 'List'.
    @@ -668,19 +682,21 @@ def eval_list(self, expr, n, h, evaluation): # prepare levels # find max depth which matches `h` expr, max_depth = walk_levels(expr) - max_depth = {"max_depth": max_depth} # hack to modify max_depth from callback + max_depth_dict = { + "max_depth": max_depth + } # hack to modify max_depth from callback def callback(expr, pos): - if len(pos) < max_depth["max_depth"] and ( + if len(pos) < max_depth_dict["max_depth"] and ( isinstance(expr, Atom) or expr.head != h ): - max_depth["max_depth"] = len(pos) + max_depth_dict["max_depth"] = len(pos) return expr - expr, depth = walk_levels(expr, callback=callback, include_pos=True, start=0) - max_depth = max_depth["max_depth"] + expr, _ = walk_levels(expr, callback=callback, include_pos=True, start=0) + max_depth = max_depth_dict["max_depth"] - levels = n.to_python() + levels = list(n.to_python()) # mappings if isinstance(levels, list) and all(isinstance(level, int) for level in levels): @@ -692,7 +708,7 @@ def callback(expr, pos): return seen_levels = [] for level in levels: - if not (isinstance(level, list) and len(level) > 0): + if not (isinstance(level, (list, tuple)) and len(level) > 0): evaluation.message("Flatten", "flpi", n) return for r in level: @@ -785,14 +801,14 @@ class GatherBy(_GatherOperation): https://reference.wolfram.com/language/ref/GatherBy.html
    -
    'GatherBy[$list$, $f$]' +
    'GatherBy'[$list$, $f$]
    gathers elements of $list$ into sub lists of items whose image \ under $f$ identical. -
    'GatherBy[$list$, {$f$, $g$, ...}]' +
    'GatherBy'[$list$, {$f$, $g$, ...}]
    gathers elements of $list$ into sub lists of items whose image \ under $f$ identical. Then, gathers these sub lists again into sub \ - sub lists, that are identical under $g. + sub lists, that are identical under $g$.
    >> GatherBy[{{1, 3}, {2, 2}, {1, 1}}, Total] @@ -837,8 +853,8 @@ class Join(Builtin): https://reference.wolfram.com/language/ref/Join.html
    -
    'Join[$l1$, $l2$]' -
    concatenates the lists $l1$ and $l2$. +
    'Join'[$l_1$, $l_2$] +
    concatenates the lists $l_1$ and $l_2$.
    'Join' concatenates lists: @@ -887,18 +903,18 @@ class PadLeft(_Pad): :WMA link:https://reference.wolfram.com/language/ref/PadLeft.html
    -
    'PadLeft[$list$, $n$]' +
    'PadLeft'[$list$, $n$]
    pads $list$ to length $n$ by adding 0 on the left. -
    'PadLeft[$list$, $n$, $x$]' +
    'PadLeft'[$list$, $n$, $x$]
    pads $list$ to length $n$ by adding $x$ on the left. -
    'PadLeft[$list$, {$n1$, $n2, ...}, $x$]' -
    pads $list$ to lengths $n1$, $n2$ at levels 1, 2, ... respectively by adding $x$ on the left. -
    'PadLeft[$list$, $n$, $x$, $m$]' +
    'PadLeft'[$list$, {$n_1$, $n_2$, ...}, $x$] +
    pads $list$ to lengths $n_1$, $n_2$ at levels 1, 2, ... respectively by adding $x$ on the left. +
    'PadLeft'[$list$, $n$, $x$, $m$]
    pads $list$ to length $n$ by adding $x$ on the left and adding a margin of $m$ on the right. -
    'PadLeft[$list$, $n$, $x$, {$m1$, $m2$, ...}]' -
    pads $list$ to length $n$ by adding $x$ on the left and adding margins of $m1$, $m2$, ... +
    'PadLeft'[$list$, $n$, $x$, {$m_1$, $m_2$, ...}] +
    pads $list$ to length $n$ by adding $x$ on the left and adding margins of $m_1$, $m_2$, ... on levels 1, 2, ... on the right. -
    'PadLeft[$list$]' +
    'PadLeft'[$list$]
    turns the ragged list $list$ into a regular list by adding 0 on the left.
    @@ -925,18 +941,18 @@ class PadRight(_Pad): :WMA link:https://reference.wolfram.com/language/ref/PadRight.html
    -
    'PadRight[$list$, $n$]' +
    'PadRight'[$list$, $n$]
    pads $list$ to length $n$ by adding 0 on the right. -
    'PadRight[$list$, $n$, $x$]' +
    'PadRight'[$list$, $n$, $x$]
    pads $list$ to length $n$ by adding $x$ on the right. -
    'PadRight[$list$, {$n1$, $n2, ...}, $x$]' -
    pads $list$ to lengths $n1$, $n2$ at levels 1, 2, ... respectively by adding $x$ on the right. -
    'PadRight[$list$, $n$, $x$, $m$]' +
    'PadRight'[$list$, {$n_1$, $n_2$, ...}, $x$] +
    pads $list$ to lengths $n_1$, $n_2$ at levels 1, 2, ... respectively by adding $x$ on the right. +
    'PadRight'[$list$, $n$, $x$, $m$]
    pads $list$ to length $n$ by adding $x$ on the left and adding a margin of $m$ on the left. -
    'PadRight[$list$, $n$, $x$, {$m1$, $m2$, ...}]' -
    pads $list$ to length $n$ by adding $x$ on the right and adding margins of $m1$, $m2$, ... +
    'PadRight'[$list$, $n$, $x$, {$m_1$, $m_2$, ...}] +
    pads $list$ to length $n$ by adding $x$ on the right and adding margins of $m_1$, $m_2$, ... on levels 1, 2, ... on the left. -
    'PadRight[$list$]' +
    'PadRight'[$list$]
    turns the ragged list $list$ into a regular list by adding 0 on the right.
    @@ -965,10 +981,10 @@ class Partition(Builtin): https://reference.wolfram.com/language/ref/Partition.html
    -
    'Partition[$list$, $n$]' +
    'Partition'[$list$, $n$]
    partitions $list$ into sublists of length $n$. -
    'Partition[$list$, $n$, $d$]' +
    'Partition'[$list$, $n$, $d$]
    partitions $list$ into sublists of length $n$ which overlap $d$ \ indices.
    @@ -1029,14 +1045,14 @@ class Reverse(Builtin): https://reference.wolfram.com/language/ref/Reverse.html
    -
    'Reverse[$expr$]' +
    'Reverse'[$expr$]
    reverses the order of $expr$'s items (on the top level) -
    'Reverse[$expr$, $n$]' +
    'Reverse'[$expr$, $n$]
    reverses the order of items in $expr$ on level $n$ -
    'Reverse[$expr$, {$n1$, $n2$, ...}]' -
    reverses the order of items in $expr$ on levels $n1$, $n2$, ... +
    'Reverse'[$expr$, {$n_1$, $n_2$, ...}] +
    reverses the order of items in $expr$ on levels $n_1$, $n_2$, ...
    >> Reverse[{1, 2, 3}] @@ -1136,11 +1152,11 @@ class Riffle(Builtin): https://reference.wolfram.com/language/ref/Riffle.html
    -
    'Riffle[$list$, $x$]' +
    'Riffle'[$list$, $x$]
    inserts a copy of $x$ between each element of $list$. -
    'Riffle[{$a1$, $a2$, ...}, {$b1$, $b2$, ...}]' -
    interelements the elements of both lists, returning '{$a1$, $b1$, $a2$, $b2$, ...}'. +
    'Riffle'[{$a_1$, $a_2$, ...}, {$b_1$, $b_2$, ...}] +
    interelements the elements of both lists, returning '{$a_1$, $b_1$, $a_2$, $b_2$, ...}'.
    >> Riffle[{a, b, c}, x] @@ -1171,15 +1187,15 @@ class RotateLeft(_Rotate): https://reference.wolfram.com/language/ref/RotateLeft.html
    -
    'RotateLeft[$expr$]' +
    'RotateLeft'[$expr$]
    rotates the items of $expr$' by one item to the left. -
    'RotateLeft[$expr$, $n$]' +
    'RotateLeft'[$expr$, $n$]
    rotates the items of $expr$' by $n$ items to the left. -
    'RotateLeft[$expr$, {$n1$, $n2$, ...}]' -
    rotates the items of $expr$' by $n1$ items to the left at \ - the first level, by $n2$ items to the left at the second level, and so on. +
    'RotateLeft'[$expr$, {$n_1$, $n_2$, ...}] +
    rotates the items of $expr$' by $n_1$ items to the left at \ + the first level, by $n_2$ items to the left at the second level, and so on.
    >> RotateLeft[{1, 2, 3}] @@ -1203,14 +1219,14 @@ class RotateRight(_Rotate): https://reference.wolfram.com/language/ref/RotateRight.html
    -
    'RotateRight[$expr$]' +
    'RotateRight'[$expr$]
    rotates the items of $expr$' by one item to the right. -
    'RotateRight[$expr$, $n$]' +
    'RotateRight'[$expr$, $n$]
    rotates the items of $expr$' by $n$ items to the right. -
    'RotateRight[$expr$, {$n1$, $n2$, ...}]' -
    rotates the items of $expr$' by $n1$ items to the right at the first level, by $n2$ items to the right at the second level, and so on. +
    'RotateRight'[$expr$, {$n_1$, $n_2$, ...}] +
    rotates the items of $expr$' by $n_1$ items to the right at the first level, by $n_2$ items to the right at the second level, and so on.
    >> RotateRight[{1, 2, 3}] @@ -1232,9 +1248,9 @@ class Split(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Split.html
    -
    'Split[$list$]' +
    'Split'[$list$]
    splits $list$ into collections of consecutive identical elements. -
    'Split[$list$, $test$]' +
    'Split'[$list$, $test$]
    splits $list$ based on whether the function $test$ yields 'True' on consecutive elements.
    @@ -1292,7 +1308,7 @@ class SplitBy(Builtin): https://reference.wolfram.com/language/ref/SplitBy.html
    -
    'SplitBy[$list$, $f$]' +
    'SplitBy'[$list$, $f$]
    splits $list$ into collections of consecutive elements that give the same result when $f$ is applied.
    @@ -1355,12 +1371,12 @@ class Tally(_GatherOperation): :WMA link:https://reference.wolfram.com/language/ref/Tally.html
    -
    'Tally[$list$]' +
    'Tally'[$list$]
    counts and returns the number of occurrences of objects and returns \ the result as a list of pairs {object, count}. -
    'Tally[$list$, $test$]' -
    counts the number of occurrences of objects and uses $test to \ +
    'Tally'[$list$, $test$] +
    counts the number of occurrences of objects and uses $test$ to \ determine if two objects should be counted in the same bin.
    @@ -1383,20 +1399,28 @@ class Union(_SetOperation): https://reference.wolfram.com/language/ref/Union.html
    -
    'Union[$a$, $b$, ...]' +
    'Union'[$a$, $b$, ...]
    gives the union of the given set or sets. The resulting list \ will be sorted and each element will only occur once.
    - >> Union[{5, 1, 3, 7, 1, 8, 3}] - = {1, 3, 5, 7, 8} - + A union of two lists: >> Union[{a, b, c}, {c, d, e}] = {a, b, c, d, e} + A union of two associations: + >> Union[{a -> b}, {c -> d}] + = {a -> b, c -> d} + + A union of one item is the item. Note that the list is sorted: >> Union[{c, b, a}] = {a, b, c} + As usual, 'Union' removes duplicate values: + >> Union[{5, 1, 3, 7, 1, 8, 3}] + = {1, 3, 5, 7, 8} + + 'Union' using a custom test which compares using the last coordinate of each element list: >> Union[{{a, 1}, {b, 2}}, {{c, 1}, {d, 3}}, SameTest->(SameQ[Last[#1],Last[#2]]&)] = {{b, 2}, {c, 1}, {d, 3}} @@ -1404,7 +1428,13 @@ class Union(_SetOperation): = {1, 2, 2, 3, 4} """ - summary_text = "enumerate all distinct elements in a list" + # FIXME: WMA add the A_FLAT attribute, but that messes up function parsing. + # In particular: + # Union[{1, -1, 2}, {-2, 3}, SameTest -> (Abs[#1] == Abs[#2] &)] + # is parsed/passed as + # Union[{1, -1, 2}, SameTest -> (Abs[#1] == Abs[#2] &)] + attributes = A_ONE_IDENTITY | A_PROTECTED | A_READ_PROTECTED + summary_text = "union distinct elements of list(s) or association(s)" _operation = "union" def _elementwise(self, a, b, sameQ: Callable[..., bool]): @@ -1422,7 +1452,7 @@ class Intersection(_SetOperation): https://reference.wolfram.com/language/ref/Intersection.html
    -
    'Intersection[$a$, $b$, ...]' +
    'Intersection'[$a$, $b$, ...]
    gives the intersection of the sets. The resulting list \ will be sorted and each element will only occur once.
    diff --git a/mathics/builtin/mainloop.py b/mathics/builtin/mainloop.py index 49548b498..0263ffa7c 100644 --- a/mathics/builtin/mainloop.py +++ b/mathics/builtin/mainloop.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -""" +r""" The Main Loop An interactive session operates a loop, called the "main loop" in this way: @@ -16,10 +16,10 @@ There are a variety of "hooks" that allow you to insert functions to be applied to the expressions at various stages \ in the main loop. -If you assign a function to the global variable '$PreRead' it will be applied with the input that is read in the first \ +If you assign a function to the global variable '\$PreRead' it will be applied with the input that is read in the first \ step listed above. -Similarly, if you assign a function to global variable '$Pre', it will be applied with the input before processing the \ +Similarly, if you assign a function to global variable '\$Pre', it will be applied with the input before processing the \ input, the second step listed above. """ @@ -31,10 +31,10 @@ class HistoryLength(Builtin): - """ + r""" :WMA: https://reference.wolfram.com/language/ref/$HistoryLength
    -
    '$HistoryLength' +
    '\$HistoryLength'
    specifies the maximum number of 'In' and 'Out' entries.
    @@ -66,8 +66,8 @@ class In(Builtin): """ :WMA: https://reference.wolfram.com/language/ref/In
    -
    'In[$k$]' -
    gives the $k$th line of input. +
    'In'[$k$] +
    gives the $k$-th line of input.
    >> x = 1 @@ -104,10 +104,10 @@ class In(Builtin): class IOHookPreRead(Builtin): - """ - :WMA: https://reference.wolfram.com/language/ref/$PreRead + r""" + :WMA: https://reference.wolfram.com/language/ref/\$PreRead
    -
    $PreRead +
    \$PreRead
    is a global variable whose value, if set, is applied to the \ text or box form of every input expression before it is fed to the parser. @@ -123,15 +123,15 @@ class IOHookPreRead(Builtin): class IOHookPre(Builtin): - """ - :WMA: https://reference.wolfram.com/language/ref/$Pre + r""" + :WMA: https://reference.wolfram.com/language/ref/\$Pre
    -
    $Pre +
    '\$Pre'
    is a global variable whose value, if set, is applied to every input expression.
    - Set $Timing$ as the $Pre function, stores the elapsed time in a variable, - stores just the result in Out[$Line] and print a formatted version showing the elapsed time + Set 'Timing' as the '\$Pre' function, stores the elapsed time in a variable, + stores just the result in 'Out[\$Line]' and print a formatted version showing the elapsed time >> $Pre := (Print["[Processing input...]"];#1)& >> $Post := (Print["[Storing result...]"]; #1)& | [Processing input...] @@ -156,10 +156,10 @@ class IOHookPre(Builtin): class IOHookPost(Builtin): - """ - :WMA: https://reference.wolfram.com/language/ref/$Post + r""" + :WMA: https://reference.wolfram.com/language/ref/\$Post
    -
    $Post +
    '\$Post'
    is a global variable whose value, if set, is applied to every output expression.
    """ @@ -170,10 +170,10 @@ class IOHookPost(Builtin): class IOHookPrePrint(Builtin): - """ - :WMA: https://reference.wolfram.com/language/ref/$PrePrint + r""" + :WMA: https://reference.wolfram.com/language/ref/\$PrePrint
    -
    $PrePrint +
    '\$PrePrint'
    is a global variable whose value, if set, is applied to every output expression before it is printed.
    """ @@ -186,10 +186,10 @@ class IOHookPrePrint(Builtin): class IOHookSyntaxHandler(Builtin): - """ - :WMA: https://reference.wolfram.com/language/ref/$SyntaxHandler + r""" + :WMA: https://reference.wolfram.com/language/ref/\$SyntaxHandler
    -
    $SyntaxHandler +
    '\$SyntaxHandler'
    is a global variable whose value, if set, is applied to any input string that is found to contain a syntax \ error. @@ -203,10 +203,10 @@ class IOHookSyntaxHandler(Builtin): class Line(Builtin): - """ + r""" :WMA: https://reference.wolfram.com/language/ref/$Line
    -
    '$Line' +
    '\$Line'
    holds the current input line number.
    diff --git a/mathics/builtin/makeboxes.py b/mathics/builtin/makeboxes.py index 38495f711..cfcdf65c1 100644 --- a/mathics/builtin/makeboxes.py +++ b/mathics/builtin/makeboxes.py @@ -22,12 +22,12 @@ class BoxForms_(Predefined): - """ - :WMA link:https://reference.wolfram.com/language/ref/$BoxForms.html + r""" + :WMA link:https://reference.wolfram.com/language/ref/\$BoxForms.html
    -
    -
    $BoxForms is the list of box formats. +
    '\$BoxForms' +
    contains the list of box formats.
    >> $BoxForms @@ -45,7 +45,7 @@ class MakeBoxes(Builtin): :WMA link:https://reference.wolfram.com/language/ref/MakeBoxes.html
    -
    'MakeBoxes[$expr$]' +
    'MakeBoxes'[$expr$]
    is a low-level formatting primitive that converts $expr$ to box form, without evaluating it.
    '\\( ... \\)' @@ -139,7 +139,7 @@ class ToBoxes(Builtin): https://reference.wolfram.com/language/ref/ToBoxes.html
    -
    'ToBoxes[$expr$]' +
    'ToBoxes'[$expr$]
    evaluates $expr$ and converts the result to box form.
    diff --git a/mathics/builtin/manipulate.py b/mathics/builtin/manipulate.py index 46d6c2054..8fa6b6eb5 100644 --- a/mathics/builtin/manipulate.py +++ b/mathics/builtin/manipulate.py @@ -154,7 +154,7 @@ # def new_callback(**kwargs): # callback( -# **dict((name, parsers[name](value)) for (name, value) in kwargs.items()) +# **dict((name, parsers[name](value)) for name, value in kwargs.items()) # ) # return new_callback @@ -252,22 +252,22 @@ # https://reference.wolfram.com/language/ref/Manipulate.html #
    -#
    'Manipulate[$expr1$, {$u$, $u_min$, $u_max$}]' +#
    'Manipulate'[$expr_1$, {$u$, $u_{min}$, $u_{max}$}] #
    interactively compute and display an expression with different values of $u$. -#
    'Manipulate[$expr1$, {$u$, $u_min$, $u_max$, $du$}]' -#
    allows $u$ to vary between $u_min$ and $u_max$ in steps of $du$. +#
    'Manipulate'[$expr_1$, {$u$, $u_{min}$, $u_{max}$, $du$}] +#
    allows $u$ to vary between $u_{min}$ and $u_{max}$ in steps of $du$. -#
    'Manipulate[$expr1$, {{$u$, $u_init$}, $u_min$, $u_max$, ...}]' +#
    'Manipulate'[$expr_1$, {{$u$, $u_init$}, $u_{min}$, $u_{max}$, ...}] #
    starts with initial value of $u_init$. -#
    'Manipulate[$expr1$, {{$u$, $u_init$, $u_lbl$}, ...}]' +#
    'Manipulate'[$expr_1$, {{$u$, $u_init$, $u_lbl$}, ...}] #
    labels the $u$ control by $u_lbl$. -#
    'Manipulate[$expr1$, {$u$, {$u_1$, $u_2$, ...}}]' +#
    'Manipulate'[$expr_1$, {$u$, {$u_1$, $u_2$, ...}}] #
    sets $u$ to take discrete values $u_1$, $u_2$, ... . -#
    'Manipulate[$expr1$, {$u$, ...}, {$v$, ...}, ...]' +#
    'Manipulate'[$expr_1$, {$u$, ...}, {$v$, ...}, ...] #
    control each of $u$, $v$, ... . #
    diff --git a/mathics/builtin/matrices/constrmatrix.py b/mathics/builtin/matrices/constrmatrix.py index 1bd4600a3..93be9b55b 100644 --- a/mathics/builtin/matrices/constrmatrix.py +++ b/mathics/builtin/matrices/constrmatrix.py @@ -24,7 +24,7 @@ class BoxMatrix(Builtin): https://reference.wolfram.com/language/ref/BoxMatrix.html
    -
    'BoxMatrix[$s]' +
    'BoxMatrix'[$s$]
    Gives a box shaped kernel of size 2 $s$ + 1.
    @@ -55,7 +55,7 @@ class DiagonalMatrix(Builtin): https://reference.wolfram.com/language/ref/DiagonalMatrix.html
    -
    'DiagonalMatrix[$list$]' +
    'DiagonalMatrix'[$list$]
    gives a matrix with the values in $list$ on its diagonal and \ zeroes elsewhere.
    @@ -90,7 +90,7 @@ class DiamondMatrix(Builtin): :WMA link:https://reference.wolfram.com/language/ref/DiamondMatrix.html
    -
    'DiamondMatrix[$s]' +
    'DiamondMatrix'[$s$]
    Gives a diamond shaped kernel of size 2 $s$ + 1.
    @@ -127,7 +127,7 @@ class DiskMatrix(Builtin): :WMA link:https://reference.wolfram.com/language/ref/DiskMatrix.html
    -
    'DiskMatrix[$s]' +
    'DiskMatrix'[$s$]
    Gives a disk shaped kernel of size 2 $s$ + 1.
    @@ -158,7 +158,7 @@ class IdentityMatrix(Builtin): https://reference.wolfram.com/language/ref/IdentityMatrix.html
    -
    'IdentityMatrix[$n$]' +
    'IdentityMatrix'[$n$]
    gives the identity matrix with $n$ rows and columns.
    diff --git a/mathics/builtin/matrices/partmatrix.py b/mathics/builtin/matrices/partmatrix.py index f87a3fe0b..9a9d31e04 100644 --- a/mathics/builtin/matrices/partmatrix.py +++ b/mathics/builtin/matrices/partmatrix.py @@ -18,10 +18,10 @@ class Diagonal(Builtin): https://reference.wolfram.com/language/ref/Diagonal.html
    -
    'Diagonal[$m$]' +
    'Diagonal'[$m$]
    gives a list with the values in the diagonal of the matrix $m$. -
    'Diagonal[$m$, $k$]' +
    'Diagonal'[$m$, $k$]
    gives a list with the values in the $k$ diagonal of the \ matrix $m$.
    diff --git a/mathics/builtin/messages.py b/mathics/builtin/messages.py index d6ae30645..09b82b98e 100644 --- a/mathics/builtin/messages.py +++ b/mathics/builtin/messages.py @@ -2,7 +2,6 @@ Message-related functions. """ - import typing from typing import Any @@ -17,11 +16,11 @@ class Aborted(Predefined): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/Aborted.html
    -
    '$Aborted' +
    '\$Aborted'
    is returned by a calculation that has been aborted.
    """ @@ -38,10 +37,10 @@ class Check(Builtin): https://reference.wolfram.com/language/ref/Check.html
    -
    'Check[$expr$, $failexpr$]' +
    'Check'[$expr$, $failexpr$]
    evaluates $expr$, and returns the result, unless messages were \ generated, in which case it evaluates and $failexpr$ will be returned. -
    'Check[$expr$, $failexpr$, {s1::t1,s2::t2,...}]' +
    'Check'[$expr$, $failexpr$, {s1::t1,s2::t2,...}]
    checks only for the specified messages.
    @@ -79,7 +78,7 @@ def eval_with_fail(self, expr, failexpr, params, evaluation: Evaluation): "Check[expr_, failexpr_, params___]" # Todo: To implement the third form of this function , we need to implement the function $MessageGroups first - #
    'Check[$expr$, $failexpr$, "name"]' + #
    'Check'[$expr$, $failexpr$, "name"] #
    checks only for messages in the named message group. def get_msg_list(exprs): @@ -125,10 +124,10 @@ def get_msg_list(exprs): class Failed(Predefined): - """ - :WMA link:https://reference.wolfram.com/language/ref/$Failed.html + r""" + :WMA link:https://reference.wolfram.com/language/ref/\$Failed.html
    -
    '$Failed' +
    '\$Failed'
    is returned by some functions in the event of an error.
    """ @@ -263,7 +262,7 @@ class Message(Builtin): https://reference.wolfram.com/language/ref/Message.html
    -
    'Message[$symbol$::$msg$, $expr1$, $expr2$, ...]' +
    'Message'[$symbol$::$msg$, $expr_1$, $expr_2$, ...]
    displays the specified message, replacing placeholders in the message text with the corresponding expressions.
    @@ -306,7 +305,7 @@ class MessageName(InfixOperator): :WMA link:https://reference.wolfram.com/language/ref/MessageName.html
    -
    'MessageName[$symbol$, $tag$]' +
    'MessageName'[$symbol$, $tag$]
    '$symbol$::$tag$'
    identifies a message.
    @@ -352,7 +351,7 @@ class Off(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Off.html
    -
    'Off[$symbol$::$tag$]' +
    'Off'[$symbol$::$tag$]
    turns a message off so it is no longer printed.
    @@ -395,7 +394,7 @@ class On(Builtin): :WMA link:https://reference.wolfram.com/language/ref/On.html
    -
    'On[$symbol$::$tag$]' +
    'On'[$symbol$::$tag$]
    turns a message on for printing.
    @@ -439,13 +438,13 @@ class Quiet(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Quiet.html
    -
    'Quiet[$expr$, {$s1$::$t1$, ...}]' -
    evaluates $expr$, without messages '{$s1$::$t1$, ...}' being displayed. -
    'Quiet[$expr$, All]' +
    'Quiet'[$expr$, {$s_1$::$t_1$, ...}] +
    evaluates $expr$, without messages '{$s_1$::$t_1$, ...}' being displayed. +
    'Quiet'[$expr$, All]
    evaluates $expr$, without any messages being displayed. -
    'Quiet[$expr$, None]' +
    'Quiet'[$expr$, None]
    evaluates $expr$, without all messages being displayed. -
    'Quiet[$expr$, $off$, $on$]' +
    'Quiet'[$expr$, $off$, $on$]
    evaluates $expr$, with messages $off$ being suppressed, but messages $on$ being displayed.
    @@ -561,9 +560,11 @@ def get_msg_list(expr): evaluation.set_quiet_messages(old_quiet_messages) +# Consider removing. If this was this added just to test some expressions, +# this should be done in pytests instead. class Syntax(Builtin): r""" - :WMA link:https://reference.wolfram.com/language/ref/Syntax.html + :WMA link:https://reference.wolfram.com/language/guide/Syntax.html
    'Syntax' @@ -571,16 +572,16 @@ class Syntax(Builtin):
    >> 1 + - : Incomplete expression; more input is needed (line 1 of ""). + : Incomplete expression; more input is needed (line 1 of ""). >> Sin[1) - : "Sin[1" cannot be followed by ")" (line 1 of ""). + : "Sin[1" cannot be followed by ")" (line 1 of ""). >> ^ 2 - : Expression cannot begin with "^ 2" (line 1 of ""). + : Expression cannot begin with "^ 2" (line 1 of ""). >> 1.5`` - : "1.5`" cannot be followed by "`" (line 1 of ""). + : "1.5`" cannot be followed by "`" (line 1 of ""). """ # Extension: WMA does not provide lineno and filename in its error messages diff --git a/mathics/builtin/no_meaning/infix.py b/mathics/builtin/no_meaning/infix.py index ed5cb5bb7..1a4828893 100644 --- a/mathics/builtin/no_meaning/infix.py +++ b/mathics/builtin/no_meaning/infix.py @@ -29,7 +29,7 @@ def create_class_function( operator_name=operator_name, operator_string=operator_string ), "operator": operator_string, - "summary_text": f"""{operator_name} postfix operator "{operator_string}" (no pre-set meaning attached)""", + "summary_text": f"""{operator_name} infix operator "{operator_string}" (no pre-set meaning attached)""", "formats": { ( ("InputForm", "OutputForm", "StandardForm"), diff --git a/mathics/builtin/no_meaning/infix_extra.py b/mathics/builtin/no_meaning/infix_extra.py index e8a1dc3d1..01d311610 100644 --- a/mathics/builtin/no_meaning/infix_extra.py +++ b/mathics/builtin/no_meaning/infix_extra.py @@ -18,7 +18,7 @@ class DirectedEdge(InfixOperator): https://reference.wolfram.com/language/ref/DirectedEdge.html
    -
    'DirectedEdge[$x$, $y$, ...]' +
    'DirectedEdge'[$x$, $y$, ...]
    displays $x$ → $y$ → ... Directed edges are typically used in network graphs. In Mathics3, \ @@ -53,7 +53,7 @@ class UndirectedEdge(InfixOperator): https://reference.wolfram.com/language/ref/UndirectedEdge.html
    -
    'UndirectedEdge[$x$, $y$, ...]' +
    'UndirectedEdge'[$x$, $y$, ...]
    displays $x$ ↔ $y$ ... Undirected edges are typically used in network graphs. In Mathics3, \\ diff --git a/mathics/builtin/numbers/algebra.py b/mathics/builtin/numbers/algebra.py index 3380a4ce2..ebd5d78e6 100644 --- a/mathics/builtin/numbers/algebra.py +++ b/mathics/builtin/numbers/algebra.py @@ -309,7 +309,7 @@ def find_vars(e, e_sympy): if lv_sympy is not None: find_vars(lv, lv_sympy) elif e.has_form("Power", 2): - (a, b) = e.elements # a^b + a, b = e.elements # a^b a_sympy, b_sympy = a.to_sympy(), b.to_sympy() if a_sympy is None or b_sympy is None: return @@ -362,9 +362,9 @@ class Apart(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Apart.html
    -
    'Apart[$expr$]' +
    'Apart'[$expr$]
    writes $expr$ as a sum of individual fractions. -
    'Apart[$expr$, $var$]' +
    'Apart'[$expr$, $var$]
    treats $var$ as the main variable.
    @@ -418,7 +418,7 @@ class Cancel(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Cancel.html
    -
    'Cancel[$expr$]' +
    'Cancel'[$expr$]
    cancels out common factors in numerators and denominators.
    @@ -777,7 +777,7 @@ class CoefficientArrays(_CoefficientHandler): https://reference.wolfram.com/language/ref/CoefficientArrays.html
    -
    'CoefficientArrays[$polys$, $vars$]' +
    'CoefficientArrays'[$polys$, $vars$]
    returns a list of arrays of coefficients of the variables $vars$ \ in the polynomial $poly$.
    @@ -1016,14 +1016,14 @@ class Collect(_CoefficientHandler): :WMA link:https://reference.wolfram.com/language/ref/Collect.html
    -
    'Collect[$expr$, $x$]' +
    'Collect'[$expr$, $x$]
    Expands $expr$ and collect together terms having the same power of $x$. -
    'Collect[$expr$, {$x_1$, $x_2$, ...}]' +
    'Collect'[$expr$, {$x_1$, $x_2$, ...}]
    Expands $expr$ and collect together terms having the same powers of \ $x_1$, $x_2$, .... -
    'Collect[$expr$, {$x_1$, $x_2$, ...}, $filter$]' +
    'Collect'[$expr$, {$x_1$, $x_2$, ...}, $filter$]
    After collect the terms, applies $filter$ to each coefficient.
    @@ -1064,7 +1064,7 @@ class Denominator(Builtin): https://reference.wolfram.com/language/ref/Denominator.html
    -
    'Denominator[$expr$]' +
    'Denominator'[$expr$]
    gives the denominator in $expr$.
    @@ -1128,7 +1128,7 @@ class Expand(_Expand): https://reference.wolfram.com/language/ref/Expand.html
    -
    'Expand[$expr$]' +
    'Expand'[$expr$]
    expands out positive integer powers and products of sums in $expr$, as \ well as trigonometric identities. @@ -1210,10 +1210,10 @@ class ExpandAll(_Expand): https://reference.wolfram.com/language/ref/ExpandAll.html
    -
    'ExpandAll[$expr$]' +
    'ExpandAll'[$expr$]
    expands out negative integer powers and products of sums in $expr$. -
    'ExpandAll[$expr$, $target$]' +
    'ExpandAll'[$expr$, $target$]
    just expands those parts involving $target$.
    @@ -1272,7 +1272,7 @@ class ExpandDenominator(_Expand): https://reference.wolfram.com/language/ref/ExpandDenominator.html
    -
    'ExpandDenominator[$expr$]' +
    'ExpandDenominator'[$expr$]
    expands out negative integer powers and products of sums in $expr$.
    @@ -1358,7 +1358,7 @@ class Factor(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Factor.html
    -
    'Factor[$expr$]' +
    'Factor'[$expr$]
    factors the polynomial expression $expr$.
    @@ -1521,11 +1521,11 @@ class Simplify(Builtin): https://reference.wolfram.com/language/ref/Simplify.html
    -
    'Simplify[$expr$]' +
    'Simplify'[$expr$]
    simplifies $expr$. -
    'Simplify[$expr$, $assump$]' -
    simplifies $expr$ assuming $assump$ instead of $Assumptions$. +
    'Simplify'[$expr$, $assump$] +
    simplifies $expr$ assuming $assump$ instead of '\$Assumptions'.
    >> Simplify[2*Sin[x]^2 + 2*Cos[x]^2] @@ -1535,23 +1535,23 @@ class Simplify(Builtin): >> Simplify[f[x]] = f[x] - Simplify over conditional expressions uses $\$Assumptions$, or $assump$ + Simplify over conditional expressions uses '\$Assumptions', or $assump$ to evaluate the condition: >> $Assumptions={a <= 0}; >> Simplify[ConditionalExpression[1, a > 0]] = Undefined - The $assump$ option override $\$Assumption$: + The $assump$ option override '\$Assumption': >> Simplify[ConditionalExpression[1, a > 0] ConditionalExpression[1, b > 0], { b > 0 }] = ConditionalExpression[1, a > 0] - On the other hand, $Assumptions$ option does not override $\$Assumption$, but add to them: + On the other hand, 'Assumptions' option does not override '\$Assumptions', but add to them: >> Simplify[ConditionalExpression[1, a > 0] ConditionalExpression[1, b > 0], Assumptions -> { b > 0 }] = ConditionalExpression[1, a > 0] - Passing both options overwrites $Assumptions with the union of $assump$ the option + Passing both options overwrites '\$Assumptions' with the union of $assump$ the option >> Simplify[ConditionalExpression[1, a > 0] ConditionalExpression[1, b > 0], {a>0},Assumptions -> { b > 0 }] = 1 >> $Assumptions={}; - The option $ComplexityFunction$ allows to control the way in which the \ + The option 'ComplexityFunction' allows to control the way in which the \ evaluator decides if one expression is simpler than another. For example, \ by default, 'Simplify' tries to avoid expressions involving numbers with many digits: >> Simplify[20 Log[2]] @@ -1637,9 +1637,9 @@ class FullSimplify(Simplify): https://reference.wolfram.com/language/ref/FullSimplify.html
    -
    'FullSimplify[$expr$]' +
    'FullSimplify'[$expr$]
    simplifies $expr$ using an extended set of simplification rules. -
    'FullSimplify[$expr$, $assump$]' +
    'FullSimplify'[$expr$, $assump$]
    simplifies $expr$ assuming $assump$ instead of $Assumptions$.
    @@ -1715,7 +1715,7 @@ class Numerator(Builtin): https://reference.wolfram.com/language/ref/Numerator.html
    -
    'Numerator[$expr$]' +
    'Numerator'[$expr$]
    gives the numerator in $expr$.
    @@ -1846,8 +1846,8 @@ class PowerExpand(Builtin): https://reference.wolfram.com/language/ref/PowerExpand.html
    -
    'PowerExpand[$expr$]' -
    expands out powers of the form '(x^y)^z' and '(x*y)^z' in $expr$. +
    'PowerExpand'[$expr$] +
    expands out powers of the form $(x^y)^z$ and $(x y)^z$ in $expr$.
    >> PowerExpand[(a ^ b) ^ c] @@ -1880,7 +1880,7 @@ class Together(Builtin): https://reference.wolfram.com/language/ref/Together.html
    -
    'Together[$expr$]' +
    'Together'[$expr$]
    writes sums of fractions in $expr$ together.
    @@ -1915,7 +1915,7 @@ class Variables(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Variables.html
    -
    'Variables[$expr$]' +
    'Variables'[$expr$]
    gives a list of the variables that appear in the polynomial $expr$.
    diff --git a/mathics/builtin/numbers/calculus.py b/mathics/builtin/numbers/calculus.py index 0efd55114..61c1bf928 100644 --- a/mathics/builtin/numbers/calculus.py +++ b/mathics/builtin/numbers/calculus.py @@ -125,17 +125,17 @@ class D(SympyFunction): (:WMA:https://reference.wolfram.com/language/ref/D.html)
    -
    'D[$f$, $x$]' +
    'D'[$f$, $x$]
    gives the partial derivative of $f$ with respect to $x$. -
    'D[$f$, $x$, $y$, ...]' +
    'D'[$f$, $x$, $y$, ...]
    differentiates successively with respect to $x$, $y$, etc. -
    'D[$f$, {$x$, $n$}]' +
    'D'[$f$, {$x$, $n$}]
    gives the multiple derivative of order $n$. -
    'D[$f$, {{$x1$, $x2$, ...}}]' -
    gives the vector derivative of $f$ with respect to $x1$, $x2$, etc. +
    'D'[$f$, {{$x_1$, $x_2$, ...}}] +
    gives the vector derivative of $f$ with respect to $x_1$, $x_2$, etc.
    First-order derivative of a polynomial: @@ -359,15 +359,22 @@ def eval_wrong(self, expr, x, other, evaluation: Evaluation): class Derivative(PostfixOperator, SympyFunction): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/Derivative.html
    -
    'Derivative[$n$][$f$]' +
    $f$'\''[$x$,...] +
    represents the derivative of $f$ with respect to the first \ + argument $x$. + +
    $f$'\'\''[$x$,...] +
    represents the 2nd derivative of $f$ with respect to $x$. + +
    'Derivative'[$n$][$f$]
    represents the $n$th derivative of the function $f$. -
    'Derivative[$n1$, $n2$, ...][$f$]' +
    'Derivative'[$n_1$, $n_2$, ...][$f$]
    represents a multivariate derivative.
    @@ -548,7 +555,7 @@ class DiscreteLimit(Builtin): https://reference.wolfram.com/language/ref/DiscreteLimit.html
    -
    'DiscreteLimit[$f$, $k$->Infinity]' +
    'DiscreteLimit'[$f$, $k$->Infinity]
    gives the limit of the sequence $f$ as $k$ tends to infinity.
    @@ -745,8 +752,8 @@ class FindMaximum(_BaseFinder): :WMA link:https://reference.wolfram.com/language/ref/FindMaximum.html
    -
    'FindMaximum[$f$, {$x$, $x0$}]' -
    searches for a numerical maximum of $f$, starting from '$x$=$x0$'. +
    'FindMaximum'[$f$, {$x$, $x_0$}] +
    searches for a numerical maximum of $f$, starting from '$x$=$x_0$'.
    'FindMaximum' by default uses Newton\'s method, so the function of \ @@ -795,8 +802,8 @@ class FindMinimum(_BaseFinder): https://reference.wolfram.com/language/ref/FindMinimum.html
    -
    'FindMinimum[$f$, {$x$, $x0$}]' -
    searches for a numerical minimum of $f$, starting from '$x$=$x0$'. +
    'FindMinimum'[$f$, {$x$, $x_0$}] +
    searches for a numerical minimum of $f$, starting from '$x$=$x_0$'.
    'FindMinimum' by default uses Newton\'s method, so the function of \ @@ -847,10 +854,10 @@ class FindRoot(_BaseFinder): :WMA link:https://reference.wolfram.com/language/ref/FindRoot.html
    -
    'FindRoot[$f$, {$x$, $x0$}]' -
    searches for a numerical root of $f$, starting from '$x$=$x0$'. +
    'FindRoot'[$f$, {$x$, $x_0$}] +
    searches for a numerical root of $f$, starting from '$x$=$x_0$'. -
    'FindRoot[$lhs$ == $rhs$, {$x$, $x0$}]' +
    'FindRoot'[$lhs$ == $rhs$, {$x$, $x_0$}]
    tries to solve the equation '$lhs$ == $rhs$'.
    @@ -952,15 +959,17 @@ class Integers(Builtin): class Integrate(SympyFunction): r""" - :WMA link: - https://reference.wolfram.com/language/ref/Integrate.html + :Integral:https://en.wikipedia.org/wiki/Integral (:SymPy: + https://docs.sympy.org/latest/modules/integrals/integrals.html, \ + :WMA: + https://reference.wolfram.com/language/ref/Integrate.html)
    -
    'Integrate[$f$, $x$]' +
    'Integrate'[$f$, $x$]
    integrates $f$ with respect to $x$. The result does not contain the \ additive integration constant. -
    'Integrate[$f$, {$x$, $a$, $b$}]' +
    'Integrate'[$f$, {$x$, $a$, $b$}]
    computes the definite integral of $f$ with respect to $x$ from $a$ to $b$.
    @@ -984,18 +993,20 @@ class Integrate(SympyFunction): >> Integrate[4 Sin[x] Cos[x], x] = 2 Sin[x] ^ 2 - > Integrate[-Infinity, {x, 0, Infinity}] + >> Integrate[-Infinity, {x, 0, Infinity}] = -Infinity - > Integrate[-Infinity, {x, Infinity, 0}] - = Infinity + Integrating something ill-defined returns the expression untouched: + + >> Integrate[1, {x, Infinity, 0}] + = Integrate[1, {x, Infinity, 0}] - Integration in TeX: + Here how is an example of converting integral equation to TeX: >> Integrate[f[x], {x, a, b}] // TeXForm = \int_a^b f\left[x\right] \, dx Sometimes there is a loss of precision during integration. - You can check the precision of your result with the following sequence + You can check the precision of your result with the following sequence \ of commands. >> Integrate[Abs[Sin[phi]], {phi, 0, 2Pi}] // N = 4. @@ -1114,6 +1125,10 @@ def eval(self, f, xs, evaluation: Evaluation, options: dict): # type: ignore[ov # e.g. NotImplementedError: Result depends on the sign of # -sign(_u`j)*sign(_u`w) return + except TypeError: + # SymPy can give this. For example: + # Integrate[-Infinity, {x, 0, Infinity}] + return if prec is not None and isinstance(sympy_result, sympy.Integral): # TODO MaxExtraPrecision -> maxn sympy_result = sympy_result.evalf(dps(prec)) @@ -1222,14 +1237,14 @@ class Limit(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Limit.html
    -
    'Limit[$expr$, $x$->$x0$]' -
    gives the limit of $expr$ as $x$ approaches $x0$. +
    'Limit'[$expr$, $x$->$x_0$] +
    gives the limit of $expr$ as $x$ approaches $x_0$. -
    'Limit[$expr$, $x$->$x0$, Direction->1]' -
    approaches $x0$ from smaller values. +
    'Limit'[$expr$, $x$->$x_0$, Direction->1] +
    approaches $x_0$ from smaller values. -
    'Limit[$expr$, $x$->$x0$, Direction->-1]' -
    approaches $x0$ from larger values. +
    'Limit'[$expr$, $x$->$x_0$, Direction->-1] +
    approaches $x_0$ from larger values.
    >> Limit[x, x->2] @@ -1295,13 +1310,13 @@ class NIntegrate(Builtin): :WMA link:https://reference.wolfram.com/language/ref/NIntegrate.html
    -
    'NIntegrate[$expr$, $interval$]' +
    'NIntegrate'[$expr$, $interval$]
    returns a numeric approximation to the definite integral of $expr$ with \ limits $interval$ and with a precision of $prec$ digits. -
    'NIntegrate[$expr$, $interval1$, $interval2$, ...]' +
    'NIntegrate'[$expr$, $interval_1$, $interval_2$, ...]
    returns a numeric approximation to the multiple integral of $expr$ with \ - limits $interval1$, $interval2$ and with a precision of $prec$ digits. + limits $interval_1$, $interval_2$ and with a precision of $prec$ digits.
    >> NIntegrate[Exp[-x],{x,0,Infinity},Tolerance->1*^-6, Method->"Internal"] @@ -1620,7 +1635,7 @@ class Root(SympyFunction): :WMA link:https://reference.wolfram.com/language/ref/Root.html
    -
    'Root[$f$, $i$]' +
    'Root'[$f$, $i$]
    represents the i-th complex root of the polynomial $f$.
    @@ -1700,7 +1715,7 @@ class RootSum(SympyFunction): :WMA link: https://reference.wolfram.com/language/ref/RootSum.html
    -
    'RootSum[$f$, $form$]' +
    'RootSum'[$f$, $form$]
    sums $form$[$x$] for all roots of the polynomial $f$[$x$].
    @@ -1748,8 +1763,8 @@ class Series(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Series.html
    -
    'Series[$f$, {$x$, $x0$, $n$}]' -
    Represents the series expansion around '$x$=$x0$' up to order $n$. +
    'Series'[$f$, {$x$, $x_0$, $n$}] +
    Represents the series expansion around '$x$=$x_0$' up to order $n$.
    For elementary expressions, 'Series' returns the explicit power series as a 'SeriesData' expression: @@ -1816,11 +1831,11 @@ class SeriesCoefficient(Builtin): :WMA link:https://reference.wolfram.com/language/ref/SeriesCoefficient.html
    -
    'SeriesCoefficient[$series$, $n$]' +
    'SeriesCoefficient'[$series$, $n$]
    Find the $n$th coefficient in the given $series$. -
    'SeriesCoefficient[$f$, {$x$, $x0$, $n$}]' -
    Find the ($x$-$x0$)^n in the expansion of $f$ about the point $x$=$x0$. +
    'SeriesCoefficient'[$f$, {$x$, $x_0$, $n$}] +
    Find the ($x$-$x_0$)^n in the expansion of $f$ about the point $x$=$x_0$.
    First we list 5 terms of a series: @@ -1879,10 +1894,10 @@ class SeriesData(Builtin): :WMA link:https://reference.wolfram.com/language/ref/SeriesData.html
    -
    'SeriesData[$x$, $x0$, {$a0$, $a1$, ...}, $nmin$, $nmax$, $den$]' -
    produces a power series in the variable $x$ about point $x0$. The \ - $ai$ are the coefficients of the power series. The powers of ($x$-$x0$) that appear \ - are $nmin$/$den$, ($nmin$+1)/$den$, ..., $nmax$/$den$. +
    'SeriesData'[$x$, $x_0$, {$a_0$, $a_1$, ...}, $n_{min}$, $n_{max}$, $den$] +
    produces a power series in the variable $x$ about point $x_0$. The \ + $ai$ are the coefficients of the power series. The powers of ($x$-$x_0$) that appear \ + are $n_{min}$/$den$, ($n_{min}$+1)/$den$, ..., $n_{max}$/$den$.
    'SeriesData' is the 'Head' of expressions generated by 'Series': @@ -2285,10 +2300,10 @@ class Solve(Builtin): https://reference.wolfram.com/language/ref/Solve.html)
    -
    'Solve[$equation$, $vars$]' +
    'Solve'[$equation$, $vars$]
    attempts to solve $equation$ for the variables $vars$. -
    'Solve[$equation$, $vars$, $domain$]' +
    'Solve'[$equation$, $vars$, $domain$]
    restricts variables to $domain$, which can be 'Complexes' \ or 'Reals' or 'Integers'.
    diff --git a/mathics/builtin/numbers/constants.py b/mathics/builtin/numbers/constants.py index b2caf6162..28158a48a 100644 --- a/mathics/builtin/numbers/constants.py +++ b/mathics/builtin/numbers/constants.py @@ -6,9 +6,6 @@ Numeric, Arithmetic, or Symbolic constants like Pi, E, or Infinity. """ -# This tells documentation how to sort this module -sort_order = "mathics.builtin.mathematical-constants" - import math from typing import Dict, Optional @@ -25,6 +22,9 @@ from mathics.core.symbols import Atom, Symbol, strip_context from mathics.core.systemsymbols import SymbolIndeterminate +# This tells documentation how to sort this module +sort_order = "mathics.builtin.mathematical-constants" + def mp_constant(fn: str, d=None) -> mpmath.mpf: """ @@ -81,6 +81,7 @@ def eval_N(self, precision, evaluation): return self.get_constant(precision, evaluation) def is_constant(self) -> bool: + """The value and evaluation of this object can never change.""" return True def get_constant( @@ -190,7 +191,7 @@ def __init__(self, *args, **kwargs): value_float = self.to_numpy(self.symbol) NUMERICAL_CONSTANTS[self.symbol] = MachineReal(value_float) - def to_numpy(self, args): + def to_numpy(self, _): return NUMERICAL_CONSTANTS[self.symbol] @@ -285,6 +286,10 @@ class ComplexInfinity(_SympyConstant): "ComplexInfinity": "DirectedInfinity[]", } + @property + def sympy(self) -> sympy.core.numbers.ComplexInfinity: + return zoo + class Degree(_MPMathConstant, _NumpyConstant, _SympyConstant): """ @@ -375,6 +380,10 @@ def eval_N(self, precision, evaluation): "N[E, precision_]" return self.get_constant(precision, evaluation) + @property + def sympy(self) -> sympy.core.numbers.Exp1: + return SymPyE + class EulerGamma(_MPMathConstant, _NumpyConstant, _SympyConstant): """ @@ -401,6 +410,10 @@ class EulerGamma(_MPMathConstant, _NumpyConstant, _SympyConstant): numpy_name = "euler_gamma" sympy_name = "EulerGamma" + @property + def sympy(self) -> sympy.core.numbers.EulerGamma: + return S.EulerGamma + class Glaisher(_MPMathConstant): """ @@ -571,7 +584,7 @@ class Overflow(Builtin): See also :Integer Overflow: - . + https://en.wikipedia.org/wiki/Integer_overflow.
    'Overflow[]' @@ -595,19 +608,19 @@ class Overflow(Builtin): class MaxMachineNumber(Predefined): - """ + r""" Largest normalizable machine number ( :WMA: - https://reference.wolfram.com/language/ref/$MaxMachineNumber.html + https://reference.wolfram.com/language/ref/\$MaxMachineNumber.html )
    -
    '$MaxMachineNumber' +
    '\$MaxMachineNumber'
    Represents the largest positive number that can be represented \ as a normalized machine number in the system.
    - The product of '$MaxMachineNumber' and '$MinMachineNumber' is a constant: + The product of '\$MaxMachineNumber' and '\$MinMachineNumber' is a constant: >> $MaxMachineNumber * $MinMachineNumber = 4. @@ -621,14 +634,14 @@ def evaluate(self, evaluation: Evaluation) -> MachineReal: class MinMachineNumber(Predefined): - """ + r""" Smallest normalizable machine number ( :WMA: - https://reference.wolfram.com/language/ref/$MinMachineNumber.html + https://reference.wolfram.com/language/ref/\$MinMachineNumber.html )
    -
    '$MinMachineNumber' +
    '\$MinMachineNumber'
    Represents the smallest positive number that can be represented \ as a normalized machine number in the system.
    diff --git a/mathics/builtin/numbers/diffeqns.py b/mathics/builtin/numbers/diffeqns.py index 7c685f769..66d0a4475 100644 --- a/mathics/builtin/numbers/diffeqns.py +++ b/mathics/builtin/numbers/diffeqns.py @@ -20,7 +20,7 @@ class DSolve(Builtin): :WMA link:https://reference.wolfram.com/language/ref/DSolve.html
    -
    'DSolve[$eq$, $y$[$x$], $x$]' +
    'DSolve[$eq$, $y$'[$x$], $x$]
    solves a differential equation for the function $y$[$x$].
    @@ -178,7 +178,7 @@ class C(Builtin):
    'C'[$n$] -
    represents the $n$th constant in a solution to a differential equation. +
    represents the $n$-th constant in a solution to a differential equation.
    """ diff --git a/mathics/builtin/numbers/exp.py b/mathics/builtin/numbers/exp.py index 86a9f7f14..c8aa8f011 100644 --- a/mathics/builtin/numbers/exp.py +++ b/mathics/builtin/numbers/exp.py @@ -164,7 +164,7 @@ class Exp(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/Exp.html
    -
    'Exp[$z$]' +
    'Exp'[$z$]
    returns the exponential function of $z$.
    @@ -194,7 +194,7 @@ class Log(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/Log.html
    -
    'Log[$z$]' +
    'Log'[$z$]
    returns the natural logarithm of $z$.
    @@ -237,7 +237,7 @@ class Log2(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Log2.html
    -
    'Log2[$z$]' +
    'Log2'[$z$]
    returns the base-2 logarithm of $z$.
    @@ -262,7 +262,7 @@ class Log10(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Log10.html
    -
    'Log10[$z$]' +
    'Log10'[$z$]
    returns the base-10 logarithm of $z$.
    @@ -287,7 +287,7 @@ class LogisticSigmoid(Builtin): :WMA link:https://reference.wolfram.com/language/ref/LogisticSigmoid.html
    -
    'LogisticSigmoid[$z$]' +
    'LogisticSigmoid'[$z$]
    returns the logistic sigmoid of $z$.
    diff --git a/mathics/builtin/numbers/hyperbolic.py b/mathics/builtin/numbers/hyperbolic.py index 9884e619c..2933d6952 100644 --- a/mathics/builtin/numbers/hyperbolic.py +++ b/mathics/builtin/numbers/hyperbolic.py @@ -42,7 +42,7 @@ class ArcCosh(MPMathFunction): https://reference.wolfram.com/language/ref/ArcCosh.html)
    -
    'ArcCosh[$z$]' +
    'ArcCosh'[$z$]
    returns the inverse hyperbolic cosine of $z$.
    @@ -80,7 +80,7 @@ class ArcCoth(MPMathFunction): https://reference.wolfram.com/language/ref/ArcCoth.html)
    -
    'ArcCoth[$z$]' +
    'ArcCoth'[$z$]
    returns the inverse hyperbolic cotangent of $z$.
    @@ -118,7 +118,7 @@ class ArcCsch(MPMathFunction): https://reference.wolfram.com/language/ref/ArcCsch.html)
    -
    'ArcCsch[$z$]' +
    'ArcCsch'[$z$]
    returns the inverse hyperbolic cosecant of $z$.
    @@ -152,7 +152,7 @@ class ArcSech(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/ArcSech.html
    -
    'ArcSech[$z$]' +
    'ArcSech'[$z$]
    returns the inverse hyperbolic secant of $z$.
    @@ -188,7 +188,7 @@ class ArcSinh(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/ArcSinh.html
    -
    'ArcSinh[$z$]' +
    'ArcSinh'[$z$]
    returns the inverse hyperbolic sine of $z$.
    @@ -215,7 +215,7 @@ class ArcTanh(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/ArcTanh.html
    -
    'ArcTanh[$z$]' +
    'ArcTanh'[$z$]
    returns the inverse hyperbolic tangent of $z$.
    @@ -253,10 +253,10 @@ class ComplexExpand(SympyFunction): )
    -
    'ComplexExpand[$expr$]' +
    'ComplexExpand'[$expr$]
    expands $expr$ assuming that all variables are real. -
    'ComplexExpand[$expr$,{$x1$,$x2$, ...}]' +
    'ComplexExpand'[$expr$,{$x_1$,$x_2$, ...}]
    expands $expr$ assuming that variables matching any of the $xi$ are complex.
    @@ -310,7 +310,7 @@ class Cosh(MPMathFunction): https://reference.wolfram.com/language/ref/Cosh.html
    -
    'Cosh[$z$]' +
    'Cosh'[$z$]
    returns the hyperbolic cosine of $z$.
    @@ -333,7 +333,7 @@ class Coth(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/Coth.html
    -
    'Coth[$z$]' +
    'Coth'[$z$]
    returns the hyperbolic cotangent of $z$.
    @@ -360,7 +360,7 @@ class Gudermannian(Builtin): :WMA: https://reference.wolfram.com/language/ref/Gudermannian.html, :MathWorld: https://mathworld.wolfram.com/Gudermannian.html)
    -
    'Gudermannian[$z$]' +
    'Gudermannian'[$z$]
    returns the Gudermannian function $gd$($z$).
    @@ -377,7 +377,7 @@ class Gudermannian(Builtin): """ # See https://mathworld.wolfram.com/Gudermannian.html for a number - # of relatiions to trigonometric and hyperbolic functions that could be + # of relations to trigonometric and hyperbolic functions that could be # used if needed. rules = { "Gudermannian[Undefined]": "Undefined", @@ -405,7 +405,7 @@ class InverseGudermannian(Builtin): https://reference.wolfram.com/language/ref/InverseGudermannian.html, :MathWorld: https://mathworld.wolfram.com/InverseGudermannian.html)
    -
    'InverseGudermannian[$z$]' +
    'InverseGudermannian'[$z$]
    returns the inverse Gudermannian function $gd$^-1($z$).
    @@ -437,7 +437,7 @@ class Sech(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/Sech.html
    -
    'Sech[$z$]' +
    'Sech'[$z$]
    returns the hyperbolic secant of $z$.
    @@ -466,7 +466,7 @@ class Sinh(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/Sinh.html
    -
    'Sinh[$z$]' +
    'Sinh'[$z$]
    returns the hyperbolic sine of $z$.
    @@ -488,7 +488,7 @@ class Tanh(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/Tanh.html
    -
    'Tanh[$z$]' +
    'Tanh'[$z$]
    returns the hyperbolic tangent of $z$.
    diff --git a/mathics/builtin/numbers/integer.py b/mathics/builtin/numbers/integer.py index 4e27ee3ed..604bbcda3 100644 --- a/mathics/builtin/numbers/integer.py +++ b/mathics/builtin/numbers/integer.py @@ -60,7 +60,7 @@ class BitLength(Builtin): :WMA link:https://reference.wolfram.com/language/ref/BitLength.html
    -
    'BitLength[$x$]' +
    'BitLength'[$x$]
    gives the number of bits needed to represent the integer $x$. $x$'s sign is ignored.
    @@ -90,7 +90,7 @@ class Ceiling(SympyFunction): :WMA link:https://reference.wolfram.com/language/ref/Ceiling.html
    -
    'Ceiling[$x$]' +
    'Ceiling'[$x$]
    gives the smallest integer greater than or equal to $x$.
    @@ -121,11 +121,11 @@ class DigitCount(_IntBaseBuiltin): :WMA link:https://reference.wolfram.com/language/ref/DigitCount.html
    -
    'DigitCount[$n$, $b$, $d$]' +
    'DigitCount'[$n$, $b$, $d$]
    returns the number of times digit $d$ occurs in the base $b$ representation of $n$. -
    'DigitCount[$n$, $b$]' +
    'DigitCount'[$n$, $b$]
    returns a list indicating the number of times each digit occurs in the base $b$ representation of $n$. -
    'DigitCount[$n$, $b$]' +
    'DigitCount'[$n$, $b$]
    returns a list indicating the number of times each digit occurs in the decimal representation of $n$.
    @@ -177,10 +177,10 @@ class Floor(SympyFunction): :WMA link:https://reference.wolfram.com/language/ref/Floor.html
    -
    'Floor[$x$]' +
    'Floor'[$x$]
    gives the greatest integer less than or equal to $x$. -
    'Floor[$x$, $a$]' +
    'Floor'[$x$, $a$]
    gives the greatest multiple of $a$ less than or equal to $x$.
    @@ -226,11 +226,11 @@ class FromDigits(Builtin): :WMA link:https://reference.wolfram.com/language/ref/FromDigits.html
    -
    'FromDigits[$l$]' +
    'FromDigits'[$l$]
    returns the integer corresponding to the decimal representation given by $l$. $l$ can \ be a list of digits or a string. -
    'FromDigits[$l$, $b$]' +
    'FromDigits'[$l$, $b$]
    returns the integer corresponding to the base $b$ representation given by $l$. $l$ can \ be a list of digits or a string.
    @@ -310,15 +310,15 @@ class IntegerDigits(_IntBaseBuiltin): https://reference.wolfram.com/language/ref/IntegerDigits.html
    -
    'IntegerDigits[$n$]' +
    'IntegerDigits'[$n$]
    returns the decimal representation of integer $x$ as list of digits. \ $x$'s sign is ignored. -
    'IntegerDigits[$n$, $b$]' +
    'IntegerDigits'[$n$, $b$]
    returns the base $b$ representation of integer $x$ as list of digits. \ $x$'s sign is ignored. -
    'IntegerDigits[$n$, $b$, $length$]' +
    'IntegerDigits'[$n$, $b$, $length$]
    returns a list of length $length$. If the number is too short, the \ list gets padded with 0 on the left. If the number is too long, the \ $length$ least significant digits are returned. @@ -392,11 +392,11 @@ class IntegerString(Builtin): :WMA link:https://reference.wolfram.com/language/ref/IntegerString.html
    -
    'IntegerString[$n$]' +
    'IntegerString'[$n$]
    returns the decimal representation of integer $x$ as string. $x$'s sign is ignored. -
    'IntegerString[$n$, $b$]' +
    'IntegerString'[$n$, $b$]
    returns the base $b$ representation of integer $x$ as string. $x$'s sign is ignored. -
    'IntegerString[$n$, $b$, $length$]' +
    'IntegerString'[$n$, $b$, $length$]
    returns a string of length $length$. If the number is too short, the string gets padded with 0 on the left. If the number is too long, the $length$ least significant digits are returned. @@ -472,11 +472,11 @@ class IntegerReverse(_IntBaseBuiltin): https://reference.wolfram.com/language/ref/IntegerReverse.html
    -
    'IntegerReverse[$n$]' +
    'IntegerReverse'[$n$]
    returns the integer that has the reverse decimal representation \ of $x$ without sign. -
    'IntegerReverse[$n$, $b$]' +
    'IntegerReverse'[$n$, $b$]
    returns the integer that has the reverse base $b$ representation \ of $x$ without sign.
    diff --git a/mathics/builtin/numbers/linalg.py b/mathics/builtin/numbers/linalg.py index e2771284b..c01a9b9c0 100644 --- a/mathics/builtin/numbers/linalg.py +++ b/mathics/builtin/numbers/linalg.py @@ -27,7 +27,7 @@ class DesignMatrix(Builtin): https://reference.wolfram.com/language/ref/DesignMatrix.html
    -
    'DesignMatrix[$m$, $f$, $x$]' +
    'DesignMatrix'[$m$, $f$, $x$]
    returns the design matrix for a linear model $f$ in the variables $x$.
    @@ -52,7 +52,7 @@ class Det(Builtin): (:WMA link:https://reference.wolfram.com/language/ref/Det.html)
    -
    'Det[$m$]' +
    'Det'[$m$]
    computes the determinant of the matrix $m$.
    @@ -85,7 +85,7 @@ class Eigensystem(Builtin): https://reference.wolfram.com/language/ref/Eigensystem.html)
    -
    'Eigensystem[$m$]' +
    'Eigensystem'[$m$]
    returns the list '{Eigenvalues[$m$], Eigenvectors[$m$]}'.
    @@ -104,7 +104,7 @@ class Eigenvalues(Builtin):
    -
    'Eigenvalues[$m$]' +
    'Eigenvalues'[$m$]
    computes the eigenvalues of the matrix $m$. By default, Sympy's routine is used. Sometimes this is slow and \ @@ -171,27 +171,25 @@ def eval(self, m, evaluation, options={}) -> Expression: return eigenvalues = list(sympy_matrix.eigenvals().items()) - if all(v.is_complex for (v, _) in eigenvalues): + if all(v.is_complex for v, _ in eigenvalues): # Try to sort the eigenvalues in the Mathematica convention: largest first. try: eigenvalues.sort( key=lambda v: (abs(v[0]), -re(v[0]), -im(v[0])), reverse=True ) - eigenvalues = [ - from_sympy(v) for (v, c) in eigenvalues for _ in range(c) - ] + eigenvalues = [from_sympy(v) for v, c in eigenvalues for _ in range(c)] return ListExpression(*eigenvalues) except TypeError: pass - eigenvalues = [(from_sympy(v), c) for (v, c) in eigenvalues] + eigenvalues = [(from_sympy(v), c) for v, c in eigenvalues] # Sort the eigenvalues by their sort key eigenvalues.sort(key=lambda v: v[0].get_sort_key()) - eigenvalues = [v for (v, c) in eigenvalues for _ in range(c)] + eigenvalues = [v for v, c in eigenvalues for _ in range(c)] return ListExpression(*eigenvalues) @@ -202,7 +200,7 @@ class Eigenvectors(Builtin): (:WMA link:https://reference.wolfram.com/language/ref/Eigenvectors.html)
    -
    'Eigenvectors[$m$]' +
    'Eigenvectors'[$m$]
    computes the eigenvectors of the matrix $m$.
    @@ -244,7 +242,7 @@ def eval(self, m, evaluation: Evaluation): return # Try to sort the eigenvectors by their corresponding eigenvalues - if all(v.is_complex for (v, _, _) in eigenvects): + if all(v.is_complex for v, _, _ in eigenvects): try: eigenvects.sort( key=lambda v: (abs(v[0]), -re(v[0]), -im(v[0])), reverse=True @@ -299,7 +297,7 @@ class Inverse(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Inverse.html
    -
    'Inverse[$m$]' +
    'Inverse'[$m$]
    computes the inverse of the matrix $m$.
    @@ -346,7 +344,7 @@ class LeastSquares(Builtin): :WMA link:https://reference.wolfram.com/language/ref/LeastSquares.html
    -
    'LeastSquares[$m$, $b$]' +
    'LeastSquares'[$m$, $b$]
    computes the least squares solution to $m$ $x$ = $b$, finding an $x$ that solves for $b$ optimally.
    @@ -395,7 +393,7 @@ class LinearModelFit(Builtin): :WMA link:https://reference.wolfram.com/language/ref/LinearModelFit.html
    -
    'LinearModelFit[$m$, $f$, $x$]' +
    'LinearModelFit'[$m$, $f$, $x$]
    fits a linear model $f$ in the variables $x$ to the dataset $m$.
    @@ -476,7 +474,7 @@ class LinearSolve(Builtin): :WMA link:https://reference.wolfram.com/language/ref/LinearSolve.html
    -
    'LinearSolve[$matrix$, $right$]' +
    'LinearSolve'[$matrix$, $right$]
    solves the linear equation system '$matrix$ . $x$ = $right$' and returns one corresponding solution $x$.
    @@ -549,7 +547,7 @@ class MatrixExp(Builtin): :WMA link:https://reference.wolfram.com/language/ref/MatrixExp.html
    -
    'MatrixExp[$m$]' +
    'MatrixExp'[$m$]
    computes the exponential of the matrix $m$.
    @@ -588,7 +586,7 @@ class MatrixPower(Builtin): :WMA link:https://reference.wolfram.com/language/ref/MatrixPower.html
    -
    'MatrixPower[$m$, $n$]' +
    'MatrixPower'[$m$, $n$]
    computes the $n$th power of a matrix $m$.
    @@ -633,7 +631,7 @@ class MatrixRank(Builtin): :WMA link:https://reference.wolfram.com/language/ref/MatrixRank.html
    -
    'MatrixRank[$matrix$]' +
    'MatrixRank'[$matrix$]
    returns the rank of $matrix$.
    @@ -667,7 +665,7 @@ class NullSpace(Builtin): (:WMA link:https://reference.wolfram.com/language/ref/NullSpace.html)
    -
    'NullSpace[$matrix$]' +
    'NullSpace'[$matrix$]
    returns a list of vectors that span the nullspace of $matrix$.
    @@ -705,7 +703,7 @@ class PseudoInverse(Builtin): :WMA link:https://reference.wolfram.com/language/ref/PseudoInverse.html
    -
    'PseudoInverse[$m$]' +
    'PseudoInverse'[$m$]
    computes the Moore-Penrose pseudoinverse of the matrix $m$. If $m$ is invertible, the pseudoinverse equals the inverse.
    @@ -742,7 +740,7 @@ class QRDecomposition(Builtin): (:WMA link:https://reference.wolfram.com/language/ref/QRDecomposition.html)
    -
    'QRDecomposition[$m$]' +
    'QRDecomposition'[$m$]
    computes the QR decomposition of the matrix $m$.
    @@ -777,7 +775,7 @@ class RowReduce(Builtin): :WMA link:https://reference.wolfram.com/language/ref/RowReduce.html
    -
    'RowReduce[$matrix$]' +
    'RowReduce'[$matrix$]
    returns the reduced row-echelon form of $matrix$.
    @@ -814,7 +812,7 @@ class SingularValueDecomposition(Builtin): (:WMA link:https://reference.wolfram.com/language/ref/SingularValueDecomposition.html)
    -
    'SingularValueDecomposition[$m$]' +
    'SingularValueDecomposition'[$m$]
    calculates the singular value decomposition for the matrix $m$.
    @@ -868,7 +866,7 @@ class Tr(Builtin): (:WMA link:https://reference.wolfram.com/language/ref/Tr.html)
    -
    'Tr[$m$]' +
    'Tr'[$m$]
    computes the trace of the matrix $m$.
    diff --git a/mathics/builtin/numbers/numbertheory.py b/mathics/builtin/numbers/numbertheory.py index 7259e9925..98678f6b4 100644 --- a/mathics/builtin/numbers/numbertheory.py +++ b/mathics/builtin/numbers/numbertheory.py @@ -46,11 +46,11 @@ class ContinuedFraction(SympyFunction): :SymPy: https://docs.sympy.org/latest/modules/ntheory.html#module-sympy.ntheory.continued_fraction, :WMA: https://reference.wolfram.com/language/ref/ContinuedFraction.html)
    -
    'ContinuedFraction[$x$, $n$]' +
    'ContinuedFraction'[$x$, $n$]
    generate the first $n$ terms in the continued fraction representation of $x$. -
    'ContinuedFraction[$x$]' -
    the complete continued fraction representation for a rational or quadradic irrational number. +
    'ContinuedFraction'[$x$] +
    the complete continued fraction representation for a rational or quadratic irrational number.
    >> ContinuedFraction[Pi, 10] @@ -87,8 +87,8 @@ class DivisorSigma(SympyFunction): :WMA: https://reference.wolfram.com/language/ref/DivisorSigma.html)
    -
    'DivisorSigma[$k$, $n$]' -
    returns $\sigma_k$($n$) +
    'DivisorSigma'[$k$, $n$] +
    returns $\sigma_k(n)$
    For reference, let us first get the integer divisors of 20: @@ -133,7 +133,7 @@ class DivisorSum(Builtin): :WMA: https://reference.wolfram.com/language/ref/DivisorSum.html
    -
    'DivisorSum[$n$, $form$]' +
    'DivisorSum'[$n$, $form$]
    transform the divisors of $n$ using $form$ and take their sum
    @@ -163,7 +163,7 @@ class Divisors(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Divisors.html
    -
    'Divisors[$n$]' +
    'Divisors'[$n$]
    returns a list of the integers that divide $n$.
    @@ -238,7 +238,7 @@ class EulerPhi(SympyFunction): This function counts positive integers up to $n$ that are relatively prime to $n$. It is typically used in cryptography and in many applications in elementary number theory.
    -
    'EulerPhi[$n$]' +
    'EulerPhi'[$n$]
    returns the Euler totient function .
    @@ -288,7 +288,7 @@ class FactorInteger(Builtin): :WMA link:https://reference.wolfram.com/language/ref/FactorInteger.html
    -
    'FactorInteger[$n$]' +
    'FactorInteger'[$n$]
    returns the factorization of $n$ as a list of factors and exponents.
    @@ -355,7 +355,7 @@ class FractionalPart(Builtin): :WMA link:https://reference.wolfram.com/language/ref/FractionalPart.html
    -
    'FractionalPart[$n$]' +
    'FractionalPart'[$n$]
    finds the fractional part of $n$.
    @@ -392,7 +392,7 @@ class FromContinuedFraction(SympyFunction): https://reference.wolfram.com/language/ref/FromContinuedFraction.html
    -
    'FromContinuedFraction[$list$]' +
    'FromContinuedFraction'[$list$]
    reconstructs a number from the list of its continued fraction terms.
    @@ -420,7 +420,7 @@ class IntegerPart(Builtin): :WMA link:https://reference.wolfram.com/language/ref/IntegerPart.html
    -
    'IntegerPart[$n$]' +
    'IntegerPart'[$n$]
    finds the integer part of $n$.
    @@ -459,19 +459,19 @@ class IntegerPartitions(Builtin): :WMA: https://reference.wolfram.com/language/ref/IntegerPartitions.html)
    -
    'IntegerPartitions[$n$]' +
    'IntegerPartitions'[$n$]
    lists all possible ways to partition integer $n$ into smaller integers. -
    'IntegerPartitions[$n$, $k$]' +
    'IntegerPartitions'[$n$, $k$]
    lists all partitions into at most $k$ integers. -
    'IntegerPartitions[$n$, {$k$}]' +
    'IntegerPartitions'[$n$, {$k$}]
    lists all partitions with exactly $k$ integers. -
    'IntegerPartitions[$n$, {$k_min$, $k_max$}]' -
    lists partitions between $k_min$ and $k_max$ integers. +
    'IntegerPartitions'[$n$, {$k_{min}$, $k_{max}$}] +
    lists partitions between $k_{min}$ and $k_{max}$ integers. -
    'IntegerPartitions[$n$, $kspec$, {$s_1$, $s_2$, ...}]' +
    'IntegerPartitions'[$n$, $kspec$, {$s_1$, $s_2$, ...}]
    lists partitions involving only the $s_i$.
    @@ -531,7 +531,7 @@ class JacobiSymbol(Builtin): :Jacobi symbol: https://en.wikipedia.org/wiki/Jacobi_symbol ( :WMA: https://reference.wolfram.com/language/ref/JacobiSymbol.html)
    -
    'JacobiSymbol[$a$, $n$]' +
    'JacobiSymbol'[$a$, $n$]
    returns the Jacobi symbol ($a$/$n$).
    @@ -554,7 +554,7 @@ class KroneckerSymbol(Builtin): :Kronecker symbol: https://en.wikipedia.org/wiki/Kronecker_symbol ( :WMA: https://reference.wolfram.com/language/ref/KroneckerSymbol.html)
    -
    'KroneckerSymbol[$a$, $n$]' +
    'KroneckerSymbol'[$a$, $n$]
    returns the Kronecker symbol ($a$/$n$).
    @@ -581,10 +581,10 @@ class MantissaExponent(Builtin): https://reference.wolfram.com/language/ref/MantissaExponent.html
    -
    'MantissaExponent[$n$]' +
    'MantissaExponent'[$n$]
    finds a list containing the mantissa and exponent of a given number $n$. -
    'MantissaExponent[$n$, $b$]' +
    'MantissaExponent'[$n$, $b$]
    finds the base b mantissa and exponent of $n$.
    @@ -680,8 +680,8 @@ class MersennePrimeExponent(SympyFunction): :WMA: https://reference.wolfram.com/language/ref/MersennePrimeExponent.html)
    -
    'MersennePrimeExponent[$n$]' -
    returns the exponent of the $n$th Mersenne prime. +
    'MersennePrimeExponent'[$n$] +
    returns the exponent of the $n$-th Mersenne prime.
    >> Table[MersennePrimeExponent[n], {n, 10}] @@ -706,7 +706,7 @@ class MoebiusMu(SympyFunction): :WMA: https://reference.wolfram.com/language/ref/MoebiusMu.html)
    -
    'MoebiusMu[$n$]' +
    'MoebiusMu'[$n$]
    returns Îź($n$).
    @@ -728,10 +728,10 @@ class NextPrime(Builtin): :WMA link:https://reference.wolfram.com/language/ref/NextPrime.html
    -
    'NextPrime[$n$]' +
    'NextPrime'[$n$]
    gives the next prime after $n$. -
    'NextPrime[$n$,$k$]' +
    'NextPrime'[$n$,$k$]
    gives the $k$th prime after $n$.
    @@ -802,7 +802,7 @@ class PartitionsP(SympyFunction): https://reference.wolfram.com/language/ref/PartitionsP.html
    -
    'PartitionsP[$n$]' +
    'PartitionsP'[$n$]
    return the number $p$($n$) of unrestricted partitions of the integer $n$.
    @@ -827,7 +827,7 @@ class PowersRepresentations(Builtin): """ :WMA: https://reference.wolfram.com/language/ref/PowersRepresentations.html
    -
    'PowersRepresentations[$n$, $k$, $p$]' +
    'PowersRepresentations'[$n$, $k$, $p$]
    represent $n$ as a sum of $k$ non-negative integers raised to the power of $p$.
    @@ -862,8 +862,8 @@ class Prime(SympyFunction): https://reference.wolfram.com/language/ref/Prime.html
    -
    'Prime[$n$]' -
    'Prime'[{$n0$, $n1$, ...}] +
    'Prime'[$n$] +
    'Prime'[{$n_0$, $n_1$, ...}]
    returns the $n$th prime number where $n$ is an positive Integer. If given a list of integers, the return value is a list with 'Prime' applied to each.
    @@ -905,7 +905,7 @@ class PrimePi(SympyFunction): :Prime numbers:https://reference.wolfram.com/language/ref/PrimePi.html
    -
    'PrimePi[$x$]' +
    'PrimePi'[$x$]
    gives the number of primes less than or equal to $x$.
    @@ -945,7 +945,7 @@ class PrimePowerQ(Builtin): :Prime numbers:https://reference.wolfram.com/language/ref/PrimePowerQ.html
    -
    'PrimePowerQ[$n$]' +
    'PrimePowerQ'[$n$]
    returns 'True' if $n$ is a power of a prime number.
    @@ -1001,13 +1001,13 @@ class RandomPrime(Builtin): :Prime numbers:https://reference.wolfram.com/language/ref/RandomPrime.html
    -
    'RandomPrime[{$imin$, $imax}]' -
    gives a random prime between $imin$ and $imax$. +
    'RandomPrime'[{$i_{min}$, $i_{max}$}] +
    gives a random prime between $i_{min}$ and $i_{max}$. -
    'RandomPrime[$imax$]' -
    gives a random prime between 2 and $imax$. +
    'RandomPrime'[$i_{max}$] +
    gives a random prime between 2 and $i_{max}$. -
    'RandomPrime[$range$, $n$]' +
    'RandomPrime'[$range$, $n$]
    gives a list of $n$ random primes in $range$.
    @@ -1062,7 +1062,7 @@ def eval(self, interval, n, evaluation: Evaluation): py_n = n.to_python() py_int = interval.to_python() - if not (isinstance(py_int, list) and len(py_int) == 2): + if not (isinstance(py_int, (list, tuple)) and len(py_int) == 2): evaluation.message("RandomPrime", "prmrng", interval) imin, imax = min(py_int), max(py_int) @@ -1092,7 +1092,7 @@ class SquaresR(Builtin): :WMA: https://reference.wolfram.com/language/ref/SquaresR.html)
    -
    'SquaresR[$d$, $n$]' +
    'SquaresR'[$d$, $n$]
    returns the number of ways to represent $n$ as a sum of $d$ squares.
    diff --git a/mathics/builtin/numbers/randomnumbers.py b/mathics/builtin/numbers/randomnumbers.py index 5103f78c6..8355df9de 100644 --- a/mathics/builtin/numbers/randomnumbers.py +++ b/mathics/builtin/numbers/randomnumbers.py @@ -224,7 +224,7 @@ class Random(Builtin):
    'Random[]'
    gives a pseudorandom real number in the range 0 to 1. -
    'Random[$type$, $range$]' +
    'Random'[$type$, $range$]
    gives a pseudorandom number of the type $type$, in the specified interval $range$. Possible types are 'Integer', 'Real' or 'Complex'.
    @@ -269,27 +269,27 @@ class RandomChoice(_RandomSelection):
    -
    'RandomChoice[$items$]' +
    'RandomChoice'[$items$]
    randomly picks one item from $items$. -
    'RandomChoice[$items$, $n$]' +
    'RandomChoice'[$items$, $n$]
    randomly picks $n$ items from $items$. Each pick in the $n$ picks happens \ from the given set of $items$, so each item can be picked any number of times. -
    'RandomChoice[$items$, {$n1$, $n2$, ...}]' +
    'RandomChoice'[$items$, {$n_1$, $n_2$, ...}]
    randomly picks items from $items$ and arranges the picked items in the \ - nested list structure described by {$n1$, $n2$, ...}. + nested list structure described by {$n_1$, $n_2$, ...}. -
    'RandomChoice[$weights$ -> $items$, $n$]' +
    'RandomChoice'[$weights$ -> $items$, $n$]
    randomly picks $n$ items from $items$ and uses the corresponding numeric \ values in $weights$ to determine how probable it is for each item in $items$ \ to get picked (in the long run, items with higher weights will get picked \ more often than ones with lower weight). -
    'RandomChoice[$weights$ -> $items$]' +
    'RandomChoice'[$weights$ -> $items$]
    randomly picks one items from $items$ using weights $weights$. -
    'RandomChoice[$weights$ -> $items$, {$n1$, $n2$, ...}]' +
    'RandomChoice'[$weights$ -> $items$, {$n_1$, $n_2$, ...}]
    randomly picks a structured list of items from $items$ using weights \ $weights$.
    @@ -325,22 +325,22 @@ class RandomComplex(Builtin): https://reference.wolfram.com/language/ref/RandomComplex.html
    -
    'RandomComplex[{$z_min$, $z_max$}]' +
    'RandomComplex'[{$z_{min}$, $z_{max}$}]
    yields a pseudorandom complex number in the rectangle with complex corners \ - $z_min$ and $z_max$. + $z_{min}$ and $z_{max}$. -
    'RandomComplex[$z_max$]' +
    'RandomComplex'[$z_{max}$]
    yields a pseudorandom complex number in the rectangle with corners at the \ - origin and at $z_max$. + origin and at $z_{max}$.
    'RandomComplex[]'
    yields a pseudorandom complex number with real and imaginary parts from 0 \ to 1. -
    'RandomComplex[$range$, $n$]' +
    'RandomComplex'[$range$, $n$]
    gives a list of $n$ pseudorandom complex numbers. -
    'RandomComplex[$range$, {$n1$, $n2$, ...}]' +
    'RandomComplex'[$range$, {$n_1$, $n_2$, ...}]
    gives a nested list of pseudorandom complex numbers.
    @@ -424,7 +424,7 @@ def eval_list(self, zmin, zmax, ns, evaluation): return py_ns = ns.to_python() - if not isinstance(py_ns, list): + if not isinstance(py_ns, (list, tuple)): py_ns = [py_ns] if not all(isinstance(i, int) and i >= 0 for i in py_ns): @@ -440,26 +440,26 @@ def eval_list(self, zmin, zmax, ns, evaluation): class RandomInteger(Builtin): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/RandomInteger.html
    -
    'RandomInteger[{$min$, $max$}]' +
    'RandomInteger'[{$min$, $max$}]
    yields a pseudorandom integer in the range from $min$ to \ $max$ inclusive. -
    'RandomInteger[$max$]' +
    'RandomInteger'[$max$]
    yields a pseudorandom integer in the range from 0 to $max$ \ inclusive.
    'RandomInteger[]'
    gives 0 or 1. -
    'RandomInteger[$range$, $n$]' +
    'RandomInteger'[$range$, $n$]
    gives a list of $n$ pseudorandom integers. -
    'RandomInteger[$range$, {$n1$, $n2$, ...}]' +
    'RandomInteger'[$range$, {$n_1$, $n_2$, ...}]
    gives a nested list of pseudorandom integers.
    @@ -471,7 +471,7 @@ class RandomInteger(Builtin): . . ... ... ... - Calling 'RandomInteger' changes '$RandomState': + Calling 'RandomInteger' changes '\$RandomState': >> previousState = $RandomState; >> RandomInteger[] = ... @@ -524,20 +524,20 @@ class RandomReal(Builtin): https://reference.wolfram.com/language/ref/RandomReal.html
    -
    'RandomReal[{$min$, $max$}]' +
    'RandomReal'[{$min$, $max$}]
    yields a pseudorandom real number in the range from $min$ to $max$. -
    'RandomReal[$max$]' +
    'RandomReal'[$max$]
    yields a pseudorandom real number in the range from 0 to $max$.
    'RandomReal[]'
    yields a pseudorandom real number in the range from 0 to 1. -
    'RandomReal[$range$, $n$]' +
    'RandomReal'[$range$, $n$]
    gives a list of $n$ pseudorandom real numbers. -
    'RandomReal[$range$, {$n1$, $n2$, ...}]' -
    gives an $n1$ x $n2$ array of pseudorandom real numbers. +
    'RandomReal'[$range$, {$n_1$, $n_2$, ...}] +
    gives an $n_1$ x $n_2$ array of pseudorandom real numbers.
    >> RandomReal[] @@ -606,11 +606,11 @@ def eval_list(self, xmin, xmax, ns, evaluation): class RandomState(Builtin): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/RandomState.html
    -
    '$RandomState' +
    '\$RandomState'
    is a long number representing the internal state of the \ pseudo-random number generator.
    @@ -649,7 +649,7 @@ class SeedRandom(Builtin): :WMA link: https://reference.wolfram.com/language/ref/SeedRandom.html
    -
    'SeedRandom[$n$]' +
    'SeedRandom'[$n$]
    resets the pseudorandom generator with seed $n$.
    'SeedRandom[]' @@ -717,31 +717,31 @@ class RandomSample(_RandomSelection): https://reference.wolfram.com/language/ref/RandomSample.html
    -
    'RandomSample[$items$]' +
    'RandomSample'[$items$]
    randomly picks one item from $items$. -
    'RandomSample[$items$, $n$]' +
    'RandomSample'[$items$, $n$]
    randomly picks $n$ items from $items$. Each pick in the $n$ picks happens \ after the previous items picked have been removed from $items$, so each item \ can be picked at most once. -
    'RandomSample[$items$, {$n1$, $n2$, ...}]' +
    'RandomSample'[$items$, {$n_1$, $n_2$, ...}]
    randomly picks items from $items$ and arranges the picked items in the \ - nested list structure described by {$n1$, $n2$, ...}. \ + nested list structure described by {$n_1$, $n_2$, ...}. \ Each item gets picked at most once. -
    'RandomSample[$weights$ -> $items$, $n$]' +
    'RandomSample'[$weights$ -> $items$, $n$]
    randomly picks $n$ items from $items$ and uses the corresponding numeric \ values in $weights$ to determine how probable it is for each item in $items$ \ to get picked (in the long run, items with higher weights will get \ picked more often than ones with lower weight). Each item gets picked at\ most once. -
    'RandomSample[$weights$ -> $items$]' +
    'RandomSample'[$weights$ -> $items$]
    randomly picks one items from $items$ using weights $weights$. \ Each item gets picked at most once. -
    'RandomSample[$weights$ -> $items$, {$n1$, $n2$, ...}]' +
    'RandomSample'[$weights$ -> $items$, {$n_1$, $n_2$, ...}]
    randomly picks a structured list of items from $items$ using weights $weights$. Each item gets picked at most once.
    diff --git a/mathics/builtin/numbers/trig.py b/mathics/builtin/numbers/trig.py index 21a25f8e1..9a5286455 100644 --- a/mathics/builtin/numbers/trig.py +++ b/mathics/builtin/numbers/trig.py @@ -161,33 +161,33 @@ def converted_operands(): class AnglePath(Builtin): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/AnglePath.html
    -
    'AnglePath[{$phi1$, $phi2$, ...}]' +
    'AnglePath'[{$\phi_1$, $\phi_2$, ...}]
    returns the points formed by a turtle starting at {0, 0} and angled \ at 0 degrees going through - the turns given by angles $phi1$, $phi2$, ... and using distance 1 \ + the turns given by angles $\phi_1$, $\phi_2$, ... and using distance 1 \ for each step. -
    'AnglePath[{{$r1$, $phi1$}, {$r2$, $phi2$}, ...}]' -
    instead of using 1 as distance, use $r1$, $r2$, ... as distances for \ +
    'AnglePath'[{{$r_1$, $\phi_1$}, {$r_2$, $\phi_2$}, ...}] +
    instead of using 1 as distance, use $r_1$, $r_2$, ... as distances for \ the respective steps. -
    'AnglePath[$phi0$, {$phi1$, $phi2$, ...}]' -
    starts with direction $phi0$ instead of 0. +
    'AnglePath'[$\phi_0$, {$\phi_1$, $\phi_2$, ...}] +
    starts with direction $\phi_0$ instead of 0. -
    'AnglePath[{$x$, $y$}, {$phi1$, $phi2$, ...}]' -
    starts at {$x, $y} instead of {0, 0}. +
    'AnglePath'[{$x$, $y$}, {$\phi_1$, $\phi_2$, ...}] +
    starts at {$x$, $y$} instead of {0, 0}. -
    'AnglePath[{{$x$, $y$}, $phi0$}, {$phi1$, $phi2$, ...}]' -
    specifies initial position {$x$, $y$} and initial direction $phi0$. +
    'AnglePath'[{{$x$, $y$}, $\phi_0$}, {$\phi_1$, $\phi_2$, ...}] +
    specifies initial position {$x$, $y$} and initial direction $\phi_0$. -
    'AnglePath[{{$x$, $y$}, {$dx$, $dy$}}, {$phi1$, $phi2$, ...}]' -
    specifies initial position {$x$, $y$} and a slope {$dx$, $dy$} that is \ +
    'AnglePath'[{{$x$, $y$}, {$d_x$, $d_y$}}, {$\phi_1$, $\phi_2$, ...}] +
    specifies initial position {$x$, $y$} and a slope {$d_x$, $d_y$} that is \ understood to be the initial direction of the turtle.
    @@ -346,7 +346,7 @@ class ArcCos(MPMathFunction): https://reference.wolfram.com/language/ref/ArcCos.html)
    -
    'ArcCos[$z$]' +
    'ArcCos'[$z$]
    returns the inverse cosine of $z$.
    @@ -383,7 +383,7 @@ class ArcCot(MPMathFunction): https://reference.wolfram.com/language/ref/ArcCot.html)
    -
    'ArcCot[$z$]' +
    'ArcCot'[$z$]
    returns the inverse cotangent of $z$.
    @@ -418,7 +418,7 @@ class ArcCsc(MPMathFunction): https://reference.wolfram.com/language/ref/ArcCsc.html)
    -
    'ArcCsc[$z$]' +
    'ArcCsc'[$z$]
    returns the inverse cosecant of $z$.
    @@ -459,7 +459,7 @@ class ArcSec(MPMathFunction): https://reference.wolfram.com/language/ref/ArcSec.html)
    -
    'ArcSec[$z$]' +
    'ArcSec'[$z$]
    returns the inverse secant of $z$.
    @@ -501,7 +501,7 @@ class ArcSin(MPMathFunction): https://reference.wolfram.com/language/ref/ArcSin.html)
    -
    'ArcSin[$z$]' +
    'ArcSin'[$z$]
    returns the inverse sine of $z$.
    @@ -537,7 +537,7 @@ class ArcTan(MPMathFunction): https://reference.wolfram.com/language/ref/ArcTan.html)
    -
    'ArcTan[$z$]' +
    'ArcTan'[$z$]
    returns the inverse tangent of $z$.
    @@ -583,7 +583,7 @@ class Cos(MPMathFunction): https://reference.wolfram.com/language/ref/Cos.html)
    -
    'Cos[$z$]' +
    'Cos'[$z$]
    returns the cosine of $z$.
    @@ -619,7 +619,7 @@ class Cot(MPMathFunction): https://reference.wolfram.com/language/ref/Cot.html)
    -
    'Cot[$z$]' +
    'Cot'[$z$]
    returns the cotangent of $z$.
    @@ -654,7 +654,7 @@ class Csc(MPMathFunction): https://reference.wolfram.com/language/ref/Csc.html)
    -
    'Csc[$z$]' +
    'Csc'[$z$]
    returns the cosecant of $z$.
    @@ -691,7 +691,7 @@ class Haversine(MPMathFunction): https://reference.wolfram.com/language/ref/Haversine.html
    -
    'Haversine[$z$]' +
    'Haversine'[$z$]
    returns the haversine function of $z$.
    @@ -713,7 +713,7 @@ class InverseHaversine(MPMathFunction): https://reference.wolfram.com/language/ref/InverseHaversine.html
    -
    'InverseHaversine[$z$]' +
    'InverseHaversine'[$z$]
    returns the inverse haversine function of $z$.
    @@ -741,7 +741,7 @@ class Sec(MPMathFunction): https://reference.wolfram.com/language/ref/Sec.html)
    -
    'Sec[$z$]' +
    'Sec'[$z$]
    returns the secant of $z$.
    @@ -783,7 +783,7 @@ class Sin(MPMathFunction): https://reference.wolfram.com/language/ref/Sin.html)
    -
    'Sin[$z$]' +
    'Sin'[$z$]
    returns the sine of $z$.
    @@ -827,7 +827,7 @@ class Tan(MPMathFunction): https://reference.wolfram.com/language/ref/Tan.html)
    -
    'Tan[$z$]' +
    'Tan'[$z$]
    returns the tangent of $z$.
    diff --git a/mathics/builtin/numeric.py b/mathics/builtin/numeric.py index d683fa94f..2d59b1e97 100644 --- a/mathics/builtin/numeric.py +++ b/mathics/builtin/numeric.py @@ -88,7 +88,7 @@ class Abs(MPMathFunction): :WMA: https://reference.wolfram.com/language/ref/Abs)
    -
    'Abs[$x$]' +
    'Abs'[$x$]
    returns the absolute value of $x$.
    @@ -130,10 +130,10 @@ class Chop(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Chop.html
    -
    'Chop[$expr$]' +
    'Chop'[$expr$]
    replaces floating point numbers close to 0 by 0. -
    'Chop[$expr$, $delta$]' +
    'Chop'[$expr$, $delta$]
    uses a tolerance of $delta$. The default tolerance is '10^-10'.
    @@ -174,7 +174,7 @@ class N(Builtin): https://reference.wolfram.com/language/ref/N.html
    -
    'N[$expr$, $prec$]' +
    'N'[$expr$, $prec$]
    evaluates $expr$ numerically with a precision of $prec$ digits.
    @@ -423,12 +423,12 @@ class Rationalize(Builtin): https://reference.wolfram.com/language/ref/Rationalize.html
    -
    'Rationalize[$x$]' +
    'Rationalize'[$x$]
    converts a real number $x$ to a nearby rational number with \ small denominator. -
    'Rationalize[$x$, $dx$]' -
    finds the rational number lies within $dx$ of $x$. +
    'Rationalize'[$x$, $d_x$] +
    finds the rational number lies within $d_x$ of $x$.
    >> Rationalize[2.2] @@ -556,7 +556,7 @@ class RealAbs(Builtin): https://reference.wolfram.com/language/ref/RealAbs.html)
    -
    'RealAbs[$x$]' +
    'RealAbs'[$x$]
    returns the absolute value of a real number $x$.
    @@ -598,7 +598,7 @@ class RealSign(Builtin): https://reference.wolfram.com/language/ref/RealSign.html)
    -
    'RealSign[$x$]' +
    'RealSign'[$x$]
    returns -1, 0 or 1 depending on whether $x$ is negative, zero or positive.
    @@ -662,10 +662,10 @@ class Round(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Round.html
    -
    'Round[$expr$]' +
    'Round'[$expr$]
    rounds $expr$ to the nearest integer. -
    'Round[$expr$, $k$]' +
    'Round'[$expr$, $k$]
    rounds $expr$ to the closest multiple of $k$.
    @@ -741,7 +741,7 @@ class Sign(SympyFunction): https://reference.wolfram.com/language/ref/Sign.html)
    -
    'Sign[$x$]' +
    'Sign'[$x$]
    return -1, 0, or 1 depending on whether $x$ is negative, zero, or positive.
    @@ -801,9 +801,9 @@ class UnitStep(Builtin): https://reference.wolfram.com/language/ref/UnitStep.html)
    -
    'UnitStep[$x$]' +
    'UnitStep'[$x$]
    return 0 if $x$ < 0, and 1 if $x$ >= 0. -
    'UnitStep[$x1$, $x2$, ...]' +
    'UnitStep'[$x_1$, $x_2$, ...]
    return the multidimensional unit step function which is 1 only if none of the $xi$ are negative.
    diff --git a/mathics/builtin/optimization.py b/mathics/builtin/optimization.py index c8ac562c4..bda30f5c4 100644 --- a/mathics/builtin/optimization.py +++ b/mathics/builtin/optimization.py @@ -39,7 +39,7 @@ class Maximize(Builtin): https://reference.wolfram.com/language/ref/Maximize.html
    -
    'Maximize[$f$, $x$]' +
    'Maximize'[$f$, $x$]
    compute the maximum of $f$ respect $x$ that change between \ $a$ and $b$.
    @@ -95,7 +95,7 @@ class Minimize(Builtin): https://reference.wolfram.com/language/ref/Minimize.html
    -
    'Minimize[$f$, $x$]' +
    'Minimize'[$f$, $x$]
    compute the minimum of $f$ respect $x$ that change between \ $a$ and $b$.
    @@ -120,9 +120,6 @@ def eval_onevariable(self, f, x, evaluation: Evaluation): for candidate in candidates: value = second_derivative.subs(candidate) if value.is_real and value > 0: - if candidate is not list: - candidate = candidate - minimum_list.append([candidate[sympy_x], sympy_f.subs(candidate)]) return ListExpression( diff --git a/mathics/builtin/options.py b/mathics/builtin/options.py index 278dbc6f2..b1f2c9037 100644 --- a/mathics/builtin/options.py +++ b/mathics/builtin/options.py @@ -12,7 +12,7 @@ """ from mathics.builtin.image.base import Image -from mathics.core.atoms import String +from mathics.core.atoms import Integer1, String from mathics.core.builtin import Builtin, Predefined, Test, get_option from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression @@ -77,14 +77,14 @@ class Default(Builtin): https://reference.wolfram.com/language/ref/Default.html
    -
    'Default[$f$]' +
    'Default'[$f$]
    gives the default value for an omitted parameter of $f$. -
    'Default[$f$, $k$]' -
    gives the default value for a parameter on the $k$th position. +
    'Default'[$f$, $k$] +
    gives the default value for a parameter on the $k$-th position. -
    'Default[$f$, $k$, $n$]' -
    gives the default value for the $k$th parameter out of $n$. +
    'Default'[$f$, $k$, $n$] +
    gives the default value for the $k$-th parameter out of $n$.
    Assign values to 'Default' to specify default values. @@ -135,11 +135,11 @@ class FilterRules(Builtin): https://reference.wolfram.com/language/ref/FilterRules.html
    -
    'FilterRules[$rules$, $pattern$]' +
    'FilterRules'[$rules$, $pattern$]
    gives those $rules$ that have a left side that matches $pattern$. -
    'FilterRules[$rules$, {$pattern1$, $pattern2$, ...}]' -
    gives those $rules$ that have a left side that match at least one of $pattern1$, $pattern2$, ... +
    'FilterRules'[$rules$, {$pattern_1$, $pattern_2$, ...}] +
    gives those $rules$ that have a left side that match at least one of $pattern_1$, $pattern_2$, ...
    >> FilterRules[{x -> 100, y -> 1000}, x] @@ -200,7 +200,7 @@ class NotOptionQ(Test): https://reference.wolfram.com/language/ref/NotOptionQ.html
    -
    'NotOptionQ[$expr$]' +
    'NotOptionQ'[$expr$]
    returns 'True' if $expr$ does not have the form of a valid \ option specification.
    @@ -238,7 +238,7 @@ class OptionQ(Test): https://reference.wolfram.com/language/ref/OptionQ.html
    -
    'OptionQ[$expr$]' +
    'OptionQ'[$expr$]
    returns 'True' if $expr$ has the form of a valid option \ specification.
    @@ -290,7 +290,7 @@ class Options(Builtin): https://reference.wolfram.com/language/ref/Options.html
    -
    'Options[$f$]' +
    'Options'[$f$]
    gives a list of optional arguments to $f$ and their \ default values.
    @@ -329,6 +329,13 @@ class Options(Builtin): >> Options[a + b] = {a -> b} : Argument a + b at position 1 is expected to be a symbol. = {a -> b} + + See also + :'OptionValue': + /doc/reference-of-built-in-symbols/options-management/optionsvalue/ and + :'OptionsPattern': + /doc/reference-of-built-in-symbols/rules-and-patterns/composite-patterns/optionspattern/. + """ summary_text = "the list of optional arguments and their default values" @@ -342,7 +349,7 @@ def eval(self, f, evaluation): # FIXME ColorSpace, MetaInformation options = f.metadata else: - evaluation.message("Options", "sym", f, 1) + evaluation.message("Options", "sym", f, Integer1) return else: options = evaluation.definitions.get_options(name) @@ -361,38 +368,62 @@ class OptionValue(Builtin): https://reference.wolfram.com/language/ref/OptionValue.html
    -
    'OptionValue[$name$]' -
    gives the value of the option $name$ as specified in a call to a function with 'OptionsPattern'. +
    'OptionValue'[$name$] +
    gives the value of the option $name$ matched by 'OptionsPattern'. -
    'OptionValue[$f$, $name$]' -
    recover the value of the option $name$ associated to the symbol $f$. +
    'OptionValue'[$f$, $name$] +
    recover the value of the option $name$ associated with the head $f$. -
    'OptionValue[$f$, $optvals$, $name$]' -
    recover the value of the option $name$ associated to the symbol $f$, extracting the values from $optvals$ if available. +
    'OptionValue'[$f$, $opts$, $name$] +
    recover the value of the option $name$ associated with the symbol $f$, extracting the values from $optvals$ if available. -
    'OptionValue[..., $list$]' +
    'OptionValue'[..., $list$]
    recover the value of the options in $list$ .
    + First, set up a symbol with some options using 'Options': + >> Options[MySetting] = {"foo" -> 5, "bar" -> 6} + = {foo -> 5, bar -> 6} + + Now get a value previously set: + + >> OptionValue[MySetting, "bar"] + = 6 + + If the option does exist we get a message: + >> OptionValue[MySetting, "baz"] + : Option name baz not found in defaults for MySetting. + = baz + + Use 'OptionValue' to get the value of option 'a' inside 'OptionsPattern' 'a->3' >> f[a->3] /. f[OptionsPattern[{}]] -> {OptionValue[a]} = {3} - Unavailable options generate a message: + An unavailable option returns argument and does not generate a message: >> f[a->3] /. f[OptionsPattern[{}]] -> {OptionValue[b]} - : Option name b not found. = {b} The argument of 'OptionValue' must be a symbol: >> f[a->3] /. f[OptionsPattern[{}]] -> {OptionValue[a+b]} : Argument a + b at position 1 is expected to be a symbol. = {OptionValue[a + b]} - However, it can be evaluated dynamically: + + However, the symbol can be evaluated dynamically: >> f[a->5] /. f[OptionsPattern[{}]] -> {OptionValue[Symbol["a"]]} = {5} + + + #> Clear[MySetting] + + See also + :'Options': + /doc/reference-of-built-in-symbols/options-management/options/ and + :'OptionsPattern': + /doc/reference-of-built-in-symbols/rules-and-patterns/composite-patterns/optionspattern/. """ messages = { - "optnf": "Option name `1` not found.", + "optnf": "Option name `1` not found in defaults for `2`.", } rules = { @@ -418,21 +449,20 @@ def eval(self, optname, evaluation): if name: name = ensure_context(name) if not name: - evaluation.message("OptionValue", "sym", optname, 1) + evaluation.message("OptionValue", "sym", optname, Integer1) return val = get_option(evaluation.options, name, evaluation) if val is None: - evaluation.message("OptionValue", "optnf", optname) return Symbol(name) return val def eval_with_f(self, f, optname, evaluation): "OptionValue[f_, optname_]" - return self.eval_with_f_and_optvals(f, None, optname, evaluation) + return self.eval_with_f_and_opts(f, None, optname, evaluation) - def eval_with_f_and_optvals(self, f, optvals, optname, evaluation): - "OptionValue[f_, optvals_, optname_]" + def eval_with_f_and_opts(self, f, opts, optname, evaluation): + "OptionValue[f_, opts_, optname_]" if type(optname) is String: name = optname.to_python()[1:-1] else: @@ -446,11 +476,14 @@ def eval_with_f_and_optvals(self, f, optvals, optname, evaluation): evaluation.message("OptionValue", "sym", optname, 1) return # Look first in the explicit list - if optvals: - val = get_option(optvals.get_option_values(evaluation), name, evaluation) + if opts: + if (options_values := opts.get_option_values(evaluation)) is None: + evaluation.message("OptionValue", "optnf", optname, f) + return + val = get_option(options_values, name, evaluation) else: val = None - # then, if not found, look at $f$. It could be a symbol, or a list of symbols, rules, and list of rules... + # then, if not found, look at f. It could be a symbol, or a list of symbols, rules, and list of rules... if val is None: if isinstance(f, Symbol): val = get_option( @@ -471,14 +504,15 @@ def eval_with_f_and_optvals(self, f, optvals, optname, evaluation): break else: values = element.get_option_values(evaluation) - val = get_option(values, name, evaluation) - if val: - break + if values: + val = get_option(values, name, evaluation) + if val: + break if val is None and evaluation.options: val = get_option(evaluation.options, name, evaluation) if val is None: - evaluation.message("OptionValue", "optnf", optname) + evaluation.message("OptionValue", "optnf", optname, f) return Symbol(name) return val @@ -490,7 +524,7 @@ class SetOptions(Builtin): https://reference.wolfram.com/language/ref/SetOptions.html
    -
    'SetOptions[$s$, name1 -> value1, name2 -> value2, ...]' +
    'SetOptions'[$s$, name1 -> value1, name2 -> value2, ...]
    sets the specified default options for a symbol $s$. \ The entire set of options for $s$ is returned.
    @@ -523,7 +557,7 @@ def eval(self, symbol: Symbol, options: Expression, evaluation: Evaluation): if isinstance(element, Symbol): option_symbol = element option_value = next(options_pairs) - elif element.head is SymbolRule: + elif hasattr(element, "head") and element.head is SymbolRule: option_symbol, option_value = element.elements else: evaluation.message("SetOptions", "rep", element) diff --git a/mathics/builtin/patterns/basic.py b/mathics/builtin/patterns/basic.py index ee9349401..1aade29b3 100644 --- a/mathics/builtin/patterns/basic.py +++ b/mathics/builtin/patterns/basic.py @@ -10,6 +10,7 @@ from mathics.core.builtin import PatternObject from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression +from mathics.core.symbols import BaseElement # This tells documentation how to sort this module sort_order = "mathics.builtin.rules-and-patterns.basic" @@ -55,7 +56,7 @@ class Blank(_Blank):
    'Blank[]'
    '_'
    represents any single expression in a pattern. -
    'Blank[$h$]' +
    'Blank'[$h$]
    '_$h$'
    represents any expression with head $h$.
    @@ -89,7 +90,7 @@ class Blank(_Blank): } summary_text = "match to any single expression" - def match(self, expression: Expression, pattern_context: dict): + def match(self, expression: BaseElement, pattern_context: dict): vars_dict = pattern_context["vars_dict"] yield_func = pattern_context["yield_func"] @@ -153,7 +154,7 @@ class BlankSequence(_Blank):
    '__'
    represents any non-empty sequence of expression elements in \ a pattern. -
    'BlankSequence[$h$]' +
    'BlankSequence'[$h$]
    '__$h$'
    represents any sequence of elements, all of which have head $h$.
    diff --git a/mathics/builtin/patterns/composite.py b/mathics/builtin/patterns/composite.py index b3a85938b..473c01381 100644 --- a/mathics/builtin/patterns/composite.py +++ b/mathics/builtin/patterns/composite.py @@ -30,9 +30,9 @@ class Alternatives(InfixOperator, PatternObject): https://reference.wolfram.com/language/ref/Alternatives.html
    -
    'Alternatives[$p1$, $p2$, ..., $p_i$]' -
    '$p1$ | $p2$ | ... | $p_i$' -
    is a pattern that matches any of the patterns $p1$, $p2$, \ +
    'Alternatives'[$p_1$, $p_2$, ..., $p_i$] +
    $p_1$ '|' $p_2$ '|' ... '|' $p_i$ +
    is a pattern that matches any of the patterns $p_1$, $p_2$, \ ...., $p_i$.
    @@ -87,11 +87,11 @@ class Except(PatternObject): https://reference.wolfram.com/language/ref/Except.html
    -
    'Except[$c$]' +
    'Except'[$c$]
    represents a pattern object that matches any expression except \ those matching $c$. -
    'Except[$c$, $p$]' +
    'Except'[$c$, $p$]
    represents a pattern object that matches $p$ but not $c$.
    @@ -142,7 +142,7 @@ class HoldPattern(PatternObject): :WMA link:https://reference.wolfram.com/language/ref/HoldPattern.html
    -
    'HoldPattern[$expr$]' +
    'HoldPattern'[$expr$]
    is equivalent to $expr$ for pattern matching, but \ maintains it in an unevaluated form.
    @@ -181,7 +181,7 @@ class Longest(Builtin): https://reference.wolfram.com/language/ref/Longest.html
    -
    'Longest[$pat$]' +
    'Longest'[$pat$]
    is a pattern object that matches the longest sequence consistent \ with the pattern $pat$.
    @@ -203,13 +203,13 @@ class OptionsPattern(PatternObject): https://reference.wolfram.com/language/ref/OptionsPattern.html
    -
    'OptionsPattern[$f$]' +
    'OptionsPattern'[$f$]
    is a pattern that stands for a sequence of options given \ to a function, with default values taken from 'Options[$f$]'. \ The options can be of the form '$opt$->$value$' or \ '$opt$:>$value$', and might be in arbitrarily nested lists. -
    'OptionsPattern[{$opt1$->$value1$, ...}]' +
    'OptionsPattern'[{$opt_1$->$value_1$, ...}]
    takes explicit default values from the given list. The \ list may also contain symbols $f$, for which 'Options[$f$]' is \ taken into account; it may be arbitrarily nested. \ @@ -234,6 +234,12 @@ class OptionsPattern(PatternObject): Options might be given in nested lists: >> f[x, {{{n->4}}}] = x ^ 4 + + See also + :'Options': + /doc/reference-of-built-in-symbols/options-management/options/ and + :'OptionValue': + /doc/reference-of-built-in-symbols/options-management/optionvalue/. """ arg_counts = [0, 1] @@ -308,15 +314,15 @@ class Pattern(PatternObject): :WMA link:https://reference.wolfram.com/language/ref/Pattern.html
    -
    'Pattern[$symb$, $pat$]' -
    '$symb$ : $pat$' +
    'Pattern'[$symb$, $pat$] +
    $symb$ ':' $pat$
    assigns the name $symb$ to the pattern $pat$. -
    '$symb$_$head$' -
    is equivalent to '$symb$ : _$head$' (accordingly with '__' \ +
    $symb$'_'$head$ +
    is equivalent to $symb$' : _'$head$ (accordingly with '__' \ and '___'). -
    '$symb$ : $pat$ : $default$' +
    $symb$' : '$pat$' : '$default$
    is a pattern with name $symb$ and default value $default$, \ - equivalent to 'Optional[$pat$ : $symb$, $default$]'. + equivalent to 'Optional'[$pat$ : $symb$, $default$].
    >> FullForm[a_b] @@ -448,7 +454,7 @@ class Repeated(PostfixOperator, PatternObject): :WMA link:https://reference.wolfram.com/language/ref/Repeated.html
    -
    'Repeated[$pat$]' +
    'Repeated'[$pat$]
    matches one or more occurrences of $pat$.
    @@ -539,7 +545,7 @@ class RepeatedNull(Repeated): :WMA link:https://reference.wolfram.com/language/ref/RepeatedNull.html
    -
    'RepeatedNull[$pat$]' +
    'RepeatedNull'[$pat$]
    matches zero or more occurrences of $pat$.
    @@ -562,7 +568,7 @@ class Shortest(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Shortest.html
    -
    'Shortest[$pat$]' +
    'Shortest'[$pat$]
    is a pattern object that matches the shortest sequence consistent with the pattern $pat$.
    @@ -583,7 +589,7 @@ class Verbatim(PatternObject): https://reference.wolfram.com/language/ref/Verbatim.html
    -
    'Verbatim[$expr$]' +
    'Verbatim'[$expr$]
    prevents pattern constructs in $expr$ from taking effect, \ allowing them to match themselves.
    diff --git a/mathics/builtin/patterns/defaults.py b/mathics/builtin/patterns/defaults.py index e3b3798e2..e5cb24fbb 100644 --- a/mathics/builtin/patterns/defaults.py +++ b/mathics/builtin/patterns/defaults.py @@ -23,7 +23,7 @@ class Optional(InfixOperator, PatternObject): :WMA link:https://reference.wolfram.com/language/ref/Optional.html
    -
    'Optional[$pattern$, $default$]' +
    'Optional'[$pattern$, $default$]
    '$pattern$ : $default$'
    is a pattern which matches $pattern$, which if omitted should be replaced by $default$. diff --git a/mathics/builtin/patterns/restrictions.py b/mathics/builtin/patterns/restrictions.py index 6b7bf1ff6..7b7a3fe7d 100644 --- a/mathics/builtin/patterns/restrictions.py +++ b/mathics/builtin/patterns/restrictions.py @@ -25,7 +25,7 @@ class Condition(InfixOperator, PatternObject): https://reference.wolfram.com/language/ref/Condition.html
    -
    'Condition[$pattern$, $expr$]' +
    'Condition'[$pattern$, $expr$]
    '$pattern$ /; $expr$'
    places an additional constraint on $pattern$ that only \ allows it to match if $expr$ evaluates to 'True'. @@ -89,7 +89,7 @@ class PatternTest(InfixOperator, PatternObject): https://reference.wolfram.com/language/ref/PatternTest.html
    -
    'PatternTest[$pattern$, $test$]' +
    'PatternTest'[$pattern$, $test$]
    '$pattern$ ? $test$'
    constrains $pattern$ to match $expr$ only if the \ evaluation of '$test$[$expr$]' yields 'True'. diff --git a/mathics/builtin/patterns/rules.py b/mathics/builtin/patterns/rules.py index dca5e0297..57d4d2aee 100644 --- a/mathics/builtin/patterns/rules.py +++ b/mathics/builtin/patterns/rules.py @@ -99,10 +99,10 @@ class DispatchAtom(AtomBuiltin): """ :WMA link: - https://reference.wolfram.com/language/ref/DispatchAtom.html + https://reference.wolfram.com/language/ref/Dispatch.html
    -
    'Dispatch[$rulelist$]' +
    'Dispatch'[$rulelist$]
    Introduced for compatibility. Currently, it just return $rulelist$. \ In the future, it should return an optimized DispatchRules atom, \ containing an optimized set of rules. @@ -135,7 +135,7 @@ def eval_list( self, rules: ListExpression, evaluation: Evaluation ) -> OptionalType[BaseElement]: """Dispatch[rules_List]""" - result = eval_dispatch_atom(rules, evaluation) + result = eval_dispatch_atom(rules.elements, evaluation) return result def eval( @@ -174,16 +174,16 @@ class Replace(Builtin): https://reference.wolfram.com/language/ref/Replace.html
    -
    'Replace[$expr$, $x$ -> $y$]' +
    'Replace'[$expr$, $x$ -> $y$]
    yields the result of replacing $expr$ with $y$ if it \ matches the pattern $x$. -
    'Replace[$expr$, $x$ -> $y$, $levelspec$]' +
    'Replace'[$expr$, $x$ -> $y$, $levelspec$]
    replaces only subexpressions at levels specified through \ $levelspec$. -
    'Replace[$expr$, {$x$ -> $y$, ...}]' +
    'Replace'[$expr$, {$x$ -> $y$, ...}]
    performs replacement with multiple rules, yielding a \ single result expression. -
    'Replace[$expr$, {{$a$ -> $b$, ...}, {$c$ -> $d$, ...}, ...}]' +
    'Replace'[$expr$, {{$a$ -> $b$, ...}, {$c$ -> $d$, ...}, ...}]
    returns a list containing the result of performing each \ set of replacements.
    @@ -254,7 +254,7 @@ class ReplaceAll(InfixOperator): https://reference.wolfram.com/language/ref/ReplaceAll.html
    -
    'ReplaceAll[$expr$, $x$ -> $y$]' +
    'ReplaceAll'[$expr$, $x$ -> $y$]
    '$expr$ /. $x$ -> $y$'
    yields the result of replacing all subexpressions of \ $expr$ matching the pattern $x$ with $y$. @@ -322,10 +322,10 @@ class ReplaceList(Builtin): https://reference.wolfram.com/language/ref/ReplaceList.html
    -
    'ReplaceList[$expr$, $rules$]' +
    'ReplaceList'[$expr$, $rules$]
    returns a list of all possible results when applying $rules$ \ to $expr$. -
    'ReplaceList[$expr$, $rules$, $n$]' +
    'ReplaceList'[$expr$, $rules$, $n$]
    returns a list of at most $n$ results when applying $rules$ \ to $expr$.
    @@ -409,7 +409,7 @@ class ReplaceRepeated(InfixOperator): https://reference.wolfram.com/language/ref/ReplaceRepeated.html
    -
    'ReplaceRepeated[$expr$, $x$ -> $y$]' +
    'ReplaceRepeated'[$expr$, $x$ -> $y$]
    '$expr$ //. $x$ -> $y$'
    repeatedly applies the rule '$x$ -> $y$' to $expr$ until the result no longer changes. @@ -494,7 +494,7 @@ class Rule_(InfixOperator): :WMA link:https://reference.wolfram.com/language/ref/Rule_.html
    -
    'Rule[$x$, $y$]' +
    'Rule'[$x$, $y$]
    '$x$ -> $y$'
    represents a rule replacing $x$ with $y$.
    @@ -531,7 +531,7 @@ class RuleDelayed(InfixOperator): :WMA link:https://reference.wolfram.com/language/ref/RuleDelayed.html
    -
    'RuleDelayed[$x$, $y$]' +
    'RuleDelayed'[$x$, $y$]
    '$x$ :> $y$'
    represents a rule replacing $x$ with $y$, with $y$ held \ unevaluated. diff --git a/mathics/builtin/physchemdata.py b/mathics/builtin/physchemdata.py index 51d016e65..ddfba9633 100644 --- a/mathics/builtin/physchemdata.py +++ b/mathics/builtin/physchemdata.py @@ -47,11 +47,11 @@ class ElementData(Builtin): :WMA link:https://reference.wolfram.com/language/ref/ElementData.html
    -
    'ElementData["$name$", "$property$"]' +
    'ElementData'["$name$", "$property$"]
    gives the value of the $property$ for the chemical specified by $name$. -
    'ElementData[$n$, "$property$"]' -
    gives the value of the $property$ for the $n$th chemical element. +
    'ElementData'[$n$, "$property$"] +
    gives the value of the $property$ for the $n$-th chemical element.
    >> ElementData[74] diff --git a/mathics/builtin/procedural.py b/mathics/builtin/procedural.py index 6544cf401..2bee12ffc 100644 --- a/mathics/builtin/procedural.py +++ b/mathics/builtin/procedural.py @@ -41,13 +41,13 @@ class Abort(Builtin): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/Abort.html
    'Abort[]' -
    aborts an evaluation completely and returns '$Aborted'. +
    aborts an evaluation completely and returns '\$Aborted'.
    >> Print["a"]; Abort[]; Print["b"] @@ -95,15 +95,15 @@ class Catch(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Catch.html
    -
    'Catch[$expr$]' +
    'Catch'[$expr$]
    returns the argument of the first 'Throw' generated in the evaluation of $expr$. -
    'Catch[$expr$, $form$]' +
    'Catch'[$expr$, $form$]
    returns value from the first 'Throw[$value$, $tag$]' for which $form$ matches $tag$. -
    'Catch[$expr$, $form$, $f$]' +
    'Catch'[$expr$, $form$, $f$]
    returns $f$[$value$, $tag$].
    @@ -158,7 +158,7 @@ class CheckAbort(Builtin): https://reference.wolfram.com/language/ref/CheckAbort.html
    -
    'CheckAbort[$expr$, $failexpr$]' +
    'CheckAbort'[$expr$, $failexpr$]
    evaluates $expr$, returning $failexpr$ if an abort occurs.
    @@ -188,8 +188,8 @@ class CompoundExpression(InfixOperator): https://reference.wolfram.com/language/ref/CompoundExpression.html
    -
    'CompoundExpression[$e1$, $e2$, ...]' -
    '$e1$; $e2$; ...' +
    'CompoundExpression'[$e_1$, $e_2$, ...] +
    $e_1$';' $e_2$';' ...
    evaluates its arguments in turn, returning the last result.
    @@ -255,25 +255,25 @@ class Do(IterationFunction): :WMA link:https://reference.wolfram.com/language/ref/Do.html
    -
    'Do[$expr$, {$max$}]' +
    'Do'[$expr$, {$max$}]
    evaluates $expr$ $max$ times. -
    'Do[$expr$, {$i$, $max$}]' +
    'Do'[$expr$, {$i$, $max$}]
    evaluates $expr$ $max$ times, substituting $i$ in $expr$ with values from 1 to $max$. -
    'Do[$expr$, {$i$, $min$, $max$}]' +
    'Do'[$expr$, {$i$, $min$, $max$}]
    starts with '$i$ = $max$'. -
    'Do[$expr$, {$i$, $min$, $max$, $step$}]' +
    'Do'[$expr$, {$i$, $min$, $max$, $step$}]
    uses a step size of $step$. -
    'Do[$expr$, {$i$, {$i1$, $i2$, ...}}]' -
    uses values $i1$, $i2$, ... for $i$. +
    'Do'[$expr$, {$i$, {$i_1$, $i_2$, ...}}] +
    uses values $i_1$, $i_2$, ... for $i$. -
    'Do[$expr$, {$i$, $imin$, $imax$}, {$j$, $jmin$, $jmax$}, ...]' -
    evaluates $expr$ for each $j$ from $jmin$ to $jmax$, for each $i$ from $imin$ - to $imax$, etc. +
    'Do'[$expr$, {$i$, $i_{min}$, $i_{max}$}, {$j$, $j_{min}$, $j_{max}$}, ...] +
    evaluates $expr$ for each $j$ from $j_{min}$ to $j_{max}$, for each $i$ from $i_{min}$ + to $i_{max}$, etc.
    >> Do[Print[i], {i, 2, 4}] @@ -306,14 +306,14 @@ class For(Builtin): :WMA link:https://reference.wolfram.com/language/ref/For.html
    -
    'For[$start$, $test$, $incr$, $body$]' +
    'For'[$start$, $test$, $incr$, $body$]
    evaluates $start$, and then iteratively $body$ and $incr$ as long as $test$ evaluates to 'True'. -
    'For[$start$, $test$, $incr$]' +
    'For'[$start$, $test$, $incr$]
    evaluates only $incr$ and no $body$. -
    'For[$start$, $test$]' +
    'For'[$start$, $test$]
    runs the loop without any body.
    @@ -358,14 +358,14 @@ class If(Builtin): :WMA link:https://reference.wolfram.com/language/ref/If.html
    -
    'If[$cond$, $pos$, $neg$]' +
    'If'[$cond$, $pos$, $neg$]
    returns $pos$ if $cond$ evaluates to 'True', and $neg$ if it evaluates to 'False'. -
    'If[$cond$, $pos$, $neg$, $other$]' +
    'If'[$cond$, $pos$, $neg$, $other$]
    returns $other$ if $cond$ evaluates to neither 'True' nor 'False'. -
    'If[$cond$, $pos$]' +
    'If'[$cond$, $pos$]
    returns 'Null' if $cond$ evaluates to 'False'.
    @@ -416,12 +416,12 @@ def eval_with_false_and_other(self, condition, t, f, u, evaluation): class Interrupt(Builtin): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/Interrupt.html
    'Interrupt[]' -
    Interrupt an evaluation and returns '$Aborted'. +
    Interrupt an evaluation and returns '\$Aborted'.
    >> Print["a"]; Interrupt[]; Print["b"] @@ -477,7 +477,7 @@ class Return(Builtin): https://reference.wolfram.com/language/ref/Return.html
    -
    'Return[$expr$]' +
    'Return'[$expr$]
    aborts a function call and returns $expr$.
    @@ -516,7 +516,7 @@ class Switch(Builtin): https://reference.wolfram.com/language/ref/Switch.html
    -
    'Switch[$expr$, $pattern1$, $value1$, $pattern2$, $value2$, ...]' +
    'Switch'[$expr$, $pattern_1$, $value_1$, $pattern_2$, $value_2$, ...]
    yields the first $value$ for which $expr$ matches the corresponding \ $pattern$.
    @@ -617,8 +617,8 @@ class Which(Builtin): https://reference.wolfram.com/language/ref/Which.html
    -
    'Which[$cond1$, $expr1$, $cond2$, $expr2$, ...]' -
    yields $expr1$ if $cond1$ evaluates to 'True', $expr2$ if $cond2$ \ +
    'Which'[$cond_1$, $expr_1$, $cond_2$, $expr_2$, ...] +
    yields $expr_1$ if $cond_1$ evaluates to 'True', $expr_2$ if $cond_2$ \ evaluates to 'True', etc.
    @@ -679,10 +679,10 @@ class While(Builtin): https://reference.wolfram.com/language/ref/While.html
    -
    'While[$test$, $body$]' +
    'While'[$test$, $body$]
    evaluates $body$ as long as $test$ evaluates to 'True'. -
    'While[$test$]' +
    'While'[$test$]
    runs the loop without any body.
    diff --git a/mathics/builtin/quantities.py b/mathics/builtin/quantities.py index be77227ef..c9905fe77 100644 --- a/mathics/builtin/quantities.py +++ b/mathics/builtin/quantities.py @@ -42,7 +42,7 @@ class KnownUnitQ(Test): https://reference.wolfram.com/language/ref/KnownUnitQ.html
    -
    'KnownUnitQ[$unit$]' +
    'KnownUnitQ'[$unit$]
    returns True if $unit$ is a canonical unit, and False otherwise.
    @@ -69,10 +69,10 @@ class Quantity(Builtin): https://reference.wolfram.com/language/ref/Quantity.html
    -
    'Quantity[$magnitude$, $unit$]' +
    'Quantity'[$magnitude$, $unit$]
    represents a quantity with size $magnitude$ and unit specified by $unit$. -
    'Quantity[$unit$]' +
    'Quantity'[$unit$]
    assumes the magnitude of the specified $unit$ to be 1.
    @@ -227,10 +227,10 @@ class QuantityMagnitude(Builtin): https://reference.wolfram.com/language/ref/QuantityMagnitude.html
    -
    'QuantityMagnitude[$quantity$]' +
    'QuantityMagnitude'[$quantity$]
    gives the amount of the specified $quantity$. -
    'QuantityMagnitude[$quantity$, $unit$]' +
    'QuantityMagnitude'[$quantity$, $unit$]
    gives the value corresponding to $quantity$ when converted to $unit$.
    @@ -303,7 +303,7 @@ class QuantityQ(Test): :WMA link: https://reference.wolfram.com/language/ref/QuantityQ.html
    -
    'QuantityQ[$expr$]' +
    'QuantityQ'[$expr$]
    return True if $expr$ is a valid Association object, and False otherwise.
    @@ -338,7 +338,7 @@ class QuantityUnit(Builtin): https://reference.wolfram.com/language/ref/QuantityUnit.html
    -
    'QuantityUnit[$quantity$]' +
    'QuantityUnit'[$quantity$]
    returns the unit associated with the specified $quantity$.
    diff --git a/mathics/builtin/quantum_mechanics/angular.py b/mathics/builtin/quantum_mechanics/angular.py index cad013268..4d92ab6a1 100644 --- a/mathics/builtin/quantum_mechanics/angular.py +++ b/mathics/builtin/quantum_mechanics/angular.py @@ -39,9 +39,9 @@ class ClebschGordan(SympyFunction): https://reference.wolfram.com/language/ref/ClebschGordan)
    -
    'ClebschGordan[{$j1$, $m1$}, {$j2$, $m2$}, {$j$ $m$}]' -
    returns the Clebsch-Gordan coefficient for the decomposition of |$j$,$m$> \ - in terms of |$j1$, $m$>, |$j2$, $m2$>. +
    'ClebschGordan'[{$j_1$, $m_1$}, {$j_2$, $m_2$}, {$j$ $m$}] +
    returns the Clebsch-Gordan coefficient for the decomposition of $|j, m\\rangle$ \ + in terms of $|j_1, m\\rangle$, $|j_2, m2\\rangle$.
    >> ClebschGordan[{3 / 2, 3 / 2}, {1 / 2, -1 / 2}, {1, 1}] @@ -96,8 +96,8 @@ class PauliMatrix(SympyFunction): https://reference.wolfram.com/language/ref/PauliMatrix.html)
    -
    'PauliMatrix[$k$]' -
    returns the $k$th Pauli spin matrix). +
    'PauliMatrix'[$k$] +
    returns the $k$-th Pauli spin matrix).
    >> Table[PauliMatrix[i], {i, 1, 3}] @@ -143,7 +143,7 @@ class SixJSymbol(SympyFunction): https://reference.wolfram.com/language/ref/SixJSymbol.html)
    -
    'SixJSymbol[{$j1, $j2$, $j3$}, {$j4$, $j5$, $j6$}]' +
    'SixJSymbol'[{$j_1$, $j_2$, $j_3$}, {$j_4$, $j_5$, $j_6$}]
    returns the values of the Wigner 6-$j$ symbol.
    @@ -227,7 +227,7 @@ class ThreeJSymbol(SympyFunction): https://reference.wolfram.com/language/ref/ThreeJSymbol.html)
    -
    'ThreeJSymbol[{$j1, $m1}, {$j2$, $m2$}, {$j3$, $m3$}]' +
    'ThreeJSymbol'[{$j_1$, $m_1$}, {$j_2$, $m_2$}, {$j_3$, $m_3$}]
    returns the values of the Wigner 3-$j$ symbol.
    diff --git a/mathics/builtin/recurrence.py b/mathics/builtin/recurrence.py index 019029aab..ddf1a19ef 100644 --- a/mathics/builtin/recurrence.py +++ b/mathics/builtin/recurrence.py @@ -30,7 +30,7 @@ class RSolve(Builtin): https://reference.wolfram.com/language/ref/RSolve.html
    -
    'RSolve[$eqn$, $a$[$n$], $n$]' +
    'RSolve[$eqn$, $a$'[$n$], $n$]
    solves a recurrence equation for the function '$a$[$n$]'.
    diff --git a/mathics/builtin/scoping.py b/mathics/builtin/scoping.py index 56bf89039..94f331f4c 100644 --- a/mathics/builtin/scoping.py +++ b/mathics/builtin/scoping.py @@ -112,7 +112,7 @@ class Begin(Builtin): class BeginPackage(Builtin): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/BeginPackage.html @@ -123,7 +123,7 @@ class BeginPackage(Builtin):
    The $context$ argument must be a valid context name. 'BeginPackage' changes \ - the values of '$Context' and '$ContextPath', setting the current context to $context$. + the values of '\$Context' and '\$ContextPath', setting the current context to $context$. ## >> BeginPackage["test`"] ## = test` @@ -153,11 +153,11 @@ class Block(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Block.html
    -
    'Block[{$x$, $y$, ...}, $expr$]' +
    'Block'[{$x$, $y$, ...}, $expr$]
    temporarily removes the definitions of the given variables, evaluates \ $expr$, and restores the original definitions afterwards. -
    'Block[{$x$=$x0$, $y$=$y0$, ...}, $expr$]' +
    'Block'[{$x$=$x_0$, $y$=$y_0$, ...}, $expr$]
    assigns temporary values to the variables during the evaluation of $expr$.
    @@ -209,10 +209,10 @@ def eval(self, vars, expr, evaluation: Evaluation): class Context_(Predefined): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/$Context.html
    -
    '$Context' +
    '\$Context'
    is the current context.
    @@ -269,12 +269,12 @@ def eval_with_string(self, string, evaluation: Evaluation) -> ListExpression: class ContextPath_(Predefined): - """ + r""" :WMA link - :https://reference.wolfram.com/language/ref/$ContextPath.html + :https://reference.wolfram.com/language/ref/\$ContextPath.html
    -
    '$ContextPath' +
    '\$ContextPath'
    is the search path for contexts.
    @@ -299,14 +299,14 @@ class ContextPath_(Predefined): class ContextPathStack(Builtin): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/ContextPathStack.html
    -
    'System`Private`$ContextPathStack' -
    is an internal variable tracking the values of '$ContextPath' \ +
    'System`Private`\$ContextPathStack' +
    is an internal variable tracking the values of '\$ContextPath' \ saved by 'Begin' and 'BeginPackage'.
    """ @@ -321,13 +321,13 @@ class ContextPathStack(Builtin): class ContextStack(Builtin): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/ContextStack.html
    -
    'System`Private`$ContextStack' -
    is an internal variable tracking the values of '$Context' +
    'System`Private`\$ContextStack' +
    is an internal variable tracking the values of '\$Context' saved by 'Begin' and 'BeginPackage'.
    """ @@ -372,7 +372,7 @@ class End(Builtin): class EndPackage(Builtin): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/EndPackage.html @@ -382,8 +382,8 @@ class EndPackage(Builtin):
    marks the end of a package, undoing a previous 'BeginPackage'.
    - After 'EndPackage', the values of '$Context' and '$ContextPath' at the \ - time of the 'BeginPackage' call are restored, with the new package\'s context prepended to $ContextPath. + After 'EndPackage', the values of '\$Context' and '\$ContextPath' at the \ + time of the 'BeginPackage' call are restored, with the new package\'s context prepended to '\$ContextPath'. """ messages = { @@ -408,16 +408,16 @@ class EndPackage(Builtin): class Module(Builtin): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/Module.html
    -
    'Module[{$vars$}, $expr$]' +
    'Module'[{$vars$}, $expr$]
    localizes variables by giving them a temporary name of the form \ - 'name$number', where number is the current value of '$ModuleNumber'. \ - Each time a module is evaluated, '$ModuleNumber' is incremented. + 'name\$number', where number is the current value of '\$ModuleNumber'. \ + Each time a module is evaluated, '\$ModuleNumber' is incremented.
    ## FIXME: fix and go over @@ -483,30 +483,30 @@ def eval(self, vars, expr, evaluation: Evaluation): class ModuleNumber_(Predefined): - """ + r""" :WMA link: - https://reference.wolfram.com/language/ref/$ModuleNumber.html + https://reference.wolfram.com/language/ref/\$ModuleNumber.html
    -
    '$ModuleNumber' +
    '\$ModuleNumber'
    is the current "serial number" to be used for local module variables.
      -
    • '$ModuleNumber' is incremented every time 'Module' or 'Unique' is called. -
    • a Mathics session starts with '$ModuleNumber' set to 1. -
    • You can reset $ModuleNumber to a positive machine integer, but if \ +
    • '\$ModuleNumber' is incremented every time 'Module' or 'Unique' is called. +
    • a Mathics session starts with '\$ModuleNumber' set to 1. +
    • You can reset '\$ModuleNumber' to a positive machine integer, but if \ you do so, naming conflicts may lead to inefficiencies.
    • ## Fixme: go over and adjuset - ## Each use of 'Module' increments '$ModuleNumber': + ## Each use of 'Module' increments '\$ModuleNumber': ## >> {$ModuleNumber, Module[{y}, y], $ModuleNumber} ## = {..., ...} ## FIXME and go over - ## You can reset $ModuleNumber: + ## You can reset '\$ModuleNumber': ## >> $ModuleNumber = 17; {Module[{x}, x], $ModuleNumber} ## = {x$17, 18} ## @@ -529,17 +529,17 @@ class ModuleNumber_(Predefined): class Unique(Predefined): - """ + r""" :WMA link: https://reference.wolfram.com/language/ref/Unique.html
      'Unique[]' -
      generates a new symbol and gives a name of the form '$number'. +
      generates a new symbol and gives a name of the form '\$number'.
      'Unique[x]' -
      generates a new symbol and gives a name of the form 'x$number'. +
      generates a new symbol and gives a name of the form 'x\$number'.
      'Unique[{x, y, ...}]'
      generates a list of new symbols. @@ -557,7 +557,7 @@ class Unique(Predefined): = x... ## FIXME: include the rest of these in test/builtin/test-unique.py - ## Each use of Unique[symbol] increments $ModuleNumber: + ## Each use of Unique[symbol] increments '\$ModuleNumber': ## >> {$ModuleNumber, Unique[x], $ModuleNumber} ## = ... @@ -678,9 +678,9 @@ class With(Builtin): https://reference.wolfram.com/language/ref/With.html
      -
      'With[{$x$=$x0$, $y$=$y0$, ...}, $expr$]' +
      'With'[{$x$=$x_0$, $y$=$y_0$, ...}, $expr$]
      specifies that all occurrences of the symbols $x$, $y$, ... in \ - $expr$ should be replaced by $x0$, $y0$, ... + $expr$ should be replaced by $x_0$, $y_0$, ...
      ## >> n = 10 diff --git a/mathics/builtin/sparse.py b/mathics/builtin/sparse.py index d18cd925d..c3d976469 100644 --- a/mathics/builtin/sparse.py +++ b/mathics/builtin/sparse.py @@ -27,13 +27,13 @@ class SparseArray(Builtin): https://reference.wolfram.com/language/ref/SparseArray.html
      -
      'SparseArray[$rules$]' +
      'SparseArray'[$rules$]
      Builds a sparse array according to the list of $rules$. -
      'SparseArray[$rules$, $dims$]' +
      'SparseArray'[$rules$, $dims$]
      Builds a sparse array of dimensions $dims$ according to the $rules$. -
      'SparseArray[$list$]' +
      'SparseArray'[$list$]
      Builds a sparse representation of $list$.
      diff --git a/mathics/builtin/specialfns/__init__.py b/mathics/builtin/specialfns/__init__.py index 97d6d19dc..ef53a34e0 100644 --- a/mathics/builtin/specialfns/__init__.py +++ b/mathics/builtin/specialfns/__init__.py @@ -5,7 +5,11 @@ There are a number of functions found in mathematical physics and found in standard handbooks. -One thing to note is that the technical literature often contains several conflicting definitions. So beware and check for conformance with the Mathics documentation. +One good source is +:The NIST Digital Library of Mathematical Functions: +https://dlmf.nist.gov/. + +The technical literature often contains several conflicting definitions. So beware, and check for conformance with the Mathics3 documentation. A number of special functions can be evaluated for arbitrary complex values of their arguments. However defining relations may apply only for some special choices of arguments. Here, the full function corresponds to an extension or "analytic continuation" of the defining relation. diff --git a/mathics/builtin/specialfns/bessel.py b/mathics/builtin/specialfns/bessel.py index 295a790aa..593996d5e 100644 --- a/mathics/builtin/specialfns/bessel.py +++ b/mathics/builtin/specialfns/bessel.py @@ -1,5 +1,9 @@ """ Bessel and Related Functions + +See also +:Chapter 10 Bessel Functions in the Digital Library of Mathematical Functions: +https://dlmf.nist.gov/10. """ import mpmath @@ -36,8 +40,8 @@ class AiryAi(MPMathFunction): :SymPy: https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.bessel.airyai, :WMA: https://reference.wolfram.com/language/ref/AiryAi.html)
      -
      'AiryAi[$x$]' -
      returns the Airy function Ai($x$). +
      'AiryAi'[$x$] +
      returns the Airy function $Ai(x)$.
      Exact values: @@ -71,8 +75,8 @@ class AiryAiPrime(MPMathFunction): :WMA link: https://reference.wolfram.com/language/ref/AiryAiPrime.html)
      -
      'AiryAiPrime[$x$]' -
      returns the derivative of the Airy function 'AiryAi[$x$]'. +
      'AiryAiPrime'[$x$] +
      returns the derivative of the Airy function 'AiryAi'[$x$].
      Exact values: @@ -82,6 +86,9 @@ class AiryAiPrime(MPMathFunction): Numeric evaluation: >> AiryAiPrime[0.5] = -0.224911 + + >> Plot[AiryAiPrime[x], {x, -10, 10}] + = -Graphics- """ mpmath_name = "" @@ -102,15 +109,15 @@ class AiryAiZero(Builtin): :WMA link:https://reference.wolfram.com/language/ref/AiryAiZero.html
      -
      'AiryAiZero[$k$]' -
      returns the $k$th zero of the Airy function Ai($z$). +
      'AiryAiZero'[$k$] +
      returns the $k$th zero of the Airy function $Ai(z)$.
      >> N[AiryAiZero[1]] = -2.33811 """ - # TODO: 'AiryAiZero[$k$, $x0$]' - $k$th zero less than x0 + # TODO: 'AiryAiZero[$k$, $x_0$]' - $k$th zero less than x0 attributes = ( A_LISTABLE @@ -151,8 +158,8 @@ class AiryBi(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/AiryBi.html
      -
      'AiryBi[$x$]' -
      returns the Airy function of the second kind Bi($x$). +
      'AiryBi'[$x$] +
      returns the Airy function of the second kind $Bi(x)$.
      Exact values: @@ -184,9 +191,9 @@ class AiryBiPrime(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/AiryBiPrime.html
      -
      'AiryBiPrime[$x$]' +
      'AiryBiPrime'[$x$]
      returns the derivative of the Airy function of the second - kind 'AiryBi[$x$]'. + kind 'AiryBi'[$x$].
      Exact values: @@ -196,16 +203,19 @@ class AiryBiPrime(MPMathFunction): Numeric evaluation: >> AiryBiPrime[0.5] = 0.544573 + + >> Plot[AiryBiPrime[x], {x, -10, 2}] + = -Graphics- """ mpmath_name = "" - sympy_name = "airybiprime" rules = { "Derivative[1][AiryBiPrime]": "(#1 AiryBi[#1])&", } summary_text = "derivative of the Airy's function Bi" + sympy_name = "airybiprime" def get_mpmath_function(self, args): return lambda x: mpmath.airybi(x, derivative=1) @@ -216,15 +226,15 @@ class AiryBiZero(Builtin): :WMA link:https://reference.wolfram.com/language/ref/AiryBiZero.html
      -
      'AiryBiZero[$k$]' -
      returns the $k$th zero of the Airy function Bi($z$). +
      'AiryBiZero'[$k$] +
      returns the $k$th zero of the Airy function $Bi(z)$.
      >> N[AiryBiZero[1]] = -1.17371 """ - # TODO: 'AiryBiZero[$k$, $x0$]' - $k$th zero less than x0 + # TODO: 'AiryBiZero[$k$, $x_0$]' - $k$th zero less than x0 attributes = ( A_LISTABLE @@ -270,8 +280,8 @@ class AngerJ(_Bessel): :WMA: https://reference.wolfram.com/language/ref/AngerJ.html)
      -
      'AngerJ[$n$, $z$]' -
      returns the Anger function J_$n$($z$). +
      'AngerJ'[$n$, $z$] +
      returns the Anger function $J_n(z)$.
      >> AngerJ[1.5, 3.5] @@ -292,9 +302,7 @@ class AngerJ(_Bessel): class BesselI(_Bessel): - """ - - + r""" :Modified Bessel function of the first kind: https://en.wikipedia.org/ @@ -306,8 +314,8 @@ class BesselI(_Bessel): https://reference.wolfram.com/language/ref/BesselI.html)
      -
      'BesselI[$n$, $z$]' -
      returns the modified Bessel function of the first kind I_$n$($z$). +
      'BesselI'[$n$, $z$] +
      returns the modified Bessel function of the first kind $I_n(z)$.
      >> BesselI[0, 0] @@ -348,8 +356,8 @@ class BesselJ(_Bessel): https://reference.wolfram.com/language/ref/BesselJ.html)
      -
      'BesselJ[$n$, $z$]' -
      returns the Bessel function of the first kind J_$n$($z$). +
      'BesselJ'[$n$, $z$] +
      returns the Bessel function of the first kind $J_n(z)$.
      >> BesselJ[0, 5.2] @@ -396,8 +404,8 @@ class BesselK(_Bessel): https://reference.wolfram.com/language/ref/BesselJ.html)
      -
      'BesselK[$n$, $z$]' -
      returns the modified Bessel function of the second kind K_$n$($z$). +
      'BesselK'[$n$, $z$] +
      returns the modified Bessel function of the second kind $K_n(z)$.
      >> BesselK[1.5, 4] @@ -435,8 +443,8 @@ class BesselY(_Bessel): https://reference.wolfram.com/language/ref/BesselY.html)
      -
      'BesselY[$n$, $z$]' -
      returns the Bessel function of the second kind Y_$n$($z$). +
      'BesselY'[$n$, $z$] +
      returns the Bessel function of the second kind $Y_n(z)$.
      >> BesselY[1.5, 4] @@ -474,8 +482,8 @@ class BesselJZero(_Bessel): :WMA link:https://reference.wolfram.com/language/ref/BesselJZero.html
      -
      'BesselJZero[$n$, $k$]' -
      returns the $k$th zero of the Bessel function of the first kind J_$n$($z$). +
      'BesselJZero'[$n$, $k$] +
      returns the $k$th zero of the Bessel function of the first kind $J_n(z)$.
      >> N[BesselJZero[0, 1]] @@ -495,8 +503,8 @@ class BesselYZero(_Bessel): :WMA link:https://reference.wolfram.com/language/ref/BesselYZero.html
      -
      'BesselYZero[$n$, $k$]' -
      returns the $k$th zero of the Bessel function of the second kind Y_$n$($z$). +
      'BesselYZero'[$n$, $k$] +
      returns the $k$th zero of the Bessel function of the second kind $Y_n(z)$.
      >> N[BesselYZero[0, 1]] @@ -519,8 +527,8 @@ class HankelH1(_Bessel): :WMA link:https://reference.wolfram.com/language/ref/HankelH1.html
      -
      'HankelH1[$n$, $z$]' -
      returns the Hankel function of the first kind H_$n$^1 ($z$). +
      'HankelH1'[$n$, $z$] +
      returns the Hankel function of the first kind $H_n^1(z)$.
      >> HankelH1[1.5, 4] @@ -541,8 +549,8 @@ class HankelH2(_Bessel): :WMA link:https://reference.wolfram.com/language/ref/HankelH2.html
      -
      'HankelH2[$n$, $z$]' -
      returns the Hankel function of the second kind H_$n$^2 ($z$). +
      'HankelH2'[$n$, $z$] +
      returns the Hankel function of the second kind $H_n^2(z)$.
      >> HankelH2[1.5, 4] @@ -558,39 +566,6 @@ class HankelH2(_Bessel): sympy_name = "hankel2" -class HypergeometricU(MPMathFunction): - """ - - :Confluent hypergeometric function: https://en.wikipedia.org/wiki/Confluent_hypergeometric_function ( - :mpmath: https://mpmath.org/doc/current/functions/bessel.html#mpmath.hyperu, - :WMA: https://reference.wolfram.com/language/ref/HypergeometricU.html) -
      -
      'HypergeometricU[$a$, $b$, $z$]' -
      returns $U$($a$, $b$, $z$). -
      - - >> HypergeometricU[3, 2, 1.] - = 0.105479 - - Plot 'U'[3, 2, x] from 0 to 2 in steps of 0.5: - >> Plot[HypergeometricU[3, 2, x], {x, 0.5, 2}] - = -Graphics- - - We handle this special case: - >> HypergeometricU[0, c, z] - = 1 - """ - - attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED - mpmath_name = "hyperu" - nargs = {3} - rules = { - "HypergeometricU[0, c_, z_]": "1", - } - summary_text = "Tricomi confluent hypergeometric function" - sympy_name = "" - - # Kelvin Functions @@ -606,11 +581,11 @@ class KelvinBei(_Bessel): https://reference.wolfram.com/language/ref/KelvinBei.html)
      -
      'KelvinBei[$z$]' -
      returns the Kelvin function bei($z$). +
      'KelvinBei'[$z$] +
      returns the Kelvin function $bei(z)$. -
      'KelvinBei[$n$, $z$]' -
      returns the Kelvin function bei_$n$($z$). +
      'KelvinBei'[$n$, $z$] +
      returns the Kelvin function $bei_n(z)$.
      >> KelvinBei[0.5] @@ -646,11 +621,11 @@ class KelvinBer(_Bessel): :WMA: https://reference.wolfram.com/language/ref/KelvinBer.html)
      -
      'KelvinBer[$z$]' -
      returns the Kelvin function ber($z$). +
      'KelvinBer'[$z$] +
      returns the Kelvin function $ber(z)$. -
      'KelvinBer[$n$, $z$]' -
      returns the Kelvin function ber_$n$($z$). +
      'KelvinBer'[$n$, $z$] +
      returns the Kelvin function $ber_n(z)$.
      >> KelvinBer[0.5] @@ -688,11 +663,11 @@ class KelvinKei(_Bessel): https://reference.wolfram.com/language/ref/KelvinKei.html)
      -
      'KelvinKei[$z$]' -
      returns the Kelvin function kei($z$). +
      'KelvinKei'[$z$] +
      returns the Kelvin function $kei(z)$. -
      'KelvinKei[$n$, $z$]' -
      returns the Kelvin function kei_$n$($z$). +
      'KelvinKei'[$n$, $z$] +
      returns the Kelvin function $kei_n(z)$.
      >> KelvinKei[0.5] @@ -723,10 +698,10 @@ class KelvinKer(_Bessel): :Kelvin function ker: https://en.wikipedia.org/wiki/Kelvin_functions#ker(x) (:mpmath: https://mpmath.org/doc/current/functions/bessel.html#ker, :WMA: https://reference.wolfram.com/language/ref/KelvinKer.html)
      -
      'KelvinKer[$z$]' -
      returns the Kelvin function ker($z$). -
      'KelvinKer[$n$, $z$]' -
      returns the Kelvin function ker_$n$($z$). +
      'KelvinKer'[$z$] +
      returns the Kelvin function $ker(z)$. +
      'KelvinKer'[$n$, $z$] +
      returns the Kelvin function $ker_n(z)$.
      >> KelvinKer[0.5] @@ -761,8 +736,8 @@ class SphericalBesselJ(_Bessel): https://reference.wolfram.com/language/ref/SphericalBesselJ.html)
      -
      'SphericalBesselJ[$n$, $z$]' -
      returns the spherical Bessel function of the first kind Y_$n$($z$). +
      'SphericalBesselJ'[$n$, $z$] +
      returns the spherical Bessel function of the first kind $Y_n(z)$.
      >> SphericalBesselJ[1, 5.2] @@ -790,8 +765,8 @@ class SphericalBesselY(_Bessel): https://reference.wolfram.com/language/ref/SphericalBesselY.html)
      -
      'SphericalBesselY[$n$, $z$]' -
      returns the spherical Bessel function of the second kind Y_$n$($z$). +
      'SphericalBesselY'[$n$, $z$] +
      returns the spherical Bessel function of the second kind $Y_n(z)$.
      >> SphericalBesselY[1, 5.5] @@ -813,8 +788,8 @@ class SphericalHankelH1(_Bessel): (:WMA link:https://reference.wolfram.com/language/ref/SphericalHankelH1.html)
      -
      'SphericalHankelH1[$n$, $z$]' -
      returns the spherical Hankel function of the first kind h_$n$^(1)($z$). +
      'SphericalHankelH1'[$n$, $z$] +
      returns the spherical Hankel function of the first kind $h_n^{(1)}(z)$.
      >> SphericalHankelH1[3, 1.5] @@ -834,8 +809,8 @@ class SphericalHankelH2(_Bessel): (:WMA link:https://reference.wolfram.com/language/ref/SphericalHankelH2.html)
      -
      'SphericalHankelH1[$n$, $z$]' -
      returns the spherical Hankel function of the second kind h_$n$^(2)($z$). +
      'SphericalHankelH1'[$n$, $z$] +
      returns the spherical Hankel function of the second kind $h_n^{(2)}(z)$.
      >> SphericalHankelH2[3, 1.5] @@ -856,8 +831,8 @@ class StruveH(_Bessel): (:WMA:https://reference.wolfram.com/language/ref/StruveH.html)
      -
      'StruveH[$n$, $z$]' -
      returns the Struve function H_$n$($z$). +
      'StruveH'[$n$, $z$] +
      returns the Struve function $H_n(z)$.
      >> StruveH[1.5, 3.5] @@ -880,8 +855,8 @@ class StruveL(_Bessel): """ :Modified Struve functions L: https://en.wikipedia.org/wiki/Struve_function
      -
      'StruveL[$n$, $z$]' -
      returns the modified Struve function L_$n$($z$). +
      'StruveL'[$n$, $z$] +
      returns the modified Struve function $L_n(z)$.
      >> StruveL[1.5, 3.5] @@ -905,8 +880,8 @@ class WeberE(_Bessel): :WMA link:https://reference.wolfram.com/language/ref/WeberE.html
      -
      'WeberE[$n$, $z$]' -
      returns the Weber function E_$n$($z$). +
      'WeberE'[$n$, $z$] +
      returns the Weber function $E_n(z)$.
      >> WeberE[1.5, 3.5] diff --git a/mathics/builtin/specialfns/elliptic.py b/mathics/builtin/specialfns/elliptic.py index a0db45c02..0cd94c1f1 100644 --- a/mathics/builtin/specialfns/elliptic.py +++ b/mathics/builtin/specialfns/elliptic.py @@ -8,6 +8,10 @@ finding the arc length of an ellipse. These functions often are used in cryptography to encode and decode messages. + +See also +:Chapter 19 Elliptic Integrals in the Digital Library of Mathematical Functions: +https://dlmf.nist.gov/19. """ import sympy @@ -20,7 +24,7 @@ class EllipticE(SympyFunction): - """ + r""" :Elliptic complete elliptic integral of the second kind: https://en.wikipedia.org/wiki/Elliptic_integral#Complete_elliptic_integral_of_the_second_kind (:SymPy: @@ -29,11 +33,11 @@ class EllipticE(SympyFunction): https://reference.wolfram.com/language/ref/EllipticE.html)
      -
      'EllipticE[$m$]' -
      computes the complete elliptic integral $E$($m$). +
      'EllipticE'[$m$] +
      computes the complete elliptic integral $E(m)$. -
      'EllipticE[phi|$m$]' -
      computes the complete elliptic integral of the second kind $E$($m$|$phi$). +
      'EllipticE'[$\phi$|$m$] +
      computes the complete elliptic integral of the second kind $E(m|\phi)$.
      Elliptic curves give Pi / 2 when evaluated at zero: @@ -77,7 +81,7 @@ def eval_phi_m(self, phi, m, evaluation): class EllipticF(SympyFunction): - """ + r""" :Complete elliptic integral of the first kind: https://en.wikipedia.org/wiki/\ @@ -89,8 +93,8 @@ class EllipticF(SympyFunction): https://reference.wolfram.com/language/ref/EllipticF.html)
      -
      'EllipticF[$phi$, $m$]' -
      computes the elliptic integral of the first kind $F$($ϕ$|$m$). +
      'EllipticF'[$\phi$, $m$] +
      computes the elliptic integral of the first kind $F(\phi|m)$.
      >> EllipticF[0.3, 0.8] @@ -132,8 +136,8 @@ class EllipticK(SympyFunction): https://reference.wolfram.com/language/ref/EllipticK.html)
      -
      'EllipticK[$m$]' -
      computes the elliptic integral of the first kind $K$($m$). +
      'EllipticK'[$m$] +
      computes the elliptic integral of the first kind $K(m)$.
      >> EllipticK[0.5] @@ -179,8 +183,8 @@ class EllipticPi(SympyFunction): https://reference.wolfram.com/language/ref/EllipticPi.html)
      -
      'EllipticPi[$n$, $m$]' -
      computes the elliptic integral of the third kind $Pi$($m$). +
      'EllipticPi'[$n$, $m$] +
      computes the elliptic integral of the third kind $Pi(m)$.
      >> EllipticPi[0.4, 0.6] diff --git a/mathics/builtin/specialfns/erf.py b/mathics/builtin/specialfns/erf.py index 08f33f860..e1666c1a7 100644 --- a/mathics/builtin/specialfns/erf.py +++ b/mathics/builtin/specialfns/erf.py @@ -2,6 +2,10 @@ """ Error Function and Related Functions + +See also +:Chapter 7 Error Functions, Dawson's and Fresnel Integrals: +https://dlmf.nist.gov/7. """ @@ -20,11 +24,11 @@ class Erf(MPMathMultiFunction): :WMA: https://reference.wolfram.com/language/ref/Erf.html)
      -
      'Erf[$z$]' +
      'Erf'[$z$]
      returns the error function of $z$. -
      'Erf[$z0$, $z1$]' -
      returns the result of 'Erf[$z1$] - Erf[$z0$]'. +
      'Erf'[$z_0$, $z_1$] +
      returns the result of 'Erf[$z_1$] - Erf[$z_0$]'.
      'Erf[$x$]' is an odd function: @@ -67,7 +71,7 @@ class Erfc(MPMathFunction): https://reference.wolfram.com/language/ref/Erfc.html)
      -
      'Erfc[$z$]' +
      'Erfc'[$z$]
      returns the complementary error function of $z$.
      @@ -99,7 +103,7 @@ class FresnelC(MPMathFunction): :WMA: https://reference.wolfram.com/language/ref/FresnelC.html)
      -
      'FresnelC[$z$]' +
      'FresnelC'[$z$]
      is the Fresnel C integral $C$($z$).
      @@ -130,7 +134,7 @@ class FresnelS(MPMathFunction): https://reference.wolfram.com/language/ref/FresnelS.html)
      -
      'FresnelS[$z$]' +
      'FresnelS'[$z$]
      is the Fresnel S integral $S$($z$).
      @@ -160,7 +164,7 @@ class InverseErf(MPMathFunction): https://reference.wolfram.com/language/ref/InverseErf.html)
      -
      'InverseErf[$z$]' +
      'InverseErf'[$z$]
      returns the inverse error function of $z$.
      @@ -209,7 +213,7 @@ class InverseErfc(MPMathFunction): :WMA: https://reference.wolfram.com/language/ref/InverseErfc.html)
      -
      'InverseErfc[$z$]' +
      'InverseErfc'[$z$]
      returns the inverse complementary error function of $z$.
      diff --git a/mathics/builtin/specialfns/expintegral.py b/mathics/builtin/specialfns/expintegral.py index 45c41c554..33e2fb3d7 100644 --- a/mathics/builtin/specialfns/expintegral.py +++ b/mathics/builtin/specialfns/expintegral.py @@ -2,6 +2,10 @@ """ Exponential Integral and Special Functions + +See also +:Chapters 4.2-4.13 Logarithm, Exponential, Powers in the Digital Library of Mathematical Functions: +https://dlmf.nist.gov/4#PT2. """ @@ -19,8 +23,8 @@ class ExpIntegralE(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/ExpIntegralE.html
      -
      'ExpIntegralE[$n$, $z$]' -
      returns the exponential integral function $E$_$n$($z$). +
      'ExpIntegralE'[$n$, $z$] +
      returns the exponential integral function $E_n(z)$.
      >> ExpIntegralE[2.0, 2.0] @@ -39,8 +43,8 @@ class ExpIntegralEi(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/ExpIntegralEi.html
      -
      'ExpIntegralEi[$z$]' -
      returns the exponential integral function Ei($z$). +
      'ExpIntegralEi'[$z$] +
      returns the exponential integral function $Ei(z)$.
      >> ExpIntegralEi[2.0] @@ -60,10 +64,10 @@ class LambertW(Builtin): https://mathworld.wolfram.com/LambertW-Function.html
      -
      'LambertW[$k$]' +
      'LambertW'[$k$]
      alias for ProductLog[$z$]. -
      'LambertW[$k$, $z$]' +
      'LambertW'[$k$, $z$]
      alias for ProductLog[$k$, $z$].
      @@ -93,11 +97,11 @@ class ProductLog(MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/ProductLog.html
      -
      'ProductLog[$z$]' -
      returns the principle solution for $w$ in $z$ == $wE$^$w$. +
      'ProductLog'[$z$] +
      returns the principle solution for $w$ in $z == wE^w$. -
      'ProductLog[$k$, $z$]' -
      gives the $k$th solution. +
      'ProductLog'[$k$, $z$] +
      gives the $k$-th solution.
      The defining equation: @@ -136,7 +140,7 @@ class ProductLog(MPMathFunction): # class ZernikeR(MPMathFunction): # """ #
      -#
      'ZernikeR[$n$, $m$, $r$]' +#
      'ZernikeR'[$n$, $m$, $r$] #
      returns the radial Zernike polynomial R_$n$^$m$($r$). #
      # diff --git a/mathics/builtin/specialfns/gamma.py b/mathics/builtin/specialfns/gamma.py index a9b1d9883..7affd99ce 100644 --- a/mathics/builtin/specialfns/gamma.py +++ b/mathics/builtin/specialfns/gamma.py @@ -1,5 +1,9 @@ """ Gamma and Related Functions + +See also +:Chapter 5 Gamma Function in the Digital Library of Mathematical Functions: +https://dlmf.nist.gov/5. """ import sys @@ -8,7 +12,15 @@ import mpmath import sympy -from mathics.core.atoms import Integer, Integer0, Number +import mathics.eval.tracing as tracing +from mathics.core.atoms import ( + Integer, + Integer0, + MachineReal, + MachineReal0, + Number, + PrecisionReal, +) from mathics.core.attributes import ( A_LISTABLE, A_NUMERIC_FUNCTION, @@ -24,6 +36,7 @@ from mathics.core.convert.mpmath import from_mpmath from mathics.core.convert.python import from_python from mathics.core.convert.sympy import from_sympy +from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.number import FP_MANTISA_BINARY_DIGITS, dps, min_prec from mathics.core.symbols import Symbol, SymbolSequence @@ -35,28 +48,28 @@ class Beta(MPMathMultiFunction): - """ - - :Euler beta function: - https://en.wikipedia.org/wiki/Beta_function (:SymPy: - https://docs.sympy.org/latest/modules/functions/ + r""" + + :Euler beta function: + https://en.wikipedia.org/wiki/Beta_function (:SymPy: + https://docs.sympy.org/latest/modules/functions/ special.html#sympy.functions.special.beta_functions.beta, - :WMA: - https://reference.wolfram.com/language/ref/Beta.html) - -
      -
      'Beta[$a$, $b$]' -
      is the Euler's Beta function. -
      'Beta[$z$, $a$, $b$]' -
      gives the incomplete Beta function. -
      - - The Beta function satisfies the property - Beta[x, y] = Integrate[t^(x-1)(1-t)^(y-1),{t,0,1}] = Gamma[a] Gamma[b] / Gamma[a + b] - >> Beta[2, 3] - = 1 / 12 - >> 12* Beta[1., 2, 3] - = 1. + :WMA: + https://reference.wolfram.com/language/ref/Beta.html
      ) + +
      +
      'Beta'[$a$, $b$] +
      is the Euler's Beta function $\mathrm{B}(a, b)$. +
      'Beta'[$z$, $a$, $b$] +
      gives the incomplete Beta function $\mathrm{B}_z(a, b)$. +
      + + The Beta function satisfies the property: + $\mathrm{B} = \int_0^t t^{(x-1)(1-t)^(y-1)} = \Gamma(a) \Gamma(b) / \Gamma(a + b)$ + >> Beta[2, 3] + = 1 / 12 + >> 12* Beta[1., 2, 3] + = 1. """ attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED @@ -143,7 +156,7 @@ class Factorial(PostfixOperator, MPMathFunction): https://reference.wolfram.com/language/ref/Factorial.html)
      -
      'Factorial[$n$]' +
      'Factorial'[$n$]
      '$n$!'
      computes the factorial of $n$.
      @@ -178,7 +191,7 @@ class Factorial2(PostfixOperator, MPMathFunction): :WMA link:https://reference.wolfram.com/language/ref/Factorial2.html
      -
      'Factorial2[$n$]' +
      'Factorial2'[$n$]
      '$n$!!'
      computes the double factorial of $n$.
      @@ -259,7 +272,7 @@ def fact2_generic(x): class Gamma(MPMathMultiFunction): - """ + r""" :Gamma function: https://en.wikipedia.org/wiki/Gamma_function ( :SymPy:https://docs.sympy.org/latest/modules/functions @@ -273,36 +286,40 @@ class Gamma(MPMathMultiFunction): the non-positive integers.
      -
      'Gamma[$z$]' -
      is the gamma function on the complex number $z$. +
      'Gamma'[$z$] +
      is the Euler gamma function, $\Gamma(z)$ on the complex number $z$. -
      'Gamma[$z$, $x$]' -
      is the upper incomplete gamma function. +
      'Gamma'[$a$, $z$] +
      is the upper incomplete gamma function, $\Gamma(a, z)$. -
      'Gamma[$z$, $x0$, $x1$]' -
      is equivalent to 'Gamma[$z$, $x0$] - Gamma[$z$, $x1$]'. +
      'Gamma'[$a$, $z_0$, $z_1$] +
      is the generalized incomplete gamma function $\Gamma[a, z_0] - \Gamma(a, z_1)$.
      - 'Gamma[$z$]' is equivalent to '($z$ - 1)!': + 'Gamma[$z$]' is equivalent to $(z - 1)!$: >> Simplify[Gamma[z] - (z - 1)!] = 0 - Exact arguments: + Examples of using 'Gamma' with exact numeric arguments: >> Gamma[8] = 5040 + >> Gamma[1/2] = Sqrt[Pi] - >> Gamma[1, x] - = E ^ (-x) - >> Gamma[0, x] - = ExpIntegralE[1, x] - Numeric arguments: >> Gamma[123.78] = 4.21078×10^204 + >> Gamma[1. + I] = 0.498016 - 0.15495 I + Examples of 'Gamma' with symbolic arguments: + + >> Gamma[1, x] + = E ^ (-x) + >> Gamma[0, x] + = ExpIntegralE[1, x] + Both 'Gamma' and 'Factorial' functions are continuous: >> Plot[{Gamma[x], x!}, {x, 0, 4}] = -Graphics- @@ -319,7 +336,6 @@ class Gamma(MPMathMultiFunction): rules = { "Gamma[z_, x0_, x1_]": "Gamma[z, x0] - Gamma[z, x1]", - "Gamma[1 + z_]": "z!", "Gamma[Undefined]": "Undefined", "Gamma[x_, Undefined]": "Undefined", "Gamma[Undefined, y_]": "Undefined", @@ -348,7 +364,7 @@ class LogGamma(MPMathMultiFunction): https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.gamma_functions.loggamma
      , :WMA:https://reference.wolfram.com/language/ref/LogGamma.html)
      -
      'LogGamma[$z$]' +
      'LogGamma'[$z$]
      is the logarithm of the gamma function on the complex number $z$.
      @@ -401,7 +417,7 @@ class Pochhammer(SympyFunction): The Pochammer symbol has a definite value even when the gamma \ functions which appear in its definition are infinite.
      -
      'Pochhammer[$a$, $n$]' +
      'Pochhammer'[$a$, $n$]
      is the Pochhammer symbol $a_n$.
      @@ -415,9 +431,9 @@ class Pochhammer(SympyFunction): >> Pochhammer[1, 3] == Pochhammer[2, 2] = True - Although sometimes 'Pochhammer[0, $n$]' is taken to be 1, in Mathics it is 0: - >> Pochhammer[0, n] - = 0 + 'Pochhammer['0, $-n$']' for positive integer $n$, is $-1^n 1 / |n|!$: + >> Table[Pochhammer[0, n], {n, 0, -4, -1}] + = {1, -1, 1 / 2, -1 / 6, 1 / 24} Pochhammer uses Gamma for non-Integer values of $n$: @@ -434,14 +450,36 @@ class Pochhammer(SympyFunction): attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED rules = { - "Pochhammer[0, n_]": "0", # Wikipedia says it should be 1 though. - "Pochhammer[a_, n_]": "Gamma[a + n] / Gamma[a]", + "Pochhammer[0, 0]": "1", + # FIXME: In WMA, if n is an Number with an integer value, it + # is rewritten to expanded terms not using + # Factorial as we do below. For example, Pochhammer[i, 2] is + # i (i + 1) instead of (1 + i)! / (-1 + i)! as the rule below + # gives. Ideally, we should match this behavior. However if + # this is done, we will *also* need to adjust Product, because + # WMA Product is sometimes rewritten as an expression using Factorial. + # In particular, Product[k, {k, 3, n}] == n! / 2 in both Mathics3 + # and WMA. + "Pochhammer[a_, n_]": "Factorial[a + n - 1] / Factorial[a - 1]", "Derivative[1,0][Pochhammer]": "(Pochhammer[#1, #2]*(-PolyGamma[0, #1] + PolyGamma[0, #1 + #2]))&", "Derivative[0,1][Pochhammer]": "(Pochhammer[#1, #2]*PolyGamma[0, #1 + #2])&", } summary_text = "compute Pochhammer's symbols" sympy_name = "RisingFactorial" + def eval_negative_int(self, n, evaluation: Evaluation): + "Pochhammer[0, n_?Negative]" + + n_value = n.value + if isinstance(n, (MachineReal, PrecisionReal)): + if n_value == int(n_value): + n_value = int(n_value) + else: + return MachineReal0 + + sympy_result = tracing.run_sympy(sympy.rf, 0, n.value) + return from_sympy(sympy_result) + class PolyGamma(MPMathMultiFunction): r""" @@ -496,10 +534,10 @@ class StieltjesGamma(SympyFunction): https://reference.wolfram.com/language/ref/StieltjesGamma.html)
      -
      'StieltjesGamma[$n$]' +
      'StieltjesGamma'[$n$]
      returns the Stieltjes constant for $n$. -
      'StieltjesGamma[$n$, $a$]' +
      'StieltjesGamma'[$n$, $a$]
      gives the generalized Stieltjes constant of its parameters
      @@ -528,7 +566,7 @@ class Subfactorial(SympyFunction): :WMA: https://reference.wolfram.com/language/ref/Subfactorial.html)
      -
      'Subfactorial[$n$]' +
      'Subfactorial'[$n$]
      computes the subfactorial of $n$.
      @@ -540,7 +578,7 @@ class Subfactorial(SympyFunction): >> Subfactorial[6.0] = 265 - Here is how the exponential, 'Factorial', and 'Subfactoral' grow in comparison: + Here is how the exponential, 'Factorial', and 'Subfactorial' grow in comparison: >> LogPlot[{10^x, Factorial[x], Subfactorial[x]}, {x, 0, 25}, PlotPoints->26] = -Graphics- @@ -551,7 +589,7 @@ class Subfactorial(SympyFunction): rules = { "Subfactorial[elements_List]": "Subfactorial @@ elements", } - summary_text = "compute the subfactorial (derangment) of a number" + summary_text = "compute the subfactorial (derangement) of a number" sympy_name = "subfactorial" def eval(self, element, evaluation): diff --git a/mathics/builtin/specialfns/hypergeom.py b/mathics/builtin/specialfns/hypergeom.py new file mode 100644 index 000000000..c83bd576f --- /dev/null +++ b/mathics/builtin/specialfns/hypergeom.py @@ -0,0 +1,231 @@ +""" +Hypergeometric functions + +See also +:Chapter 15 Hypergeometric Functions in the Digital Library of Mathematical Functions: +https://dlmf.nist.gov/15. +""" + +import mpmath +import sympy + +import mathics.eval.tracing as tracing +from mathics.core.attributes import ( + A_LISTABLE, + A_N_HOLD_FIRST, + A_NUMERIC_FUNCTION, + A_PROTECTED, + A_READ_PROTECTED, +) +from mathics.core.builtin import MPMathFunction +from mathics.core.convert.mpmath import from_mpmath +from mathics.core.convert.sympy import from_sympy +from mathics.core.evaluation import Evaluation +from mathics.core.number import FP_MANTISA_BINARY_DIGITS +from mathics.core.systemsymbols import SymbolComplexInfinity, SymbolMachinePrecision + + +class HypergeometricPFQ(MPMathFunction): + """ + + :Generalized hypergeometric function: https://en.wikipedia.org/wiki/Generalized_hypergeometric_function ( + :mpmath: https://mpmath.org/doc/current/functions/hypergeometric.html#hyper, + :sympy: https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.hyper.hyper, + :WMA: https://reference.wolfram.com/language/ref/HypergeometricPFQ.html) +
      +
      'HypergeometricPFQ'[${a_1, ..., a_p}, {b_1, ..., b_q}, z$] +
      returns ${}_p F_q({a_1, ..., a_p}; {b_1, ..., b_q}; z)$. +
      + >> HypergeometricPFQ[{2}, {2}, 1] + = E + + Result is symbollicaly simplified by default: + >> HypergeometricPFQ[{3}, {2}, 1] + = HypergeometricPFQ[{3}, {2}, 1] + unless a numerical evaluation is explicitly requested: + >> HypergeometricPFQ[{3}, {2}, 1] // N + = 4.07742 + >> HypergeometricPFQ[{3}, {2}, 1.] + = 4.07742 + + The following special cases are handled: + >> HypergeometricPFQ[{}, {}, z] + = 1 + >> HypergeometricPFQ[{0}, {b}, z] + = 1 + >> Hypergeometric1F1[b, b, z] + = E ^ z + """ + + attributes = A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED + mpmath_name = "hyper" + nargs = {3} + rules = { + "HypergeometricPFQ[{}, {}, z_]": "1", + "HypergeometricPFQ[{0}, b_, z_]": "1", + "HypergeometricPFQ[b_, b_, z_]": "Exp[z]", + } + summary_text = "compute the generalized hypergeometric function" + sympy_name = "hyper" + + def eval(self, a, b, z, evaluation: Evaluation): + "HypergeometricPFQ[a_, b_, z_]" + try: + a_sympy = [e.to_sympy() for e in a] + b_sympy = [e.to_sympy() for e in b] + result_sympy = tracing.run_sympy( + sympy.hyper, a_sympy, b_sympy, z.to_sympy() + ) + return from_sympy(result_sympy) + except Exception: + pass + + def eval_N(self, a, b, z, prec, evaluation: Evaluation): + "N[HypergeometricPFQ[a_, b_, z_], prec_]" + try: + result_mpmath = tracing.run_mpmath( + mpmath.hyper, a.to_python(), b.to_python(), z.to_python() + ) + return from_mpmath(result_mpmath) + except ZeroDivisionError: + return SymbolComplexInfinity + except Exception as ex: + pass + + def eval_numeric(self, a, b, z, evaluation: Evaluation): + "HypergeometricPFQ[a:{__?NumericQ}, b:{__?NumericQ}, z_?MachineNumberQ]" + return self.eval_N(a, b, z, SymbolMachinePrecision, evaluation) + + +class Hypergeometric1F1(MPMathFunction): + """ + + :Kummer confluent hypergeometric function: https://en.wikipedia.org/wiki/Confluent_hypergeometric_function ( + :mpmath: https://mpmath.org/doc/current/functions/hypergeometric.html#hyper, + :WMA: https://reference.wolfram.com/language/ref/Hypergeometric1F1.html) +
      +
      'Hypergeometric1F1'[$a$, $b$, $z$] +
      returns ${}_1 F_1(a; b; z)$. +
      + + Result is symbollicaly simplified by default: + >> Hypergeometric1F1[3, 2, 1] + = HypergeometricPFQ[{3}, {2}, 1] + unless a numerical evaluation is explicitly requested: + >> Hypergeometric1F1[3, 2, 1] // N + = 4.07742 + >> Hypergeometric1F1[3, 2, 1.] + = 4.07742 + + Plot 'M'[3, 2, x] from 0 to 2 in steps of 0.5: + >> Plot[Hypergeometric1F1[3, 2, x], {x, 0.5, 2}] + = -Graphics- + Here, plot explicitly requests a numerical evaluation. + """ + + attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED + mpmath_name = "" + nargs = {3} + rules = { + "Hypergeometric1F1[a_, b_, z_]": "HypergeometricPFQ[{a},{b},z]", + } + summary_text = "compute Kummer confluent hypergeometric function" + sympy_name = "" + + +class MeijerG(MPMathFunction): + """ + + :Meijer G-function: https://en.wikipedia.org/wiki/Meijer_G-function ( + :mpmath: https://mpmath.org/doc/current/functions/hypergeometric.html#meijerg, + :sympy: https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.hyper.meijerg, + :WMA: https://reference.wolfram.com/language/ref/MeijerG.html) +
      +
      'MeijerG'[${{a_1, ..., a_n}, {a_{n+1}, ..., a_p}}, {{b_1, ..., b_m}, {b_{m+1}, ..., a_q}}, z$] +
      returns $G^{m,n}_{p,q}(z | {a_1, ..., a_p}; {b_1, ..., b_q})$. +
      + Result is symbollicaly simplified by default: + >> MeijerG[{{1, 2}, {}}, {{3}, {}}, 1] + = MeijerG[{{1, 2}, {}}, {{3}, {}}, 1] + unless a numerical evaluation is explicitly requested: + >> MeijerG[{{1, 2},{}}, {{3},{}}, 1] // N + = 0.210958 + >> MeijerG[{{1, 2},{}}, {{3},{}}, 1.] + = 0.210958 + """ + + attributes = A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED + mpmath_name = "meijerg" + nargs = {3} + rules = {} + summary_text = "compute the Meijer G-function" + sympy_name = "meijerg" + + def eval(self, a, b, z, evaluation: Evaluation): + "MeijerG[a_, b_, z_]" + try: + a_sympy = [[e2.to_sympy() for e2 in e1] for e1 in a] + b_sympy = [[e2.to_sympy() for e2 in e1] for e1 in b] + result_sympy = tracing.run_sympy( + sympy.meijerg, a_sympy, b_sympy, z.to_sympy() + ) + return from_sympy(result_sympy) + except Exception: + pass + + def eval_N(self, a, b, z, prec, evaluation: Evaluation): + "N[MeijerG[a_, b_, z_], prec_]" + try: + result_mpmath = tracing.run_mpmath( + mpmath.meijerg, a.to_python(), b.to_python(), z.to_python() + ) + return from_mpmath(result_mpmath) + except ZeroDivisionError: + return SymbolComplexInfinity + except Exception: + pass + + def eval_numeric(self, a, b, z, evaluation: Evaluation): + "MeijerG[a:{___List?(AllTrue[#, NumericQ, Infinity]&)}, b:{___List?(AllTrue[#, NumericQ, Infinity]&)}, z_?MachineNumberQ]" + return self.eval_N(a, b, z, SymbolMachinePrecision, evaluation) + + +class HypergeometricU(MPMathFunction): + """ + + :Confluent hypergeometric function: https://en.wikipedia.org/wiki/Confluent_hypergeometric_function ( + :mpmath: https://mpmath.org/doc/current/functions/bessel.html#mpmath.hyperu, + :WMA: https://reference.wolfram.com/language/ref/HypergeometricU.html) +
      +
      'HypergeometricU'[$a$, $b$, $z$] +
      returns $U(a, b, z)$. +
      + Result is symbollicaly simplified, where possible: + >> HypergeometricU[3, 2, 1] + = MeijerG[{{-2}, {}}, {{0, -1}, {}}, 1] / 2 + >> HypergeometricU[1,4,8] + = HypergeometricU[1, 4, 8] + unless a numerical evaluation is explicitly requested: + >> HypergeometricU[3, 2, 1] // N + = 0.105479 + >> HypergeometricU[3, 2, 1.] + = 0.105479 + + Plot 'U'[3, 2, x] from 0 to 10 in steps of 0.5: + >> Plot[HypergeometricU[3, 2, x], {x, 0.5, 10}] + = -Graphics- + + We handle this special case: + >> HypergeometricU[0, b, z] + = 1 + """ + + attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED + mpmath_name = "hyperu" + nargs = {3} + rules = { + "HypergeometricU[0, c_, z_]": "1", + "HypergeometricU[a_, b_, z_] /; (a > 0) && (a-b+1 > 0)": "MeijerG[{{1-a},{}},{{0,1-b},{}},z]/Gamma[a]/Gamma[a-b+1]", + } + summary_text = "compute the Tricomi confluent hypergeometric function" + sympy_name = "" diff --git a/mathics/builtin/specialfns/orthogonal.py b/mathics/builtin/specialfns/orthogonal.py index bd2cb002e..4925a2f09 100644 --- a/mathics/builtin/specialfns/orthogonal.py +++ b/mathics/builtin/specialfns/orthogonal.py @@ -1,5 +1,9 @@ """ Orthogonal Polynomials + +See also +:Chapters 18.3 Classical Orthogonal Polynomials in the Digital Library of Mathematical Functions: +https://dlmf.nist.gov/18.3. """ @@ -12,8 +16,8 @@ class ChebyshevT(MPMathFunction): :Chebyshev polynomial of the first kind: https://en.wikipedia.org/wiki/Chebyshev_polynomials (:Sympy: https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.polynomials.chebyshevt, :WMA: https://reference.wolfram.com/language/ref/ChebyshevT.html)
      -
      'ChebyshevT[$n$, $x$]' -
      returns the Chebyshev polynomial of the first kind T_$n$($x$). +
      'ChebyshevT'[$n$, $x$] +
      returns the Chebyshev polynomial of the first kind $T_n(x)$.
      >> ChebyshevT[8, x] @@ -35,8 +39,8 @@ class ChebyshevU(MPMathFunction):
      -
      'ChebyshevU[$n$, $x$]' -
      returns the Chebyshev polynomial of the second kind U_$n$($x$). +
      'ChebyshevU'[$n$, $x$] +
      returns the Chebyshev polynomial of the second kind $U_n(x)$.
      >> ChebyshevU[8, x] @@ -57,8 +61,8 @@ class GegenbauerC(MPMathFunction): :Gegenbauer polynomials: https://en.wikipedia.org/wiki/Gegenbauer_polynomials (:SymPy: https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.polynomials.gegenbauer, :WMA: https://reference.wolfram.com/language/ref/GegenbauerC.html)
      -
      'GegenbauerC[$n$, $m$, $x$]' -
      returns the Gegenbauer polynomial C_$n$^($m$)($x$). +
      'GegenbauerC'[$n$, $m$, $x$] +
      returns the Gegenbauer polynomial $C_n^{(m)}(x)$.
      >> GegenbauerC[6, 1, x] @@ -80,8 +84,8 @@ class HermiteH(MPMathFunction): """ :Hermite polynomial: https://en.wikipedia.org/wiki/Hermite_polynomials (:SymPy: https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.polynomials.hermite, :WMA: https://reference.wolfram.com/language/ref/HermiteH.html)
      -
      'HermiteH[$n$, $x$]' -
      returns the Hermite polynomial H_$n$($x$). +
      'HermiteH'[$n$, $x$] +
      returns the Hermite polynomial $H_n(x)$.
      >> HermiteH[8, x] @@ -105,8 +109,8 @@ class JacobiP(MPMathFunction): :Jacobi polynomials: https://en.wikipedia.org/wiki/Jacobi_polynomials (:SymPy: https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.polynomials.jacobi, :WMA: https://reference.wolfram.com/language/ref/JacobiP.html)
      -
      'JacobiP[$n$, $a$, $b$, $x$]' -
      returns the Jacobi polynomial P_$n$^($a$,$b$)($x$). +
      'JacobiP'[$n$, $a$, $b$, $x$] +
      returns the Jacobi polynomial $P_n^{(a,b)}(x)$.
      >> JacobiP[1, a, b, z] @@ -127,11 +131,12 @@ class LaguerreL(MPMathFunction): :Laguerre polynomials: https://en.wikipedia.org/wiki/Laguerre_polynomials (:SymPy: https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.polynomials.leguarre_poly, :WMA: https://reference.wolfram.com/language/ref/LeguerreL.html)
      -
      'LaguerreL[$n$, $x$]' -
      returns the Laguerre polynomial L_$n$($x$). +
      'LaguerreL'[$n$, $x$] +
      returns the Laguerre polynomial $L_n(x)$. -
      'LaguerreL[$n$, $a$, $x$]' -
      returns the generalised Laguerre polynomial L^$a$_$n$($x$). +
      'LaguerreL'[$n$, $a$, $x$] +
      returns the generalised Laguerre polynomial of order $n$ + and index $a$, $L^a_n(x)$.
      >> LaguerreL[8, x] @@ -163,11 +168,11 @@ class LegendreP(MPMathFunction): """ :Lengendre polynomials: https://en.wikipedia.org/wiki/Legendre_polynomials (:SymPy: https://docs.sympy.org/latest/modules/functions/special.html#sympy.functions.special.polynomials.legendre, :WMA: https://reference.wolfram.com/language/ref/LegendreP)
      -
      'LegendreP[$n$, $x$]' -
      returns the Legendre polynomial P_$n$($x$). +
      'LegendreP'[$n$, $x$] +
      returns the Legendre polynomial $P_n(x)$. -
      'LegendreP[$n$, $m$, $x$]' -
      returns the associated Legendre polynomial P^$m$_$n$($x$). +
      'LegendreP'[$n$, $m$, $x$] +
      returns the associated Legendre polynomial $P^m_n(x)$.
      >> LegendreP[4, x] @@ -214,11 +219,11 @@ class LegendreQ(MPMathFunction): """ :Legendre functions of the second kind: https://mathworld.wolfram.com/LegendreFunctionoftheSecondKind.html (:mpmath: https://mpmath.org/doc/current/functions/orthogonal.html#mpmath.legenq, :WMA: https://reference.wolfram.com/language/ref/LegendreQ)
      -
      'LegendreQ[$n$, $x$]' -
      returns the Legendre function of the second kind Q_$n$($x$). +
      'LegendreQ'[$n$, $x$] +
      returns the Legendre function of the second kind $Q_n(x)$. -
      'LegendreQ[$n$, $m$, $x$]' -
      returns the associated Legendre function of the second Q^$m$_$n$($x$). +
      'LegendreQ'[$n$, $m$, $x$] +
      returns the associated Legendre function of the second $Q^m_n(x)$.
      >> LegendreQ[5/2, 1.5] @@ -256,11 +261,11 @@ def prepare_sympy(self, elements): class SphericalHarmonicY(MPMathFunction): - """ - :Spherical Harmonic https://mathworld.wolfram.com/SphericalHarmonic.html (:mpmath: https://mpmath.org/doc/current/functions/orthogonal.html#mpmath.sperharm, :WMA: https://reference.wolfram.com/language/ref/SphericalHarmonicY.html) + r""" + :Spherical Harmonic https://mathworld.wolfram.com/SphericalHarmonic.html (:mpmath: https://mpmath.org/doc/current/functions/orthogonal.html#mpmath.spherharm, :WMA: https://reference.wolfram.com/language/ref/SphericalHarmonicY.html)
      -
      'SphericalHarmonicY[$l$, $m$, $theta$, $phi$]' -
      returns the spherical harmonic function Y_$l$^$m$(theta, phi). +
      'SphericalHarmonicY'[$l$, $m$, $\theta$, $\phi$] +
      returns the spherical harmonic function $Y_l^m(\theta, \phi)$.
      >> SphericalHarmonicY[3/4, 0.5, Pi/5, Pi/3] @@ -292,7 +297,7 @@ def prepare_mathics(self, sympy_expr): # :Zermike polynomials: https://en.wikipedia.org/wiki/Zernike_polynomials. #
      -#
      'ZernikeR[$n$, $m$, $r$]' +#
      'ZernikeR'[$n$, $m$, $r$] #
      returns the radial Zernike polynomial R_$n$^$m$($r$). #
      # diff --git a/mathics/builtin/specialfns/zeta.py b/mathics/builtin/specialfns/zeta.py index c2ea553f6..4d4f6ed3f 100644 --- a/mathics/builtin/specialfns/zeta.py +++ b/mathics/builtin/specialfns/zeta.py @@ -2,6 +2,10 @@ """ Zeta Functions and Polylogarithms + +See also +:Chapters 25 Zeta and Related Functions in the Digital Library of Mathematical Functions: +https://dlmf.nist.gov/25. """ import mpmath @@ -16,32 +20,39 @@ from mathics.core.builtin import MPMathFunction from mathics.core.convert.mpmath import from_mpmath from mathics.core.convert.sympy import from_sympy +from mathics.core.evaluation import Evaluation class LerchPhi(MPMathFunction): - """ - - :WMA link: - https://reference.wolfram.com/language/ref/LerchPhi.html + r""" + :Lerch transcendent: + https://en.wikipedia.org/wiki/Lerch_transcendent ( + :WMA: + https://reference.wolfram.com/language/ref/LerchPhi.html)
      'LerchPhi[z,s,a]' -
      gives the Lerch transcendent ÎŚ(z,s,a). +
      gives the Lerch transcendent $\Phi(z,s,a)$.
      >> LerchPhi[2, 3, -1.5] = 19.3893 - 2.1346 I - >> LerchPhi[1, 2, 1/4] - = 17.1973 + >> LerchPhi[1, 2, 1/4] == 8 Catalan + Pi^2 + = True + + Plot between between -1 and 1: + >> Plot[LerchPhi[x, 1, 2], {x, -1, 1}] + = -Graphics- + """ attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED mpmath_name = "lerchphi" sympy_name = "lerchphi" - summary_text = "Lerch's trascendental ϕ function" + summary_text = "compute Lerch's trascendental ϕ function" - def eval(self, z, s, a, evaluation): + def eval(self, z, s, a, evaluation: Evaluation): "%(name)s[z_, s_, a_]" py_z = z.to_python() @@ -56,42 +67,47 @@ def eval(self, z, s, a, evaluation): class PolyLog(MPMathFunction): """ - - :WMA link: - https://reference.wolfram.com/language/ref/PolyLog.html + :Polylogarithm: + https://en.wikipedia.org/wiki/Polylogarithm ( + :WMA: + https://reference.wolfram.com/language/ref/PolyLog.html)
      -
      'PolyLog[$n$, $z$]' -
      returns the polylogarithm function Li_$n$($z$). +
      'PolyLog'[$n$, $z$] +
      returns the polylogarithm function $Li_n(z)$.
      >> PolyLog[s, 1] = Zeta[s] >> PolyLog[-7, I] //Chop = 136. + + Dilogarithm function $Li_2(x)$: + >> Plot[PolyLog[2,x], {x, -20, 1}] + = -Graphics- """ attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED - summary_text = "Polylogarithm function" - sympy_name = "polylog" mpmath_name = "polylog" + summary_text = "compute the Polylogarithm function" + sympy_name = "polylog" - def eval(self, n, z, evaluation): + def eval(self, n, z, evaluation: Evaluation): "PolyLog[n_, z_]" try: return from_mpmath(mpmath.polylog(n.to_python(), z.to_python())) - except: + except Exception: return from_sympy(sympy.polylog(n.to_sympy(), z.to_sympy())) class Zeta(MPMathFunction): """ - - :WMA link: - https://reference.wolfram.com/language/ref/Zeta.html + :Riemenn zeta function: + https://en.wikipedia.org/wiki/Riemann_zeta_function (:WMA: + https://reference.wolfram.com/language/ref/Zeta.html)
      -
      'Zeta[$z$]' +
      'Zeta'[$z$]
      returns the Riemann zeta function of $z$.
      @@ -100,12 +116,15 @@ class Zeta(MPMathFunction): >> Zeta[-2.5 + I] = 0.0235936 + 0.0014078 I + + >> Plot[Zeta[z], {z, -20, 10}] + = -Graphics- """ attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED - summary_text = "Riemann's Îś function" sympy_name = "zeta" mpmath_name = "zeta" + summary_text = "compute Riemann's Îś function" # TODO: ReimannSiegelTheta, ReimannSiegelZ, ReimannXi, ZetaZero diff --git a/mathics/builtin/statistics/dependency.py b/mathics/builtin/statistics/dependency.py index e2949f40e..db3f335a7 100644 --- a/mathics/builtin/statistics/dependency.py +++ b/mathics/builtin/statistics/dependency.py @@ -39,7 +39,7 @@ class Correlation(Builtin): https://reference.wolfram.com/language/ref/Correlation.html)
      -
      'Correlation[$a$, $b$]' +
      'Correlation'[$a$, $b$]
      computes Pearson's correlation of two equal-sized vectors $a$ and $b$.
      @@ -78,7 +78,7 @@ class Covariance(Builtin): :WMA: https://reference.wolfram.com/language/ref/Covariance.html)
      -
      'Covariance[$a$, $b$]' +
      'Covariance'[$a$, $b$]
      computes the covariance between the equal-sized vectors $a$ and $b$.
      @@ -119,12 +119,12 @@ class StandardDeviation(Rectangular): :WMA: https://reference.wolfram.com/language/ref/StandardDeviation.html)
      -
      'StandardDeviation[$list$]' +
      'StandardDeviation'[$list$]
      computes the standard deviation of $list. $list$ may consist of \ numerical values or symbols. Numerical values may be real or complex. - StandardDeviation[{{$a1$, $a2$, ...}, {$b1$, $b2$, ...}, ...}] will yield - {StandardDeviation[{$a1$, $b1$, ...}, StandardDeviation[{$a2$, $b2$, ...}], ...}. + StandardDeviation[{{$a_1$, $a_2$, ...}, {$b_1$, $b_2$, ...}, ...}] will yield + {StandardDeviation[{$a_1$, $b_1$, ...}, StandardDeviation[{$a_2$, $b_2$, ...}], ...}.
      >> StandardDeviation[{1, 2, 3}] @@ -171,10 +171,10 @@ class Variance(Rectangular): :WMA: https://reference.wolfram.com/language/ref/Variance.html)
      -
      'Variance[$list$]' +
      'Variance'[$list$]
      computes the variance of $list. $list$ may consist of numerical values or symbols. Numerical values may be real or complex. - Variance[{{$a1$, $a2$, ...}, {$b1$, $b2$, ...}, ...}] will yield {Variance[{$a1$, $b1$, ...}, Variance[{$a2$, $b2$, ...}], ...}. + Variance[{{$a_1$, $a_2$, ...}, {$b_1$, $b_2$, ...}, ...}] will yield {Variance[{$a_1$, $b_1$, ...}, Variance[{$a_2$, $b_2$, ...}], ...}.
      >> Variance[{1, 2, 3}] diff --git a/mathics/builtin/statistics/general.py b/mathics/builtin/statistics/general.py index 782c8147b..5e667588f 100644 --- a/mathics/builtin/statistics/general.py +++ b/mathics/builtin/statistics/general.py @@ -19,7 +19,7 @@ class CentralMoment(Builtin): https://reference.wolfram.com/language/ref/CentralMoment.html)
      -
      'CentralMoment[$list$, $r$]' +
      'CentralMoment'[$list$, $r$]
      gives the the $r$th central moment (i.e. the $r$th moment about the mean) of $list$.
      @@ -36,7 +36,7 @@ class CentralMoment(Builtin): # class Moment(SympyFunction): # """ #
      -#
      'Moment[$sample_List$, $r$]' +#
      'Moment'[$sample_List$, $r$] #
      gives the the $r$th sample moment of the elements of $list$. #
      diff --git a/mathics/builtin/statistics/location.py b/mathics/builtin/statistics/location.py index 079e290ea..8186b48e2 100644 --- a/mathics/builtin/statistics/location.py +++ b/mathics/builtin/statistics/location.py @@ -19,7 +19,7 @@ class Mean(Builtin): https://reference.wolfram.com/language/ref/Mean.html
      -
      'Mean[$list$]' +
      'Mean'[$list$]
      returns the statistical mean of $list$.
      @@ -46,7 +46,7 @@ class Median(Rectangular): https://reference.wolfram.com/language/ref/Median.html
      -
      'Median[$list$]' +
      'Median'[$list$]
      returns the median of $list$.
      diff --git a/mathics/builtin/statistics/orderstats.py b/mathics/builtin/statistics/orderstats.py index 6c33000f2..12b0314f7 100644 --- a/mathics/builtin/statistics/orderstats.py +++ b/mathics/builtin/statistics/orderstats.py @@ -47,20 +47,19 @@ class Quantile(Builtin): Quantile is also known as value at risk (VaR) or fractile.
      -
      'Quantile[$list$, $q$]' +
      'Quantile'[$list$, $q$]
      returns the $q$th quantile of $list$. -
      'Quantile[$list$, $q$, {{$a$,$b$}, {$c$,$d$}}]' +
      'Quantile'[$list$, $q$, {{$a,b$}, {$c,d$}}]
      uses the quantile definition specified by parameters $a$, $b$, $c$, $d$. -
      For a list of length $n$: - 'Quantile[$list$, $q$, {{$a$,$b$}, {$c$,$d$}}]' - depends on $x$=$a$+($n$+$b$)$q$. + For a list of length $n$, 'Quantile'[$list$, $q$, {{$a ,b$}, {$c, d$}}] depends \ + on $x=a+(n+b)q$. - If $x$ is an integer, the result is '$s$[[$x$]]', where $s$='Sort[list,Less]'. + If $x$ is an integer, the result is $s[[x]]$, where $s$='Sort[list,Less]'. Otherwise, the result is: - 's[[Floor[x]]]+(s[[Ceiling[x]]]-s[[Floor[x]]])(c+dFractionalPart[x])', + 's[[Floor[x]]] + (s[[Ceiling[x]]] - s[[Floor[x]]])(c + d FractionalPart[x])', with the indices taken to be 1 or n if they are out of range. The default choice of parameters is '{{0,0},{1,0}}'. @@ -177,7 +176,7 @@ class Quartiles(Builtin): :WMA link: https://reference.wolfram.com/language/ref/Quartiles.html)
      -
      'Quartiles[$list$]' +
      'Quartiles'[$list$]
      returns the 1/4, 1/2, and 3/4 quantiles of $list$.
      @@ -197,7 +196,7 @@ class RankedMax(Builtin): :WMA link:https://reference.wolfram.com/language/ref/RankedMax.html
      -
      'RankedMax[$list$, $n$]' +
      'RankedMax'[$list$, $n$]
      returns the $n$th largest element of $list$ (with $n$ = 1 yielding the largest element, $n$ = 2 yielding the second largest element, and so on).
      @@ -234,7 +233,7 @@ class RankedMin(Builtin): https://reference.wolfram.com/language/ref/RankedMin.html
      -
      'RankedMin[$list$, $n$]' +
      'RankedMin'[$list$, $n$]
      returns the $n$th smallest element of $list$ (with \ $n$ = 1 yielding the smallest element, $n$ = 2 yielding \ the second smallest element, and so on). @@ -269,11 +268,11 @@ class ReverseSort(Builtin): :WMA link:https://reference.wolfram.com/language/ref/ReverseSort.html
      -
      'ReverseSort[$list$]' +
      'ReverseSort'[$list$]
      sorts $list$ (or the elements of any other expression) according \ to reverse canonical ordering. -
      'ReverseSort[$list$, $p$]' +
      'ReverseSort'[$list$, $p$]
      sorts using $p$ to determine the order of two elements.
      @@ -306,11 +305,11 @@ class Sort(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Sort.html
      -
      'Sort[$list$]' +
      'Sort'[$list$]
      sorts $list$ (or the elements of any other expression) according \ to canonical ordering. -
      'Sort[$list$, $p$]' +
      'Sort'[$list$, $p$]
      sorts using $p$ to determine the order of two elements.
      @@ -374,19 +373,20 @@ class TakeLargest(_RankedTakeLargest): https://reference.wolfram.com/language/ref/TakeLargest.html
      -
      'TakeLargest[$list$, $f$, $n$]' +
      'TakeLargest'[$list$, $f$, $n$]
      returns the a sorted list of the $n$ largest items in $list$.
      + List the largest two numbers of a list: >> TakeLargest[{100, -1, 50, 10}, 2] = {100, 50} - None, Null, Indeterminate and expressions with head Missing are ignored + None, Null, Indeterminate and expressions with head Missing are ignored \ by default: >> TakeLargest[{-8, 150, Missing[abc]}, 2] = {150, -8} - You may specify which items are ignored using the option ExcludedForms: + You may specify which items are ignored using the option 'ExcludedForms': >> TakeLargest[{-8, 150, Missing[abc]}, 2, ExcludedForms -> {}] = {Missing[abc], 150} """ @@ -404,14 +404,17 @@ class TakeSmallest(_RankedTakeSmallest): :WMA link:https://reference.wolfram.com/language/ref/TakeSmallest.html
      -
      'TakeSmallest[$list$, $n$]' +
      'TakeSmallest'[$list$, $n$]
      returns the a sorted list of the $n$ smallest items in $list$.
      - For details on how to use the ExcludedForms option, see TakeLargest[]. - + List the smallest two numbers of a list: >> TakeSmallest[{100, -1, 50, 10}, 2] = {-1, 10} + + For details on how to use the 'ExcludedForms' option, see + :TakeLargest: + /doc/reference-of-built-in-symbols/descriptive-statistics/order-statistics/takelargest/. """ attributes = A_PROTECTED diff --git a/mathics/builtin/statistics/shape.py b/mathics/builtin/statistics/shape.py index f0b9e6218..0ee7b6a13 100644 --- a/mathics/builtin/statistics/shape.py +++ b/mathics/builtin/statistics/shape.py @@ -11,7 +11,7 @@ class Kurtosis(Builtin): """ :Kurtosis: https://en.wikipedia.org/wiki/Kurtosis (:WMA: https://reference.wolfram.com/language/ref/Kurtosis.html)
      -
      'Kurtosis[$list$]' +
      'Kurtosis'[$list$]
      gives the Pearson measure of kurtosis for $list$ (a measure of existing outliers).
      @@ -30,7 +30,7 @@ class Skewness(Builtin): :Skewness: https://en.wikipedia.org/wiki/Skewness (:WMA: https://reference.wolfram.com/language/ref/Skewness.html)
      -
      'Skewness[$list$]' +
      'Skewness'[$list$]
      gives Pearson's moment coefficient of skewness for $list$ (a measure for estimating the symmetry of a distribution).
      diff --git a/mathics/builtin/string/characters.py b/mathics/builtin/string/characters.py index 337cfb897..a5c86fc68 100644 --- a/mathics/builtin/string/characters.py +++ b/mathics/builtin/string/characters.py @@ -19,7 +19,7 @@ class Characters(Builtin): https://reference.wolfram.com/language/ref/Characters.html
      -
      'Characters["$string$"]' +
      'Characters'["$string$"]
      returns a list of the characters in $string$.
      @@ -43,7 +43,7 @@ class CharacterRange(Builtin): https://reference.wolfram.com/language/ref/CharacterRange.html
      -
      'CharacterRange["$a$", "$b$"]' +
      'CharacterRange'["$a$", "$b$"]
      returns a list of the Unicode characters from $a$ to $b$ inclusive.
      @@ -77,7 +77,7 @@ class LowerCaseQ(Test): :WMA link:https://reference.wolfram.com/language/ref/LowerCaseQ.html
      -
      'LowerCaseQ[$s$]' +
      'LowerCaseQ'[$s$]
      returns True if $s$ consists wholly of lower case characters.
      @@ -102,7 +102,7 @@ class ToLowerCase(Builtin): :WMA link:https://reference.wolfram.com/language/ref/ToLowerCase.html
      -
      'ToLowerCase[$s$]' +
      'ToLowerCase'[$s$]
      returns $s$ in all lower case.
      @@ -123,7 +123,7 @@ class ToUpperCase(Builtin): :WMA link:https://reference.wolfram.com/language/ref/ToUpperCase.html
      -
      'ToUpperCase[$s$]' +
      'ToUpperCase'[$s$]
      returns $s$ in all upper case.
      @@ -144,7 +144,7 @@ class UpperCaseQ(Test): :WMA link:https://reference.wolfram.com/language/ref/UpperCaseQ.html
      -
      'UpperCaseQ[$s$]' +
      'UpperCaseQ'[$s$]
      returns True if $s$ consists wholly of upper case characters.
      diff --git a/mathics/builtin/string/charcodes.py b/mathics/builtin/string/charcodes.py index 67a4e7b71..22bcfd8b3 100644 --- a/mathics/builtin/string/charcodes.py +++ b/mathics/builtin/string/charcodes.py @@ -33,10 +33,10 @@ class ToCharacterCode(Builtin): https://reference.wolfram.com/language/ref/ToCharacterCode.html
      -
      'ToCharacterCode["$string$"]' +
      'ToCharacterCode'["$string$"]
      converts the string to a list of character codes (Unicode codepoints). -
      'ToCharacterCode[{"$string1$", "$string2$", ...}]' +
      'ToCharacterCode'[{"$string_1$", "$string_2$", ...}]
      converts a list of strings to character codes.
      @@ -124,13 +124,13 @@ class FromCharacterCode(Builtin): https://reference.wolfram.com/language/ref/FromCharacterCode.html
      -
      'FromCharacterCode[$n$]' +
      'FromCharacterCode'[$n$]
      returns the character corresponding to Unicode codepoint $n$. -
      'FromCharacterCode[{$n1$, $n2$, ...}]' +
      'FromCharacterCode'[{$n_1$, $n_2$, ...}]
      returns a string with characters corresponding to $n_i$. -
      'FromCharacterCode[{{$n11$, $n12$, ...}, {$n21$, $n22$, ...}, ...}]' +
      'FromCharacterCode'[{{$n_{11}$, $n_{12}$, ...}, {$n_{21}$, $n_{22}$, ...}, ...}]
      returns a list of strings.
      diff --git a/mathics/builtin/string/operations.py b/mathics/builtin/string/operations.py index b74a26df2..d4512e03b 100644 --- a/mathics/builtin/string/operations.py +++ b/mathics/builtin/string/operations.py @@ -49,16 +49,16 @@ class StringDrop(Builtin): https://reference.wolfram.com/language/ref/StringDrop.html
      -
      'StringDrop["$string$", $n$]' +
      'StringDrop'["$string$", $n$]
      gives $string$ with the first $n$ characters dropped. -
      'StringDrop["$string$", -$n$]' +
      'StringDrop'["$string$", -$n$]
      gives $string$ with the last $n$ characters dropped. -
      'StringDrop["$string$", {$n$}]' -
      gives $string$ with the $n$th character dropped. +
      'StringDrop'["$string$", {$n$}] +
      gives $string$ with the $n$-th character dropped. -
      'StringDrop["$string$", {$m$, $n$}]' +
      'StringDrop'["$string$", {$m$, $n$}]
      gives $string$ with the characters $m$ through $n$ dropped.
      @@ -164,17 +164,17 @@ class StringInsert(Builtin): https://reference.wolfram.com/language/ref/StringInsert.html
      -
      'StringInsert["$string$", "$snew$", $n$]' +
      'StringInsert'["$string$", "$snew$", $n$]
      yields a string with $snew$ inserted starting at position $n$ in $string$. -
      'StringInsert["$string$", "$snew$", -$n$]' +
      'StringInsert'["$string$", "$snew$", -$n$]
      inserts a at position $n$ from the end of "$string$". -
      'StringInsert["$string$", "$snew$", {$n_1$, $n_2$, ...}]' +
      'StringInsert'["$string$", "$snew$", {$n_1$, $n_2$, ...}]
      inserts a copy of $snew$ at each position $n_i$ in $string$; the $n_i$ are taken before any insertion is done. -
      'StringInsert[{$s_1$, $s_2$, ...}, "$snew$", $n$]' +
      'StringInsert'[{$s_1$, $s_2$, ...}, "$snew$", $n$]
      gives the list of results for each of the $s_i$.
      @@ -303,8 +303,8 @@ class StringJoin(InfixOperator): :WMA link:https://reference.wolfram.com/language/ref/StringJoin.html
      -
      'StringJoin["$s1$", "$s2$", ...]' -
      returns the concatenation of the strings $s1$, $s2$, . +
      'StringJoin'["$s_1$", "$s_2$", ...] +
      returns the concatenation of the strings $s_1$, $s_2$, .
      >> StringJoin["a", "b", "c"] @@ -344,7 +344,7 @@ class StringLength(Builtin): :WMA link:https://reference.wolfram.com/language/ref/StringLength.html
      -
      'StringLength["$string$"]' +
      'StringLength'["$string$"]
      gives the length of $string$.
      @@ -376,13 +376,13 @@ class StringPosition(Builtin): :WMA link:https://reference.wolfram.com/language/ref/StringPosition.html
      -
      'StringPosition["$string$", $patt$]' +
      'StringPosition'["$string$", $patt$]
      gives a list of starting and ending positions where $patt$ matches "$string$". -
      'StringPosition["$string$", $patt$, $n$]' +
      'StringPosition'["$string$", $patt$, $n$]
      returns the first $n$ matches only. -
      'StringPosition["$string$", {$patt1$, $patt2$, ...}, $n$]' +
      'StringPosition'["$string$", {$patt_1$, $patt_2$, ...}, $n$]
      matches multiple patterns. -
      'StringPosition[{$s1$, $s2$, ...}, $patt$]' +
      'StringPosition'[{$s_1$, $s_2$, ...}, $patt$]
      returns a list of matches for multiple strings.
      @@ -507,14 +507,14 @@ class StringReplace(_StringFind): :WMA link:https://reference.wolfram.com/language/ref/StringReplace.html
      -
      'StringReplace["$string$", "$a$"->"$b$"]' +
      'StringReplace'["$string$", "$a$"->"$b$"]
      replaces each occurrence of $old$ with $new$ in $string$. -
      'StringReplace["$string$", {"$s1$"->"$sp1$", "$s2$"->"$sp2$"}]' +
      'StringReplace'["$string$", {"$s_1$"->"$sp_1$", "$s_2$"->"$sp_2$"}]
      performs multiple replacements of each $si$ by the corresponding $spi$ in $string$. -
      'StringReplace["$string$", $srules$, $n$]' +
      'StringReplace'["$string$", $srules$, $n$]
      only performs the first $n$ replacements. -
      'StringReplace[{"$string1$", "$string2$", ...}, $srules$]' +
      'StringReplace'[{"$string_1$", "$string_2$", ...}, $srules$]
      performs the replacements specified by $srules$ on a list of strings.
      @@ -581,7 +581,7 @@ class StringReverse(Builtin): :WMA link:https://reference.wolfram.com/language/ref/StringReverse.html
      -
      'StringReverse["$string$"]' +
      'StringReverse'["$string$"]
      reverses the order of the characters in "string".
      @@ -703,16 +703,16 @@ class StringSplit(Builtin): :WMA link:https://reference.wolfram.com/language/ref/StringSplit.html
      -
      'StringSplit[$s$]' +
      'StringSplit'[$s$]
      splits the string $s$ at whitespace, discarding the whitespace and returning a list of strings. -
      'StringSplit[$s$, $pattern$]' +
      'StringSplit'[$s$, $pattern$]
      splits $s$ into substrings separated by delimiters matching the string expression $pattern$. -
      'StringSplit[$s$, {$p_1$, $p_2$, ...}]' +
      'StringSplit'[$s$, {$p_1$, $p_2$, ...}]
      splits $s$ at any of the $p_i$ patterns. -
      'StringSplit[{$s_1$, $s_2$, ...}, {$d_1$, $d_2$, ...}]' +
      'StringSplit'[{$s_1$, $s_2$, ...}, {$d_1$, $d_2$, ...}]
      returns a list with the result of applying the function to each element.
      @@ -740,7 +740,7 @@ class StringSplit(Builtin): >> StringSplit["x", "x"] = {} - Split using a delmiter that has nonzero list of 12's + Split using a delimiter that has nonzero list of 12's >> StringSplit["12312123", "12"..] = {3, 3} @@ -816,22 +816,22 @@ class StringTake(Builtin): :WMA link:https://reference.wolfram.com/language/ref/StringTake.html
      -
      'StringTake["$string$", $n$]' +
      'StringTake'["$string$", $n$]
      gives the first $n$ characters in $string$. -
      'StringTake["$string$", -$n$]' +
      'StringTake'["$string$", -$n$]
      gives the last $n$ characters in $string$. -
      'StringTake["$string$", {$n$}]' +
      'StringTake'["$string$", {$n$}]
      gives the $n$th character in $string$. -
      'StringTake["$string$", {$m$, $n$}]' +
      'StringTake'["$string$", {$m$, $n$}]
      gives characters $m$ through $n$ in $string$. -
      'StringTake["$string$", {$m$, $n$, $s$}]' +
      'StringTake'["$string$", {$m$, $n$, $s$}]
      gives characters $m$ through $n$ in steps of $s$. -
      'StringTake[{$s1$, $s2$, ...} $spec$}]' +
      'StringTake'[{$s_1$, $s_2$, ...} $spec$}]
      gives the list of results for each of the $si$.
      @@ -913,7 +913,7 @@ class StringTrim(Builtin): :WMA link:https://reference.wolfram.com/language/ref/StringTrim.html
      -
      'StringTrim[$s$]' +
      'StringTrim'[$s$]
      returns a version of $s$ with whitespace removed from start and end.
      diff --git a/mathics/builtin/string/patterns.py b/mathics/builtin/string/patterns.py index 12c91c6e0..648caf6ce 100644 --- a/mathics/builtin/string/patterns.py +++ b/mathics/builtin/string/patterns.py @@ -155,20 +155,20 @@ class StringCases(_StringFind): https://reference.wolfram.com/language/ref/StringCases.html
      -
      'StringCases["$string$", $pattern$]' +
      'StringCases'["$string$", $pattern$]
      gives all occurrences of $pattern$ in $string$. -
      'StringReplace["$string$", $pattern$ -> $form$]' +
      'StringReplace'["$string$", $pattern$ -> $form$]
      gives all instances of $form$ that stem from occurrences of $pattern$ in $string$. -
      'StringCases["$string$", {$pattern1$, $pattern2$, ...}]' -
      gives all occurrences of $pattern1$, $pattern2$, .... +
      'StringCases'["$string$", {$pattern_1$, $pattern_2$, ...}] +
      gives all occurrences of $pattern_1$, $pattern_2$, .... -
      'StringReplace["$string$", $pattern$, $n$]' +
      'StringReplace'["$string$", $pattern$, $n$]
      gives only the first $n$ occurrences. -
      'StringReplace[{"$string1$", "$string2$", ...}, $pattern$]' -
      gives occurrences in $string1$, $string2$, ... +
      'StringReplace'[{"$string_1$", "$string_2$", ...}, $pattern$] +
      gives occurrences in $string_1$, $string_2$, ...
      >> StringCases["axbaxxb", "a" ~~ x_ ~~ "b"] diff --git a/mathics/builtin/string/regexp.py b/mathics/builtin/string/regexp.py index da8d55ff7..02db0ca62 100644 --- a/mathics/builtin/string/regexp.py +++ b/mathics/builtin/string/regexp.py @@ -15,7 +15,7 @@ class RegularExpression(Builtin):
      'RegularExpression["regex"]' -
      represents the regex specified by the string $"regex"$. +
      represents the regex specified by the string "$regex$".
      >> StringSplit["1.23, 4.56 7.89", RegularExpression["(\\s|,)+"]] diff --git a/mathics/builtin/symbolic_history/stack.py b/mathics/builtin/symbolic_history/stack.py index 09a0aa119..25422ac09 100644 --- a/mathics/builtin/symbolic_history/stack.py +++ b/mathics/builtin/symbolic_history/stack.py @@ -15,7 +15,7 @@ class Stack(Builtin):
      'Stack[]' -
      Print Mathics3 stack trace of evalutations leading to this point. +
      Print Mathics3 stack trace of evaluations leading to this point.
      >> f[g[1, Print[Stack[]] ; 2]] @@ -44,7 +44,7 @@ class Trace(Builtin): https://reference.wolfram.com/language/ref/Trace.html
      -
      'Trace[$expr$]' +
      'Trace'[$expr$]
      generate a list of all expressions used in the evaluation of $expr$.
      diff --git a/mathics/builtin/system.py b/mathics/builtin/system.py index 8b26cc7d0..ea46f41d0 100644 --- a/mathics/builtin/system.py +++ b/mathics/builtin/system.py @@ -4,6 +4,7 @@ Global System Information """ +import _thread import gc import os import platform @@ -76,15 +77,14 @@ class Breakpoint(Builtin): def eval(self, evaluation: Evaluation): "Breakpoint[]" - breakpoint() class CommandLine(Predefined): """ - :WMA link:https://reference.wolfram.com/language/ref/$CommandLine.html + :WMA link:https://reference.wolfram.com/language/ref/\\$CommandLine.html
      -
      '$CommandLine' +
      '\\$CommandLine'
      is a list of strings passed on the command line to launch the Mathics3 session.
      @@ -92,11 +92,11 @@ class CommandLine(Predefined): = {...} """ + name = "$CommandLine" summary_text = ( - "the command line arguments passed when the current Mathics3 " + "get the command line arguments passed when the current Mathics3 " "session was launched" ) - name = "$CommandLine" def evaluate(self, evaluation: Evaluation) -> Expression: return ListExpression(*(String(arg) for arg in sys.argv)) @@ -107,7 +107,7 @@ class Environment(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Environment.html
      -
      'Environment[$var$]' +
      'Environment'[$var$]
      gives the value of an operating system environment variable.
      @@ -137,11 +137,11 @@ class GetEnvironment(Builtin): :WMA link:https://reference.wolfram.com/language/ref/GetEnvironment.html
      -
      'GetEnvironment["$var$"]' +
      'GetEnvironment'["$var$"]
      gives the setting corresponding to the variable "var" in the operating \ system environment. -
      'GetEnvironment[{"$var1$", "$var2$", ...}]' +
      'GetEnvironment'[{"$var_1$", "$var_2$", ...}]
      gives a list rules for each of the environment variables listed.
      'GetEnvironment[]' @@ -217,10 +217,10 @@ def eval(self, var, evaluation: Evaluation): class Machine(Predefined): """ - :WMA link:https://reference.wolfram.com/language/ref/$Machine.html + :WMA link:https://reference.wolfram.com/language/ref/\\$Machine.html
      -
      '$Machine' +
      '\\$Machine'
      returns a string describing the type of computer system on which the \ Mathics3 is being run.
      @@ -241,7 +241,7 @@ class MachineName(Predefined): :WMA link:https://reference.wolfram.com/language/ref/MachineName.html
      -
      '$MachineName' +
      '\\$MachineName'
      is a string that gives the assigned name of the computer on which Mathics3 \ is being run, if such a name is defined.
      @@ -250,8 +250,8 @@ class MachineName(Predefined): = ... """ - summary_text = "the name of computer over with Mathics is running" name = "$MachineName" + summary_text = "get the name of computer that Mathics3 is running" def evaluate(self, evaluation: Evaluation) -> String: return String(platform.uname().node) @@ -270,7 +270,7 @@ class MathicsVersion(Predefined): = ... """ - summary_text = "the version of the mathics core" + summary_text = "get the version of the Mathics3 kernel" def evaluate(self, evaluation: Evaluation) -> String: return String(__version__) @@ -287,7 +287,7 @@ class MaxLengthIntStringConversion(Predefined): string value is too large, then the middle of the integer contains \ an indication of the number of digits elided inside << >>. - If '$MaxLengthIntStringConversion' is set to 0, there is no \ + If '\\$MaxLengthIntStringConversion' is set to 0, there is no \ bound. Aside from 0, 640 is the smallest value allowed. The initial value can be set via environment variable \ @@ -303,7 +303,7 @@ class MaxLengthIntStringConversion(Predefined): the number of digits allows when converting a large integer into \ a string. - Show the default value of '$MaxLengthIntStringConversion': + Show the default value of '\\$MaxLengthIntStringConversion': >> $MaxLengthIntStringConversion = ... @@ -311,14 +311,14 @@ class MaxLengthIntStringConversion(Predefined): >> 500! //ToString//StringLength = ... - We first set '$MaxLengthIntStringConversion' to the smallest value allowed, \ + We first set '\\$MaxLengthIntStringConversion' to the smallest value allowed, \ so that we can see the truncation of digits in the middle: >> $MaxLengthIntStringConversion = 640 ## Pyston 2.3.5 returns 0 while CPython returns 640 ## Therefore output testing below is generic. = ... - Note that setting '$MaxLengthIntStringConversion' has an effect only on Python 3.11 and later; + Note that setting '\\$MaxLengthIntStringConversion' has an effect only on Python 3.11 and later; Pyston 2.x however ignores this. Now when we print the string value of 500! and Pyston 2.x is not used, \ @@ -342,7 +342,9 @@ class MaxLengthIntStringConversion(Predefined): attributes = A_CONSTANT messages = {"inv": "`1` is not 0 or an Integer value greater than 640."} name = "$MaxLengthIntStringConversion" - summary_text = "the maximum length for which an integer is converted to a String" + summary_text = ( + "get the maximum length for which an integer is converted to a String" + ) def evaluate(self, evaluation: Evaluation) -> Integer: try: @@ -384,7 +386,7 @@ class MemoryInUse(Builtin): = ... """ - summary_text = "number of bytes of memory currently being used by Mathics3" + summary_text = "get the number of bytes of memory currently being used by Mathics3" def eval(self, evaluation: Evaluation) -> Integer: """MemoryInUse[]""" @@ -397,7 +399,7 @@ class Packages(Predefined): :WMA link:https://reference.wolfram.com/language/ref/Packages.html
      -
      '$Packages' +
      '\\$Packages'
      returns a list of the contexts corresponding to all packages which have \ been loaded into Mathics.
      @@ -418,7 +420,7 @@ class ParentProcessID(Predefined): :WMA link:https://reference.wolfram.com/language/ref/$ParentProcessID.html
      -
      '$ParentProcesID' +
      '\$ParentProcesID'
      gives the ID assigned to the process which invokes Mathics3 by the operating \ system under which it is run.
      @@ -440,7 +442,7 @@ class ProcessID(Predefined): :WMA link:https://reference.wolfram.com/language/ref/ProcessID.html
      -
      '$ProcessID' +
      '\$ProcessID'
      gives the ID assigned to the Mathics3 process by the operating system under \ which it is run.
      @@ -463,7 +465,7 @@ class ProcessorType(Predefined): https://reference.wolfram.com/language/ref/ProcessorType.html
      -
      '$ProcessorType' +
      '\\$ProcessorType'
      gives a string giving the architecture of the processor on which \ Mathics3 is being run.
      @@ -474,9 +476,7 @@ class ProcessorType(Predefined): name = "$ProcessorType" - summary_text = ( - "name of the architecture of the processor over which Mathics3 is running" - ) + summary_text = "get the name of the architecture of the processor over which Mathics3 is running" def evaluate(self, evaluation): return String(platform.machine()) @@ -487,7 +487,7 @@ class PythonImplementation(Predefined): ## :PythonImplementation native symbol:
      -
      '$PythonImplementation' +
      '\$PythonImplementation'
      gives a string indication the Python implementation used to run Mathics3.
      @@ -497,7 +497,7 @@ class PythonImplementation(Predefined): name = "$PythonImplementation" - summary_text = "name of the Python implementation running Mathics3" + summary_text = "get the name of the Python implementation running Mathics3" def evaluate(self, evaluation: Evaluation): from mathics.system_info import python_implementation @@ -510,7 +510,7 @@ class Run(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Run.html
      -
      'Run[$command$]' +
      'Run'[$command$]
      runs command as an external operating system command, returning the exit \ code returned from running the system command.
      @@ -532,7 +532,7 @@ class ScriptCommandLine(Predefined): :WMA link:https://reference.wolfram.com/language/ref/ScriptCommandLine.html
      -
      '$ScriptCommandLine' +
      '\\$ScriptCommandLine'
      is a list of string arguments when running the kernel is script mode.
      @@ -554,15 +554,43 @@ def evaluate(self, evaluation: Evaluation): return to_mathics_list(*params, elements_conversion_fn=String) +class SessionID(Predefined): + r""" + :WMA link:https://reference.wolfram.com/language/ref/SessionID.html + +
      +
      '\$SessionID' +
      is a number which is unique to a particular \Mathics System session. +
      + + X> $SessionID + = ... + """ + + name = "$SessionID" + summary_text = "get a unique session id" + + def evaluate(self, evaluation: Evaluation) -> Integer: + # In theory, it is possible for two different sessions to have + # the same id since threading ID's are recycled. Also in + # theory, on different processes the thread numbers might be + # the same. In practice, however, this is unlikely. What we + # want here is something that is likely to be available on all + # platforms and OS's including enscripten. I had considered + # folding in the os.getpid() value, but this is not available + # on the enscripten platform. + return Integer(_thread.get_ident()) + + class SetEnvironment(Builtin): """ :WMA link:https://reference.wolfram.com/language/ref/SetEnvironment.html
      -
      'SetEnvironment["$var$" -> $value"]' +
      'SetEnvironment'["$var$" -> "$value$"]
      sets the value of an operating system environment variable. -
      'SetEnvironment[{"$var$" -> $value", ...}]' +
      'SetEnvironment'[{"$var$" -> "$value$", ...}]
      sets more than one environment variable.
      @@ -682,7 +710,7 @@ class SystemID(Predefined): :WMA link:https://reference.wolfram.com/language/ref/SystemID.html
      -
      '$SystemID' +
      '\$SystemID'
      is a short string that identifies the type of computer system on which the \Mathics is being run.
      @@ -690,8 +718,8 @@ class SystemID(Predefined): = linux """ - summary_text = "id for the type of computer system" name = "$SystemID" + summary_text = "get id for the type of computer system" def evaluate(self, evaluation: Evaluation) -> String: return String(sys.platform) @@ -702,7 +730,7 @@ class SystemWordLength(Predefined): :WMA link:https://reference.wolfram.com/language/ref/SystemWordLength.html
      -
      '$SystemWordLength' +
      '\$SystemWordLength'
      gives the effective number of bits in raw machine words on the computer \ system where Mathics3 is running.
      @@ -711,8 +739,8 @@ class SystemWordLength(Predefined): = 64 """ - summary_text = "word length of computer system" name = "$SystemWordLength" + summary_text = "get word length of computer system" def evaluate(self, evaluation: Evaluation) -> Integer: # https://docs.python.org/3/library/platform.html#module-platform @@ -729,7 +757,7 @@ class UserName(Predefined): :WMA link:https://reference.wolfram.com/language/ref/UserName.html
      -
      $UserName +
      \$UserName
      returns the login name, according to the operative system, of the user that started the current \Mathics session.
      @@ -738,8 +766,8 @@ class UserName(Predefined): = ... """ - summary_text = "login name of the user that invoked the current session" name = "$UserName" + summary_text = "get login name of the user that invoked the current session" def evaluate(self, evaluation: Evaluation) -> String: try: @@ -764,10 +792,10 @@ class Version(Predefined): = Mathics3 ... """ - summary_text = "the current Mathics version" name = "$Version" + summary_text = "get the current Mathics3 version" - def evaluate(self, evaluation) -> String: + def evaluate(self, evaluation: Evaluation) -> String: return String(version_string.replace("\n", " ")) @@ -776,7 +804,7 @@ class VersionNumber(Predefined): :WMA link:https://reference.wolfram.com/language/ref/VersionNumber.html
      -
      '$VersionNumber' +
      '\$VersionNumber'
      is a real number which gives the current Wolfram Language version that \Mathics tries to be compatible with.
      @@ -784,9 +812,9 @@ class VersionNumber(Predefined): = ... """ - summary_text = "the version number of the current Mathics core" name = "$VersionNumber" value = 10.0 + summary_text = "get the version number of the current Mathics3 Kernel" def evaluate(self, evaluation: Evaluation) -> Real: # Make this be whatever the latest Mathematica release is, @@ -801,7 +829,7 @@ class SystemMemory(Predefined): :WMA link:https://reference.wolfram.com/language/ref/SystemMemory.html
      -
      '$SystemMemory' +
      '\\$SystemMemory'
      Returns the total amount of physical memory.
      @@ -809,8 +837,8 @@ class SystemMemory(Predefined): = ... """ - summary_text = "the total amount of physical memory in the system" name = "$SystemMemory" + summary_text = "get the total amount of physical memory in the system" def evaluate(self, evaluation: Evaluation) -> Integer: totalmem = psutil.virtual_memory().total @@ -828,12 +856,12 @@ class MemoryAvailable(Builtin): >> MemoryAvailable[] = ... - The relationship between $SystemMemory, MemoryAvailable, and MemoryInUse: + The relationship between \\$SystemMemory, MemoryAvailable, and MemoryInUse: >> $SystemMemory > MemoryAvailable[] > MemoryInUse[] = True """ - summary_text = "the available amount of physical memory in the system" + summary_text = "get the available amount of physical memory in the system" def eval(self, evaluation: Evaluation) -> Integer: """MemoryAvailable[]""" @@ -876,7 +904,7 @@ class MemoryAvailable(Builtin): = -1 """ - summary_text = "the available amount of physical memory in the system" + summary_text = "get the available amount of physical memory in the system" def eval(self, evaluation: Evaluation) -> Integer: """MemoryAvailable[]""" diff --git a/mathics/builtin/tensors.py b/mathics/builtin/tensors.py index 523717e73..420a51e01 100644 --- a/mathics/builtin/tensors.py +++ b/mathics/builtin/tensors.py @@ -18,7 +18,6 @@ of any rank can be handled. """ - from mathics.core.atoms import Integer from mathics.core.attributes import A_FLAT, A_ONE_IDENTITY, A_PROTECTED from mathics.core.builtin import Builtin, InfixOperator @@ -28,6 +27,7 @@ eval_Inner, eval_LeviCivitaTensor, eval_Outer, + eval_Transpose2D, get_dimensions, ) @@ -38,7 +38,7 @@ class ArrayDepth(Builtin): https://reference.wolfram.com/language/ref/ArrayDepth.html
      -
      'ArrayDepth[$a$]' +
      'ArrayDepth'[$a$]
      returns the depth of the non-ragged array $a$, defined as \ 'Length[Dimensions[$a$]]'.
      @@ -61,7 +61,7 @@ class Dimensions(Builtin): :WMA: https://reference.wolfram.com/language/ref/Dimensions.html
      -
      'Dimensions[$expr$]' +
      'Dimensions'[$expr$]
      returns a list of the dimensions of the expression $expr$.
      @@ -96,7 +96,7 @@ class Dot(InfixOperator): (:WMA link: https://reference.wolfram.com/language/ref/Dot.html)
      -
      'Dot[$x$, $y$]' +
      'Dot'[$x$, $y$]
      '$x$ . $y$'
      computes the vector dot product or matrix product $x$ . $y$.
      @@ -128,7 +128,7 @@ class Inner(Builtin): :WMA link: https://reference.wolfram.com/language/ref/Inner.html
      -
      'Inner[$f$, $x$, $y$, $g$]' +
      'Inner'[$f$, $x$, $y$, $g$]
      computes a generalised inner product of $x$ and $y$, using a multiplication function $f$ and an addition function $g$.
      @@ -174,7 +174,7 @@ class Outer(Builtin): (:WMA link: https://reference.wolfram.com/language/ref/Outer.html)
      -
      'Outer[$f$, $x$, $y$]' +
      'Outer'[$f$, $x$, $y$]
      computes a generalised outer product of $x$ and $y$, using the function $f$ in place of multiplication.
      @@ -229,10 +229,10 @@ class RotationTransform(Builtin): :WMA link: https://reference.wolfram.com/language/ref/RotationTransform.html
      -
      'RotationTransform[$phi$]' +
      'RotationTransform'[$phi$]
      gives a rotation by $phi$. -
      'RotationTransform[$phi$, $p$]' +
      'RotationTransform'[$phi$, $p$]
      gives a rotation by $phi$ around the point $p$.
      """ @@ -249,10 +249,10 @@ class ScalingTransform(Builtin): :WMA link: https://reference.wolfram.com/language/ref/ScalingTransform.html
      -
      'ScalingTransform[$v$]' +
      'ScalingTransform'[$v$]
      gives a scaling transform of $v$. $v$ may be a scalar or a vector. -
      'ScalingTransform[$phi$, $p$]' +
      'ScalingTransform'[$phi$, $p$]
      gives a scaling transform of $v$ that is centered at the point $p$.
      """ @@ -269,11 +269,11 @@ class ShearingTransform(Builtin): :WMA link: https://reference.wolfram.com/language/ref/ShearingTransform.html
      -
      'ShearingTransform[$phi$, {1, 0}, {0, 1}]' +
      'ShearingTransform'[$phi$, {1, 0}, {0, 1}]
      gives a horizontal shear by the angle $phi$. -
      'ShearingTransform[$phi$, {0, 1}, {1, 0}]' +
      'ShearingTransform'[$phi$, {0, 1}, {1, 0}]
      gives a vertical shear by the angle $phi$. -
      'ShearingTransform[$phi$, $u$, $u$, $p$]' +
      'ShearingTransform'[$phi$, $u$, $u$, $p$]
      gives a shear centered at the point $p$.
      """ @@ -291,7 +291,7 @@ class TransformationFunction(Builtin): :WMA link: https://reference.wolfram.com/language/ref/TransformationFunction.html
      -
      'TransformationFunction[$m$]' +
      'TransformationFunction'[$m$]
      represents a transformation.
      @@ -316,7 +316,7 @@ class TranslationTransform(Builtin): https://reference.wolfram.com/language/ref/TranslationTransform.html
      -
      'TranslationTransform[$v$]' +
      'TranslationTransform'[$v$]
      gives a 'TransformationFunction' that translates points by vector $v$.
      @@ -347,7 +347,7 @@ class Transpose(Builtin): :WMA: https://reference.wolfram.com/language/ref/Transpose.html)
      -
      'Transpose[$m$]' +
      'Transpose'[$m$]
      transposes rows and columns in the matrix $m$.
      @@ -378,15 +378,7 @@ class Transpose(Builtin): def eval(self, m, evaluation: Evaluation): "Transpose[m_?MatrixQ]" - - result = [] - for row_index, row in enumerate(m.elements): - for col_index, item in enumerate(row.elements): - if row_index == 0: - result.append([item]) - else: - result[col_index].append(item) - return ListExpression(*[ListExpression(*row) for row in result]) + return eval_Transpose2D(m) class ConjugateTranspose(Builtin): @@ -396,7 +388,7 @@ class ConjugateTranspose(Builtin): :WMA: https://reference.wolfram.com/language/ref/ConjugateTranspose.html)
      -
      'ConjugateTranspose[$m$]' +
      'ConjugateTranspose'[$m$]
      gives the conjugate transpose of $m$.
      @@ -419,7 +411,7 @@ class LeviCivitaTensor(Builtin): (:WMA link:https://reference.wolfram.com/language/ref/LeviCivitaTensor.html)
      -
      'LeviCivitaTensor[$d$]' +
      'LeviCivitaTensor'[$d$]
      gives the $d$-dimensional Levi-Civita totally antisymmetric tensor.
      diff --git a/mathics/builtin/testing_expressions/equality_inequality.py b/mathics/builtin/testing_expressions/equality_inequality.py index 86a253f5c..4c6c15f61 100644 --- a/mathics/builtin/testing_expressions/equality_inequality.py +++ b/mathics/builtin/testing_expressions/equality_inequality.py @@ -348,9 +348,9 @@ class Between(Builtin):
      'Between'[$x$, {$min$, $max$}]
      equivalent to $min$ <= $x$ <= $max$. -
      'Between[$x$, { {$min1$, $max1$}, {$min2$, $max2$}, ...]' -
      equivalent to $min1$ <= $x$ <= $max1$ || $min2$ <= $x$ <= $max2$ ... -
      'Between[$range$]' +
      'Between'[$x$, { {$min_1$, $max_1$}, {$min_2$, $max_2$}, ...] +
      equivalent to $min_1$ <= $x$ <= $max_1$ || $min_2$ <= $x$ <= $max_2$ ... +
      'Between'[$range$]
      operator form that yields 'Between'[$x$, $range$] when applied to expression $x$.
      @@ -391,7 +391,7 @@ class BooleanQ(Builtin): https://reference.wolfram.com/language/ref/BooleanQ.html
      -
      'BooleanQ[$expr$]' +
      'BooleanQ'[$expr$]
      returns 'True' if $expr$ is either 'True' or 'False'.
      @@ -421,7 +421,7 @@ class Equal(_EqualityOperator, _SympyComparison): https://reference.wolfram.com/language/ref/Equal.html
      -
      'Equal[$x$, $y$]' +
      'Equal'[$x$, $y$]
      '$x$ == $y$'
      is 'True' if $x$ and $y$ are known to be equal, or 'False' if $x$ and $y$ are known to be unequal, in which case @@ -557,7 +557,7 @@ class Greater(_ComparisonOperator, _SympyComparison): :WMA link:https://reference.wolfram.com/language/ref/Greater.html
      -
      'Greater[$x$, $y$]' or '$x$ > $y$' +
      'Greater'[$x$, $y$] or '$x$ > $y$'
      yields 'True' if $x$ is known to be greater than $y$.
      @@ -584,7 +584,7 @@ class GreaterEqual(_ComparisonOperator, _SympyComparison): https://reference.wolfram.com/language/ref/GreaterEqual.html
      -
      'GreaterEqual[$x$, $y$]' +
      'GreaterEqual'[$x$, $y$]
      $x$ \u2265 $y$ or '$x$ >= $y$'
      yields 'True' if $x$ is known to be greater than or equal to $y$. @@ -652,7 +652,7 @@ class Less(_ComparisonOperator, _SympyComparison): :WMA link:https://reference.wolfram.com/language/ref/Less.html
      -
      'Less[$x$, $y$]' or $x$ < $y$ +
      'Less'[$x$, $y$] or $x$ < $y$
      yields 'True' if $x$ is known to be less than $y$.
      @@ -677,7 +677,7 @@ class LessEqual(_ComparisonOperator, _SympyComparison): :WMA link:https://reference.wolfram.com/language/ref/LessEqual.html
      -
      'LessEqual[$x$, $y$, ...]' or $x$ <= $y$ or $x$ \u2264 $y$ +
      'LessEqual'[$x$, $y$, ...] or $x$ <= $y$ or $x$ \u2264 $y$
      yields 'True' if $x$ is known to be less than or equal to $y$.
      @@ -699,7 +699,7 @@ class Max(_MinMax): :WMA link:https://reference.wolfram.com/language/ref/Max.html
      -
      'Max[$e_1$, $e_2$, ..., $e_i$]' +
      'Max'[$e_1$, $e_2$, ..., $e_i$]
      returns the expression with the greatest value among the $e_i$.
      @@ -736,7 +736,7 @@ class Min(_MinMax): :WMA link:https://reference.wolfram.com/language/ref/Min.html
      -
      'Min[$e_1$, $e_2$, ..., $e_i$]' +
      'Min'[$e_1$, $e_2$, ..., $e_i$]
      returns the expression with the lowest value among the $e_i$.
      @@ -766,11 +766,11 @@ class Min(_MinMax): class SameQ(_ComparisonOperator): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/SameQ.html
      -
      'SameQ[$x$, $y$]' +
      'SameQ'[$x$, $y$]
      '$x$ === $y$'
      returns 'True' if $x$ and $y$ are structurally identical. \ Commutative properties apply, so if $x$ === $y$ then $y$ === $x$. @@ -781,7 +781,7 @@ class SameQ(_ComparisonOperator):
    • 'SameQ' requires exact correspondence between expressions, expect that \ it still considers 'Real' numbers equal if they differ in their last \ binary digit. -
    • $e1$ === $e2$ === $e3$ gives 'True' if all the $ei$'s are identical. +
    • $e_1$ === $e_2$ === $e_3$ gives 'True' if all the $ei$'s are identical.
    • 'SameQ[]' and 'SameQ[$expr$]' always yield 'True'.
    @@ -809,7 +809,7 @@ class SameQ(_ComparisonOperator): $0.222`3$ is not equivalent to $0.2222`3$: >> .2222222`6 === .222`3 = False - 15.9546 is the value of '$MaxPrecision' + 15.9546 is the value of '\$MaxPrecision' """ grouping = "None" # Indeterminate grouping: Neither left nor right @@ -834,7 +834,7 @@ class TrueQ(Builtin): :WMA link:https://reference.wolfram.com/language/ref/TrueQ.html
    -
    'TrueQ[$expr$]' +
    'TrueQ'[$expr$]
    returns 'True' if and only if $expr$ is 'True'.
    @@ -861,7 +861,7 @@ class Unequal(_EqualityOperator, _SympyComparison): https://reference.wolfram.com/language/ref/Unequal.html
    -
    'Unequal[$x$, $y$]' or $x$ != $y$ or $x$ \u2260 $y$ +
    'Unequal'[$x$, $y$] or $x$ != $y$ or $x$ \u2260 $y$
    is 'False' if $x$ and $y$ are known to be equal, or 'True' if $x$ \ and $y$ are known to be unequal. @@ -919,7 +919,7 @@ class UnsameQ(_ComparisonOperator): :WMA link:https://reference.wolfram.com/language/ref/UnsameQ.html
    -
    'UnsameQ[$x$, $y$]' +
    'UnsameQ'[$x$, $y$]
    '$x$ =!= $y$'
    returns 'True' if $x$ and $y$ are not structurally identical. Commutative properties apply, so if $x$ =!= $y$, then $y$ =!= $x$. diff --git a/mathics/builtin/testing_expressions/expression_tests.py b/mathics/builtin/testing_expressions/expression_tests.py index 5b32b386b..2f52597ab 100644 --- a/mathics/builtin/testing_expressions/expression_tests.py +++ b/mathics/builtin/testing_expressions/expression_tests.py @@ -15,7 +15,7 @@ class ListQ(Test): https://reference.wolfram.com/language/ref/ListQ.html
    -
    'ListQ[$expr$]' +
    'ListQ'[$expr$]
    tests whether $expr$ is a 'List'.
    @@ -40,7 +40,7 @@ class MatchQ(Builtin): https://reference.wolfram.com/language/ref/MatchQ.html
    -
    'MatchQ[$expr$, $form$]' +
    'MatchQ'[$expr$, $form$]
    tests whether $expr$ matches $form$.
    @@ -53,6 +53,10 @@ class MatchQ(Builtin): >> MatchQ[3, Pattern[3]] : First element in pattern Pattern[3] is not a valid pattern name. = False + + See also + :'Cases': + /doc/reference-of-built-in-symbols/list-functions/elements-of-lists/cases/. """ rules = {"MatchQ[form_][expr_]": "MatchQ[expr, form]"} @@ -75,7 +79,7 @@ class Order(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Order.html
    -
    'Order[$x$, $y$]' +
    'Order'[$x$, $y$]
    returns a number indicating the canonical ordering of $x$ and $y$. \ 1 indicates that $x$ is before $y$, and -1 that $y$ is before $x$. \ 0 indicates that there is no specific ordering. Uses the same order \ @@ -114,7 +118,7 @@ class OrderedQ(Builtin): https://reference.wolfram.com/language/ref/OrderedQ.html
    -
    'OrderedQ[{$a$, $b$}]' +
    'OrderedQ'[{$a$, $b$}]
    is 'True' if $a$ sorts before $b$ according to canonical ordering.
    @@ -142,7 +146,7 @@ def eval(self, expr, evaluation: Evaluation): class PatternsOrderedQ(Builtin): """
    -
    'PatternsOrderedQ[$patt1$, $patt2$]' +
    'PatternsOrderedQ'[$patt1$, $patt2$]
    returns 'True' if pattern $patt1$ would be applied before $patt2$ according to canonical pattern ordering.
    diff --git a/mathics/builtin/testing_expressions/list_oriented.py b/mathics/builtin/testing_expressions/list_oriented.py index f7619b4d0..dc9eb2faf 100644 --- a/mathics/builtin/testing_expressions/list_oriented.py +++ b/mathics/builtin/testing_expressions/list_oriented.py @@ -22,13 +22,13 @@ class ArrayQ(Builtin): https://reference.wolfram.com/language/ref/ArrayQ.html
    -
    'ArrayQ[$expr$]' +
    'ArrayQ'[$expr$]
    tests whether $expr$ is a full array. -
    'ArrayQ[$expr$, $pattern$]' +
    'ArrayQ'[$expr$, $pattern$]
    also tests whether the array depth of $expr$ matches $pattern$. -
    'ArrayQ[$expr$, $pattern$, $test$]' +
    'ArrayQ'[$expr$, $pattern$, $test$]
    furthermore tests whether $test$ yields 'True' for all elements of $expr$. 'ArrayQ[$expr$]' is equivalent to 'ArrayQ[$expr$, _, True&]'.
    @@ -73,7 +73,7 @@ class DisjointQ(Test): https://reference.wolfram.com/language/ref/DisjointQ.html
    -
    'DisjointQ[$a$, $b$]' +
    'DisjointQ'[$a$, $b$]
    gives True if $a$ and $b$ are disjoint, or False if $a$ and \ $b$ have any common elements.
    @@ -90,9 +90,9 @@ class IntersectingQ(Builtin): https://reference.wolfram.com/language/ref/IntersectingQ.html
    -
    'IntersectingQ[$a$, $b$]' -
    gives True if there are any common elements in $a and $b, or \ - False if $a and $b are disjoint. +
    'IntersectingQ'[$a$, $b$] +
    gives True if there are any common elements in $a$ and $b$, or \ + False if $a$ and $b$ are disjoint.
    """ @@ -103,7 +103,7 @@ class IntersectingQ(Builtin): class LevelQ(Test): """
    -
    'LevelQ[$expr$]' +
    'LevelQ'[$expr$]
    tests whether $expr$ is a valid level specification. This function \ is primarily used in function patterns for specifying type of a \ parameter. @@ -158,10 +158,10 @@ class MatrixQ(Builtin): https://reference.wolfram.com/language/ref/MatrixQ.html
    -
    'MatrixQ[$m$]' +
    'MatrixQ'[$m$]
    gives 'True' if $m$ is a list of equal-length lists. -
    'MatrixQ[$m$, $f$]' +
    'MatrixQ'[$m$, $f$]
    gives 'True' only if '$f$[$x$]' returns 'True' for when applied to \ element $x$ of the matrix $m$.
    @@ -199,7 +199,7 @@ class MemberQ(Builtin): https://reference.wolfram.com/language/ref/MemberQ.html
    -
    'MemberQ[$list$, $pattern$]' +
    'MemberQ'[$list$, $pattern$]
    returns 'True' if $pattern$ matches any element of $list$, or 'False' otherwise.
    @@ -223,7 +223,7 @@ class MemberQ(Builtin): class NotListQ(Test): """
    -
    'NotListQ[$expr$]' +
    'NotListQ'[$expr$]
    returns 'True' if $expr$ is not a list. This function is primarily \ used in function patterns for specifying type of a parameter.
    @@ -263,8 +263,8 @@ class SubsetQ(Builtin): https://reference.wolfram.com/language/ref/SubsetQ.html
    -
    'SubsetQ[$list1$, $list2$]' -
    returns True if $list2$ is a subset of $list1$, and False otherwise. +
    'SubsetQ'[$list_1$, $list_2$] +
    returns True if $list_2$ is a subset of $list_1$, and False otherwise.
    >> SubsetQ[{1, 2, 3}, {3, 1}] @@ -330,10 +330,10 @@ class VectorQ(Builtin): https://reference.wolfram.com/language/ref/VectorQ.html
    -
    'VectorQ[$v$]' +
    'VectorQ'[$v$]
    returns 'True' if $v$ is a list of elements which are not themselves lists. -
    'VectorQ[$v$, $f$]' +
    'VectorQ'[$v$, $f$]
    returns 'True' if $v$ is a vector and '$f$[$x$]' returns 'True' for each element $x$ of $v$.
    diff --git a/mathics/builtin/testing_expressions/logic.py b/mathics/builtin/testing_expressions/logic.py index 0ddc0b6b2..4273aa44c 100644 --- a/mathics/builtin/testing_expressions/logic.py +++ b/mathics/builtin/testing_expressions/logic.py @@ -72,8 +72,8 @@ class And(InfixOperator): https://reference.wolfram.com/language/ref/And.html
    -
    'And[$expr1$, $expr2$, ...]' -
    '$expr1$ && $expr2$ && ...' +
    'And'[$expr_1$, $expr_2$, ...] +
    '$expr_1$ && $expr_2$ && ...'
    evaluates each expression in turn, returning 'False' \ as soon as an expression evaluates to 'False'. If all \ expressions evaluate to 'True', 'And' returns 'True'. @@ -123,15 +123,15 @@ class AnyTrue(_ManyTrue): https://reference.wolfram.com/language/ref/AnyTrue.html
    -
    'AnyTrue[{$expr1$, $expr2$, ...}, $test$]' +
    'AnyTrue'[{$expr_1$, $expr_2$, ...}, $test$]
    returns True if any application of $test$ to \ - $expr1$, $expr2$, ... evaluates to True. + $expr_1$, $expr_2$, ... evaluates to True. -
    'AnyTrue[$list$, $test$, $level$]' +
    'AnyTrue'[$list$, $test$, $level$]
    returns True if any application of $test$ to items of \ $list$ at $level$ evaluates to True. -
    'AnyTrue[$test$]' +
    'AnyTrue'[$test$]
    gives an operator that may be applied to expressions.
    @@ -157,11 +157,11 @@ class AllTrue(_ManyTrue): :WMA link:https://reference.wolfram.com/language/ref/AllTrue.html
    -
    'AllTrue[{$expr1$, $expr2$, ...}, $test$]' -
    returns True if all applications of $test$ to $expr1$, $expr2$, ... evaluate to True. -
    'AllTrue[$list$, $test$, $level$]' +
    'AllTrue'[{$expr_1$, $expr_2$, ...}, $test$] +
    returns True if all applications of $test$ to $expr_1$, $expr_2$, ... evaluate to True. +
    'AllTrue'[$list$, $test$, $level$]
    returns True if all applications of $test$ to items of $list$ at $level$ evaluate to True. -
    'AllTrue[$test$]' +
    'AllTrue'[$test$]
    gives an operator that may be applied to expressions.
    @@ -189,11 +189,11 @@ class Equivalent(InfixOperator): https://reference.wolfram.com/language/ref/Equivalent.html
    -
    'Equivalent[$expr1$, $expr2$, ...]' -
    $expr1$ \u29E6 $expr2$ \u29E6 ... +
    'Equivalent'[$expr_1$, $expr_2$, ...] +
    $expr_1$ \u29E6 $expr_2$ \u29E6 ...
    is equivalent to - ($expr1$ && $expr2$ && ...) || (!$expr1$ && !$expr2$ && ...) + ($expr_1$ && $expr_2$ && ...) || (!$expr_1$ && !$expr_2$ && ...)
    >> Equivalent[True, True, False] @@ -256,8 +256,8 @@ class Implies(InfixOperator): :WMA link:https://reference.wolfram.com/language/ref/Implies.html
    -
    'Implies[$expr1$, $expr2$]' -
    $expr1$ \u21D2 $expr2$ +
    'Implies'[$expr_1$, $expr_2$] +
    $expr_1$ \u21D2 $expr_2$
    evaluates each expression in turn, returning 'True' \ as soon as the first expression evaluates to 'False'. If the \ first expression evaluates to 'True', 'Implies' returns the \ @@ -297,15 +297,15 @@ class NoneTrue(_ManyTrue): https://reference.wolfram.com/language/ref/NoneTrue.html
    -
    'NoneTrue[{$expr1$, $expr2$, ...}, $test$]' -
    returns True if no application of $test$ to $expr1$, $expr2$, ... \ +
    'NoneTrue'[{$expr_1$, $expr_2$, ...}, $test$] +
    returns True if no application of $test$ to $expr_1$, $expr_2$, ... \ evaluates to True. -
    'NoneTrue[$list$, $test$, $level$]' +
    'NoneTrue'[$list$, $test$, $level$]
    returns True if no application of $test$ to items of $list$ at \ $level$ evaluates to True. -
    'NoneTrue[$test$]' +
    'NoneTrue'[$test$]
    gives an operator that may be applied to expressions.
    @@ -331,8 +331,8 @@ class Or(InfixOperator): :WMA link:https://reference.wolfram.com/language/ref/Or.html
    -
    'Or[$expr1$, $expr2$, ...]' -
    '$expr1$ || $expr2$ || ...' +
    'Or'[$expr_1$, $expr_2$, ...] +
    '$expr_1$ || $expr_2$ || ...'
    evaluates each expression in turn, returning 'True' as soon as an expression evaluates to 'True'. If all expressions evaluate to 'False', 'Or' returns 'False'. @@ -381,10 +381,10 @@ class Nand(InfixOperator): https://reference.wolfram.com/language/ref/Nand.html
    -
    'Nand[$expr1$, $expr2$, ...]' +
    'Nand'[$expr_1$, $expr_2$, ...] -
    $expr1$ \u22BC $expr2$ \u22BC ... -
    Implements the logical NAND function. The same as 'Not[And['$expr1$, $expr2$, ...']]' +
    $expr_1$ \u22BC $expr_2$ \u22BC ... +
    Implements the logical NAND function. The same as 'Not[And['$expr_1$, $expr_2$, ...']]'
    >> Nand[True, False] @@ -402,10 +402,10 @@ class Nor(InfixOperator): :WMA link:https://reference.wolfram.com/language/ref/Nor.html
    -
    'Nor[$expr1$, $expr2$, ...]' +
    'Nor'[$expr_1$, $expr_2$, ...] -
    $expr1$ \u22BD $expr2$ \u22BD ... -
    Implements the logical NOR function. The same as 'Not[Or['$expr1$, $expr2$, ...']]' +
    $expr_1$ \u22BD $expr_2$ \u22BD ... +
    Implements the logical NOR function. The same as 'Not[Or['$expr_1$, $expr_2$, ...']]'
    >> Nor[True, False] @@ -423,7 +423,7 @@ class Not(PrefixOperator): :WMA link:https://reference.wolfram.com/language/ref/Not.html
    -
    'Not[$expr$]' +
    'Not'[$expr$]
    '!$expr$'
    negates the logical expression $expr$.
    @@ -437,7 +437,7 @@ class Not(PrefixOperator): """ # FIXME: If we remove this we pick up unicode unconditionally - # which wew don't want to do. + # which we don't want to do. operator = "!" rules = { @@ -468,8 +468,8 @@ class Xor(InfixOperator): :WMA link:https://reference.wolfram.com/language/ref/Xor.html
    -
    'Xor[$expr1$, $expr2$, ...]' -
    $expr1$ \u22BB $expr2$ \u22BB ... +
    'Xor'[$expr_1$, $expr_2$, ...] +
    $expr_1$ \u22BB $expr_2$ \u22BB ...
    evaluates each expression in turn, returning 'True' as soon as not all expressions evaluate to the same value. If all diff --git a/mathics/builtin/testing_expressions/numerical_properties.py b/mathics/builtin/testing_expressions/numerical_properties.py index 84a275744..0cb3fd8a7 100644 --- a/mathics/builtin/testing_expressions/numerical_properties.py +++ b/mathics/builtin/testing_expressions/numerical_properties.py @@ -24,7 +24,7 @@ class CoprimeQ(Builtin): https://reference.wolfram.com/language/ref/CoprimeQ.html
    -
    'CoprimeQ[$x$, $y$]' +
    'CoprimeQ'[$x$, $y$]
    tests whether $x$ and $y$ are coprime by computing their greatest \ common divisor.
    @@ -68,7 +68,7 @@ def eval(self, args, evaluation: Evaluation): if not all(isinstance(i, int) or isinstance(i, complex) for i in py_args): return SymbolFalse - if all(sympy.gcd(n, m) == 1 for (n, m) in combinations(py_args, 2)): + if all(sympy.gcd(n, m) == 1 for n, m in combinations(py_args, 2)): return SymbolTrue else: return SymbolFalse @@ -81,7 +81,7 @@ class EvenQ(Test): https://reference.wolfram.com/language/ref/EvenQ.html
    -
    'EvenQ[$x$]' +
    'EvenQ'[$x$]
    returns 'True' if $x$ is even, and 'False' otherwise.
    @@ -107,7 +107,7 @@ class ExactNumberQ(Test): https://reference.wolfram.com/language/ref/ExactNumberQ.html
    -
    'ExactNumberQ[$expr$]' +
    'ExactNumberQ'[$expr$]
    returns 'True' if $expr$ is an exact real or complex number, and returns 'False' otherwise.
    @@ -159,7 +159,7 @@ class InexactNumberQ(Test): https://reference.wolfram.com/language/ref/InexactNumberQ.html
    -
    'InexactNumberQ[$expr$]' +
    'InexactNumberQ'[$expr$]
    returns 'True' if $expr$ is not an exact real or complex number number, and 'False' otherwise.
    @@ -195,7 +195,7 @@ class IntegerQ(Test): https://reference.wolfram.com/language/ref/IntegerQ.html
    -
    'IntegerQ[$expr$]' +
    'IntegerQ'[$expr$]
    returns 'True' if $expr$ is an integer, and 'False' otherwise.
    @@ -218,7 +218,7 @@ class MachineNumberQ(Test): https://reference.wolfram.com/language/ref/MachineNumberQ.html
    -
    'MachineNumberQ[$expr$]' +
    'MachineNumberQ'[$expr$]
    returns 'True' if $expr$ is a machine-precision real or complex number.
    @@ -242,7 +242,7 @@ class Negative(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Negative.html
    -
    'Negative[$x$]' +
    'Negative'[$x$]
    returns 'True' if $x$ is a negative real number.
    @@ -271,7 +271,7 @@ class NonNegative(Builtin): :WMA link:https://reference.wolfram.com/language/ref/NonNegative.html
    -
    'NonNegative[$x$]' +
    'NonNegative'[$x$]
    returns 'True' if $x$ is a positive real number or zero.
    @@ -292,7 +292,7 @@ class NonPositive(Builtin): :WMA link:https://reference.wolfram.com/language/ref/NonPositive.html
    -
    'NonPositive[$x$]' +
    'NonPositive'[$x$]
    returns 'True' if $x$ is a negative real number or zero.
    @@ -315,7 +315,7 @@ class NumberQ(Test): https://reference.wolfram.com/language/ref/NumberQ.html
    -
    'NumberQ[$expr$]' +
    'NumberQ'[$expr$]
    returns 'True' if $expr$ is an explicit number, and 'False' \ otherwise.
    @@ -340,7 +340,7 @@ class NumericQ(Builtin): https://reference.wolfram.com/language/ref/NumericQ.html
    -
    'NumericQ[$expr$]' +
    'NumericQ'[$expr$]
    tests whether $expr$ represents a numeric quantity.
    @@ -392,7 +392,7 @@ class OddQ(Test): https://reference.wolfram.com/language/ref/OddQ.html
    -
    'OddQ[$x$]' +
    'OddQ'[$x$]
    returns 'True' if $x$ is odd, and 'False' otherwise.
    @@ -417,7 +417,7 @@ class PossibleZeroQ(SympyFunction): https://reference.wolfram.com/language/ref/PossibleZeroQ.html
    -
    'PossibleZeroQ[$expr$]' +
    'PossibleZeroQ'[$expr$]
    returns 'True' if basic symbolic and numerical methods suggest that \ expr has value zero, and 'False' otherwise.
    @@ -493,7 +493,7 @@ class Positive(Builtin): https://reference.wolfram.com/language/ref/Positive.html
    -
    'Positive[$x$]' +
    'Positive'[$x$]
    returns 'True' if $x$ is a positive real number.
    @@ -522,7 +522,7 @@ class PrimeQ(SympyFunction): https://reference.wolfram.com/language/ref/PrimeQ.html
    -
    'PrimeQ[$n$]' +
    'PrimeQ'[$n$]
    returns 'True' if $n$ is a prime number.
    diff --git a/mathics/builtin/testing_expressions/string_tests.py b/mathics/builtin/testing_expressions/string_tests.py index f3a810ab7..aee037356 100644 --- a/mathics/builtin/testing_expressions/string_tests.py +++ b/mathics/builtin/testing_expressions/string_tests.py @@ -4,7 +4,8 @@ import re -from mathics_scanner import SingleLineFeeder, TranslateError +from mathics_scanner import SingleLineFeeder, SyntaxError +from mathics_scanner.location import ContainerKind from mathics.builtin.atomic.strings import anchor_pattern from mathics.core.atoms import Integer1, String @@ -13,7 +14,7 @@ from mathics.core.convert.regex import to_regex from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression -from mathics.core.parser.util import parse +from mathics.core.parser.util import parser from mathics.core.symbols import Symbol, SymbolFalse, SymbolTrue from mathics.core.systemsymbols import SymbolStringExpression, SymbolStringMatchQ from mathics.eval.strings import eval_StringContainsQ @@ -26,7 +27,7 @@ class DigitQ(Builtin): https://reference.wolfram.com/language/ref/DigitQ.html
    -
    'DigitQ[$string$]' +
    'DigitQ'[$string$]
    yields 'True' if all the characters in the $string$ are \ digits, and yields 'False' otherwise. @@ -61,7 +62,7 @@ class LetterQ(Builtin): https://reference.wolfram.com/language/ref/LetterQ.html
    -
    'LetterQ[$string$]' +
    'LetterQ'[$string$]
    yields 'True' if all the characters in the $string$ are \ letters, and yields 'False' otherwise.
    @@ -93,7 +94,7 @@ class StringFreeQ(Builtin): https://reference.wolfram.com/language/ref/StringFreeQ.html
    -
    'StringFreeQ["$string$", $patt$]' +
    'StringFreeQ'["$string$", $patt$]
    returns True if no substring in $string$ matches the string \ expression $patt$, and returns False otherwise. @@ -152,7 +153,7 @@ class StringMatchQ(Builtin): https://reference.wolfram.com/language/ref/StringMatchQ.html
    -
    'StringMatchQ["string", $pattern$]' +
    'StringMatchQ'["string", $pattern$]
    checks is "string" matches $pattern$
    @@ -224,7 +225,7 @@ class StringQ(Test): :WMA link: https://reference.wolfram.com/language/ref/StringQ.html
    -
    'StringQ[$expr$]' +
    'StringQ'[$expr$]
    returns 'True' if $expr$ is a 'String', or 'False' otherwise.
    @@ -278,10 +279,10 @@ def eval(self, string, evaluation: Evaluation): ) return - feeder = SingleLineFeeder(string.value) + feeder = SingleLineFeeder(string.value, "", ContainerKind.STRING) try: - parse(evaluation.definitions, feeder) - except TranslateError: + parser.parse(feeder) + except SyntaxError: return SymbolFalse else: return SymbolTrue diff --git a/mathics/builtin/trace.py b/mathics/builtin/trace.py index 3529ead48..f8b3954a3 100644 --- a/mathics/builtin/trace.py +++ b/mathics/builtin/trace.py @@ -22,16 +22,24 @@ from time import time from typing import Callable +import mathics_scanner.location + import mathics.eval.tracing from mathics.core.attributes import A_HOLD_ALL, A_HOLD_ALL_COMPLETE, A_PROTECTED -from mathics.core.builtin import Builtin +from mathics.core.builtin import Builtin, Predefined from mathics.core.convert.python import from_bool, from_python from mathics.core.definitions import Definitions from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression from mathics.core.list import ListExpression from mathics.core.rules import FunctionApplyRule -from mathics.core.symbols import SymbolFalse, SymbolNull, SymbolTrue, strip_context +from mathics.core.symbols import ( + Symbol, + SymbolFalse, + SymbolNull, + SymbolTrue, + strip_context, +) def traced_apply_function( @@ -101,7 +109,7 @@ def eval(self, evaluation: Evaluation): class PrintTrace(_TraceBase): - """ + r""" ## :trace native symbol:
    @@ -120,7 +128,7 @@ class PrintTrace(_TraceBase): Note that in a browser the information only appears in a console. - Note: before '$TraceBuiltins' is set to 'True', 'PrintTrace[]' will print an empty + Note: before '\$TraceBuiltins' is set to 'True', 'PrintTrace[]' will print an empty list. >> PrintTrace[] (* See console log *) @@ -151,7 +159,7 @@ class TraceBuiltins(_TraceBase): ## :trace native symbol:
    -
    'TraceBuiltins[$expr$]' +
    'TraceBuiltins'[$expr$]
    Evaluate $expr$ and then print a list of the Built-in Functions called \ in evaluating $expr$ along with the number of times is each called, \ and combined elapsed time in milliseconds spent in each. @@ -277,11 +285,11 @@ def eval(self, expr, evaluation, options={}): # The convention is to use the name of the variable without the "$" as # the class name, but it is already taken by the builtin `TraceBuiltins` class TraceBuiltinsVariable(Builtin): - """ + r""" ## :trace native symbol:
    -
    '$TraceBuiltins' +
    '\$TraceBuiltins'
    A Boolean Built-in variable when True collects function evaluation statistics.
    @@ -310,7 +318,7 @@ class TraceBuiltinsVariable(Builtin): To clear statistics collected use 'ClearTrace[]': X> ClearTrace[] - '$TraceBuiltins' cannot be set to a non-boolean value. + '\$TraceBuiltins' cannot be set to a non-boolean value. >> $TraceBuiltins = x : x should be True or False. = x @@ -349,7 +357,7 @@ class TraceEvaluation(Builtin): ## :trace native symbol:
    -
    'TraceEvaluation[$expr$]' +
    'TraceEvaluation'[$expr$]
    Evaluate $expr$ and print each step of the evaluation.
    @@ -404,11 +412,11 @@ def eval(self, expr, evaluation: Evaluation, options: dict): class TraceEvaluationVariable(Builtin): - """ + r""" ## :trace native symbol:
    -
    '$TraceEvaluation' +
    '\$TraceEvaluation'
    A Boolean variable which when set True traces Expression evaluation calls and returns.
    @@ -429,7 +437,7 @@ class TraceEvaluationVariable(Builtin): >> a + a = 2 a - '$TraceEvaluation' cannot be set to a non-boolean value. + '\$TraceEvaluation' cannot be set to a non-boolean value. >> $TraceEvaluation = x : x should be True or False. = x @@ -464,7 +472,7 @@ class PythonCProfileEvaluation(Builtin): :Python:https://docs.python.org/3/library/profile.html
    -
    'PythonProfileEvaluation[$expr$]' +
    'PythonProfileEvaluation'[$expr$]
    profile $expr$ with the Python's cProfiler.
    @@ -493,3 +501,33 @@ def eval(self, expr: Expression, evaluation: Evaluation): else: result = expr.evaluate(evaluation) return ListExpression(result, profile_result) + + +class TrackLocations(Predefined): + r"""## :TrackLocations native symbol: + +
    +
    '$TrackLocations' +
    specifies whether we should track \ + source-text location information during evaluation. This \ + can be helpful in debugging when there is a failure. +
    + """ + + name = "$TrackLocations" + messages = {"bool": "`1` should be True or False."} + + summary_text = "track source-text locations in evaluation" + + def evaluate(self, evaluation: Evaluation) -> Symbol: + print(mathics_scanner.location.MATHICS3_PATHS) + return from_bool(mathics_scanner.location.TRACK_LOCATIONS) + + def eval_set(self, value, evaluation): + """Set[$TrackLocations, value_]""" + if value is SymbolTrue or value is SymbolFalse: + evaluation.definitions.set_ownvalue("System`$TrackLocations", value) + mathics.core.parser.parser.TRACK_LOCATIONS = value.to_python() + else: + evaluation.message("$TrackLocations", "bool", value) + return value diff --git a/mathics/builtin/vectors/constructing.py b/mathics/builtin/vectors/constructing.py index 551617bbf..7510cb83c 100644 --- a/mathics/builtin/vectors/constructing.py +++ b/mathics/builtin/vectors/constructing.py @@ -12,21 +12,21 @@ class AngleVector(Builtin): - """ + r""" :WMA link:https://reference.wolfram.com/language/ref/AngleVector.html
    -
    'AngleVector[$phi$]' -
    returns the point at angle $phi$ on the unit circle. +
    'AngleVector'[$\phi$] +
    returns the point at angle $\phi$ on the unit circle. -
    'AngleVector[{$r$, $phi$}]' -
    returns the point at angle $phi$ on a circle of radius $r$. +
    'AngleVector'[{$r$, $\phi$}] +
    returns the point at angle $\phi$ on a circle of radius $r$. -
    'AngleVector[{$x$, $y$}, $phi$]' -
    returns the point at angle $phi$ on a circle of radius 1 centered at {$x$, $y$}. +
    'AngleVector'[{$x$, $y$}, $\phi$] +
    returns the point at angle $\phi$ on a circle of radius 1 centered at {$x$, $y$}. -
    'AngleVector[{$x$, $y$}, {$r$, $phi$}]' -
    returns point at angle $phi$ on a circle of radius $r$ centered at {$x$, $y$}. +
    'AngleVector'[{$x$, $y$}, {$r$, $\phi$}] +
    returns point at angle $\phi$ on a circle of radius $r$ centered at {$x$, $y$}.
    >> AngleVector[90 Degree] diff --git a/mathics/builtin/vectors/math_ops.py b/mathics/builtin/vectors/math_ops.py index 19f373740..07fdf121c 100644 --- a/mathics/builtin/vectors/math_ops.py +++ b/mathics/builtin/vectors/math_ops.py @@ -23,7 +23,7 @@ class Cross(Builtin): https://reference.wolfram.com/language/ref/Cross.html)
    -
    'Cross[$a$, $b$]' +
    'Cross'[$a$, $b$]
    computes the vector cross product of $a$ and $b$.
    @@ -91,11 +91,11 @@ class Curl(SympyFunction): :WMA: https://reference.wolfram.com/language/ref/Curl.html)
    -
    'Curl[{$f1$, $f2$}, {$x1$, $x2$}]' -
    returns the curl $df2$/$dx1$ - $df1$/$dx2$ +
    'Curl'[{$f_1$, $f_2$}, {$x_1$, $x_2$}] +
    returns the curl $df_2$/$dx_1$ - $df_1$/$dx_2$ -
    'Curl[{$f1$, $f2$, $f3} {$x1$, $x2$, $x3}]' -
    returns the curl ($df3$/$dx2$ - $df2$/$dx3$, $dx3$/$df$3 - $df3$/$dx1$, $df2$/$df1$ - $df1$/$dx2$) +
    'Curl'[{$f_1$, $f_2$, $f_3$} {$x_1$, $x_2$, $x_3$}] +
    returns the curl ($df_3$/$dx_2$ - $df_2$/$dx_3$, $dx_3$/$df_3$ - $df_3$/$dx_1$, $df_2$/$df_1$ - $df_1$/$dx_2$)
    Two-dimensional 'Curl': @@ -138,10 +138,10 @@ class Norm(Builtin): https://reference.wolfram.com/language/ref/Norm.html)
    -
    'Norm[$m$, $p$]' +
    'Norm'[$m$, $p$]
    computes the p-norm of matrix m. -
    'Norm[$m$]' +
    'Norm'[$m$]
    computes the 2-norm of matrix m.
    diff --git a/mathics/builtin/vectors/vector_space_operations.py b/mathics/builtin/vectors/vector_space_operations.py index 776ad5f08..05c53d71e 100644 --- a/mathics/builtin/vectors/vector_space_operations.py +++ b/mathics/builtin/vectors/vector_space_operations.py @@ -31,8 +31,8 @@ class KroneckerProduct(SympyFunction): https://reference.wolfram.com/language/ref/KroneckerProduct.html)
    -
    'KroneckerProduct[$m1$, $m2$, ...]' -
    returns the Kronecker product of the arrays $mi$ +
    'KroneckerProduct'[$m_1$, $m_2$, ...] +
    returns the Kronecker product of the arrays $m_i$
    Show symbolically how the Kronecker product works on two two-dimensional arrays: @@ -72,10 +72,10 @@ class Normalize(Builtin): :WMA link:https://reference.wolfram.com/language/ref/KroneckerProduct.html
    -
    'Normalize[$v$]' +
    'Normalize'[$v$]
    calculates the normalized vector $v$. -
    'Normalize[$z$]' +
    'Normalize'[$z$]
    calculates the normalized complex number $z$.
    @@ -96,7 +96,7 @@ class Projection(Builtin): :WMA link:https://reference.wolfram.com/language/ref/Projection.html
    -
    'Projection[$u$, $v$]' +
    'Projection'[$u$, $v$]
    gives the projection of the vector $u$ onto $v$
    @@ -161,10 +161,10 @@ class UnitVector(Builtin): https://reference.wolfram.com/language/ref/UnitVector.html)
    -
    'UnitVector[$n$, $k$]' +
    'UnitVector'[$n$, $k$]
    returns the $n$-dimensional unit vector with a 1 in position $k$. -
    'UnitVector[$k$]' +
    'UnitVector'[$k$]
    is equivalent to 'UnitVector[2, $k$]'.
    @@ -208,7 +208,7 @@ class VectorAngle(Builtin): :WMA link:https://reference.wolfram.com/language/ref/VectorAngle.html
    -
    'VectorAngle[$u$, $v$]' +
    'VectorAngle'[$u$, $v$]
    gives the angles between vectors $u$ and $v$
    diff --git a/mathics/core/assignment.py b/mathics/core/assignment.py index 9b3974871..e02a8ad99 100644 --- a/mathics/core/assignment.py +++ b/mathics/core/assignment.py @@ -176,11 +176,13 @@ def is_protected(tag: str, definitions: Definitions) -> bool: def normalize_lhs(lhs, evaluation): """ - Process the lhs in a way that + Process the lhs in a way that: + * if it is a conditional expression, reduce it to a shallow conditional expression ( Conditional[Conditional[...],tst] -> Conditional[stripped_lhs, tst]) with `stripped_lhs` the result of strip all the conditions from lhs. + * if ``stripped_lhs`` is not a ``List`` or a ``Part`` expression, evaluate the elements. diff --git a/mathics/core/atoms.py b/mathics/core/atoms.py index d6e542a60..a5cadae53 100644 --- a/mathics/core/atoms.py +++ b/mathics/core/atoms.py @@ -8,6 +8,7 @@ import mpmath import sympy +from sympy.core import numbers as sympy_numbers from mathics.core.element import BoxElementMixin, ImmutableValueMixin from mathics.core.number import ( @@ -63,9 +64,21 @@ def __getnewargs__(self): """ return (self._value,) + def __eq__(self, other): + if isinstance(other, Number): + return self.get_sort_key() == other.get_sort_key() + else: + return False + def __str__(self) -> str: return str(self.value) + def default_format(self, evaluation, form) -> str: + return str(self.value) + + def do_copy(self) -> "Number": + raise NotImplementedError + # FIXME: can we refactor or subclass objects to remove pattern_sort? def get_sort_key(self, pattern_sort=False) -> tuple: """ @@ -96,7 +109,7 @@ def is_numeric(self, evaluation=None) -> bool: def to_mpmath(self, precision: Optional[int] = None) -> mpmath.ctx_mp_python.mpf: """ - Convert self._value to an mpmath number with precision ``precision`` + Convert self.value to an mpmath number with precision ``precision`` If ``precision`` is None, use mpmath's default precision. A mpmath number is the default implementation for Number. @@ -109,21 +122,15 @@ def to_mpmath(self, precision: Optional[int] = None) -> mpmath.ctx_mp_python.mpf return mpmath.mpf(self.value) return mpmath.mpf(self.value) - @property - def value(self) -> T: + def to_python(self, *_, **kwargs): + """Returns a native builtin Python object + something in (int, float, complex, str, tuple, list or dict.). + (See discussions in + https://github.com/Mathics3/mathics-core/discussions/550 + and + https://github.com/Mathics3/mathics-core/pull/551 """ - Returns this number's value. - """ - return self._value - - def __eq__(self, other): - if isinstance(other, Number): - return self.get_sort_key() == other.get_sort_key() - else: - return False - - def default_format(self, evaluation, form) -> str: - return str(self.value) + return self.value def round(self, d: Optional[int] = None) -> "Number": """ @@ -131,8 +138,13 @@ def round(self, d: Optional[int] = None) -> "Number": """ return self - def do_copy(self) -> "Number": - raise NotImplementedError + @property + def value(self) -> T: + """Equivalent value in either SymPy's or Python's native + datatype if that exist. Note the SymPy value + and the Python value might be the same thing. + """ + return self._value def _ExponentFunction(value): @@ -185,6 +197,8 @@ class Integer(Number[int]): # dictionary's value is the corresponding Mathics Integer object. _integers: Dict[Any, "Integer"] = {} + _sympy: sympy_numbers.Integer + # We use __new__ here to ensure that two Integer's that have the same value # return the same object, and to set an object hash value. # Consider also @lru_cache, and mechanisms for limiting and @@ -199,6 +213,7 @@ def __new__(cls, value) -> "Integer": # Cache object so we don't allocate again. self._integers[value] = self + self._sympy = sympy_numbers.Integer(value) # Set a value for self.__hash__() once so that every time # it is used this is fast. Note that in contrast to the @@ -256,12 +271,24 @@ def __ne__(self, other) -> bool: else super().__ne__(other) ) + def __neg__(self) -> "Integer": + return Integer(-self._value) + def abs(self) -> "Integer": return -self if self < Integer0 else self def atom_to_boxes(self, f, evaluation): return self.make_boxes(f.get_name()) + def get_int_value(self) -> int: + return self._value + + @property + def is_zero(self) -> bool: + # Note: 0 is self._value or the other way around is a syntax + # error. + return self._value == 0 + def make_boxes(self, form) -> "String": from mathics.eval.makeboxes import _boxed_string @@ -281,12 +308,6 @@ def make_boxes(self, form) -> "String": return int_to_string_shorter_repr(self._value, form) - def to_sympy(self, **kwargs): - return sympy.Integer(self._value) - - def to_python(self, *args, **kwargs): - return self.value - def round(self, d: Optional[int] = None) -> Union["MachineReal", "PrecisionReal"]: """ Produce a Real approximation of ``self`` with decimal precision ``d``. @@ -302,12 +323,16 @@ def round(self, d: Optional[int] = None) -> Union["MachineReal", "PrecisionReal" d = MACHINE_PRECISION_VALUE return PrecisionReal(sympy.Float(self.value, d)) - def get_int_value(self) -> int: - return self._value + @property + def sympy(self) -> sympy_numbers.Integer: + return self._sympy + + def to_sympy(self, **_) -> sympy_numbers.Integer: + return self.sympy - def sameQ(self, other) -> bool: + def sameQ(self, rhs) -> bool: """Mathics SameQ""" - return isinstance(other, Integer) and self._value == other.value + return isinstance(rhs, Integer) and self._value == rhs.value def do_copy(self) -> "Integer": return Integer(self._value) @@ -315,15 +340,6 @@ def do_copy(self) -> "Integer": def user_hash(self, update): update(b"System`Integer>" + str(self._value).encode("utf8")) - def __neg__(self) -> "Integer": - return Integer(-self._value) - - @property - def is_zero(self) -> bool: - # Note: 0 is self._value or the other way around is a syntax - # error. - return self._value == 0 - Integer0 = Integer(0) Integer1 = Integer(1) @@ -485,25 +501,25 @@ def make_boxes(self, form): def is_zero(self) -> bool: return self.value == 0.0 - def sameQ(self, other) -> bool: + def sameQ(self, rhs) -> bool: """Mathics SameQ for MachineReal. - If the other comparison value is a MachineReal, the values - have to be equal. If the other value is a PrecisionReal though, then + If the rhs comparison value is a MachineReal, the values + have to be equal. If the rhs value is a PrecisionReal though, then the two values have to be within 1/2 ** (precision) of - other-value's precision. For any other type, sameQ is False. + rhs-value's precision. For any rhs type, sameQ is False. """ - if isinstance(other, MachineReal): - return self.value == other.value - if isinstance(other, PrecisionReal): - other_value = other.value + if isinstance(rhs, MachineReal): + return self.value == rhs.value + if isinstance(rhs, PrecisionReal): + rhs_value = rhs.value value = self.to_sympy() # If sympy fixes the issue, this comparison would be # enough - if (value - other_value).is_zero: + if (value - rhs_value).is_zero: return True # this handles the issue... - diff = abs(value - other_value) - prec = min(value._prec, other_value._prec) + diff = abs(value - rhs_value) + prec = min(value._prec, rhs_value._prec) return diff < 0.5 ** (prec) else: return False @@ -532,13 +548,14 @@ class PrecisionReal(Real[sympy.Float]): # The key is the PrecisionReal's sympy.Float, and the # dictionary's value is the corresponding Mathics PrecisionReal object. _precision_reals: Dict[Any, "PrecisionReal"] = {} + _sympy: Number def __new__(cls, value) -> "PrecisionReal": n = sympy.Float(value) self = cls._precision_reals.get(n) if self is None: self = Number.__new__(cls) - self._value = n + self._sympy = self._value = n # Cache object so we don't allocate again. self._precision_reals[n] = self @@ -586,12 +603,12 @@ def round(self, d: Optional[int] = None) -> Union[MachineReal, "PrecisionReal"]: _prec = min(prec(d), self.value._prec) return PrecisionReal(sympy.Float(self.value, precision=_prec)) - def sameQ(self, other) -> bool: + def sameQ(self, rhs) -> bool: """Mathics SameQ for PrecisionReal""" - if isinstance(other, PrecisionReal): - other_value = other.value - elif isinstance(other, MachineReal): - other_value = other.to_sympy() + if isinstance(rhs, PrecisionReal): + other_value = rhs.value + elif isinstance(rhs, MachineReal): + other_value = rhs.to_sympy() else: return False value = self.value @@ -672,11 +689,11 @@ def is_literal(self) -> bool: """ return True - def sameQ(self, other) -> bool: + def sameQ(self, rhs) -> bool: """Mathics SameQ""" # FIX: check - if isinstance(other, ByteArrayAtom): - return self.value == other.value + if isinstance(rhs, ByteArrayAtom): + return self.value == rhs.value return False def get_string_value(self) -> Optional[str]: @@ -732,6 +749,10 @@ def __new__(cls, real, imag): f"Argument 'image' must be an Integer, Real, or Rational type; is {imag}." ) + # Note: for the below test, imag.value == 0 catches more + # reals. In particular, MachineReals that have an imaginary + # value of floating point 0.0. But MachineReal 0.0 is "approximate 0", + # not exactly 0. So "Complex[0., 0.]" is "0. + 0." and not "0." if imag.sameQ(Integer0): return real @@ -811,12 +832,10 @@ def get_sort_key(self, pattern_sort=False) -> tuple: else: return (0, 0, self.real.get_sort_key()[2], self.imag.get_sort_key()[2], 1) - def sameQ(self, other) -> bool: + def sameQ(self, rhs) -> bool: """Mathics SameQ""" return ( - isinstance(other, Complex) - and self.real == other.real - and self.imag == other.imag + isinstance(rhs, Complex) and self.real == rhs.real and self.imag == rhs.imag ) def round(self, d=None) -> "Complex": @@ -940,9 +959,9 @@ def round(self, d=None) -> Union["MachineReal", "PrecisionReal"]: else: return PrecisionReal(self.value.n(d)) - def sameQ(self, other) -> bool: + def sameQ(self, rhs) -> bool: """Mathics SameQ""" - return isinstance(other, Rational) and self.value == other.value + return isinstance(rhs, Rational) and self.value == rhs.value def numerator(self) -> "Integer": return Integer(self.value.as_numer_denom()[0]) @@ -1048,9 +1067,9 @@ def is_literal(self) -> bool: """ return True - def sameQ(self, other) -> bool: + def sameQ(self, rhs) -> bool: """Mathics SameQ""" - return isinstance(other, String) and self.value == other.value + return isinstance(rhs, String) and self.value == rhs.value def to_expression(self): return self diff --git a/mathics/core/builtin.py b/mathics/core/builtin.py index 269300b2d..bab2913d8 100644 --- a/mathics/core/builtin.py +++ b/mathics/core/builtin.py @@ -118,9 +118,9 @@ def __init__(self, name, count, expected): class Builtin: """ - A base class for a Built-in function symbols, like List, or - variables, like $SystemID, and Built-in Objects, like - DateTimeObject. + A base class for a Built-in function symbols, like ``List``, or + variables, like ``$SystemID``, and Built-in Objects, like + ``DateTimeObject``. Some of the class variables of the Builtin object are used to create a definition object for that built-in symbol. In particular, @@ -136,11 +136,11 @@ class Builtin: For example: - ``` + .. code-block:: python + def eval(x, evaluation): "F[x_Real]" return Expression(Symbol("G"), x*2) - ``` adds a ``FunctionApplyRule`` to the symbol's definition object that implements ``F[x_]->G[x*2]``. @@ -305,18 +305,6 @@ def contribute(self, definitions: Definitions, is_pymodule=False): system=True, ) ) - for pattern, function in self.get_functions(is_pymodule=is_pymodule): - pat_attr = attributes if pattern.get_head_name() == name else None - rules.append( - FunctionApplyRule( - name, - pattern, - function, - check_options, - attributes=pat_attr, - system=True, - ) - ) for pattern_str, replace_str in self.rules.items(): pattern_str = pattern_str % {"name": name} pattern = parse_builtin_rule(pattern_str, definition_class) @@ -468,6 +456,8 @@ def get_functions(self, prefix="eval", is_pymodule=False): for name in dir(self): if name.startswith(prefix): function = getattr(self, name) + if not hasattr(function, "__call__"): + continue pattern = function.__doc__ if pattern is None: # Fixes PyPy bug continue @@ -494,7 +484,15 @@ def get_functions(self, prefix="eval", is_pymodule=False): definition_class = ( PyMathicsDefinitions() if is_pymodule else SystemDefinitions() ) - pattern = parse_builtin_rule(pattern, definition_class) + + # Passing the function parameter is in a way + # redundant, because creating FunctionApplyRule has + # access to the function and sets the postion this + # way. But revised afte the dust has settled and + # we have a very good idea of what is desirable and useful. + pattern = parse_builtin_rule( + pattern, definition_class, location=function + ) if unavailable_function: function = unavailable_function if attrs: @@ -583,20 +581,23 @@ def __init__(self, *args, **kwargs): self.sympy_name = strip_context(self.get_name()).lower() self.mathics_to_sympy[self.__class__.__name__] = self.sympy_name - def is_constant(self) -> bool: - return False - def get_sympy_names(self) -> List[str]: if self.sympy_name: return [self.sympy_name] return [] - def to_sympy(self, expr=None, **kwargs): - raise NotImplementedError + def is_constant(self) -> bool: + """Returns true if the value of evaluation of this object can + never change. + """ + return False def from_sympy(self, elements: Tuple[BaseElement, ...]) -> Expression: raise NotImplementedError + def to_sympy(self, expr=None, **kwargs): + raise NotImplementedError + # This has to come before MPMathFunction class SympyFunction(SympyObject): @@ -1289,7 +1290,7 @@ class NoMeaningInfixOperator(InfixOperator): https://reference.wolfram.com/language/ref/{operator_name}.html
    -
    '{operator_name}[$x$, $y$, ...]' +
    '{operator_name}['$x$, $y$, ...']'
    displays $x$ {operator_string} $y$ {operator_string} ...
    @@ -1389,7 +1390,7 @@ class NoMeaningPostfixOperator(PostfixOperator): https://reference.wolfram.com/language/ref/{operator_name}.html
    -
    '{operator_name}[$x$]' +
    '{operator_name}['$x$']'
    displays $x$ {operator_string}
    @@ -1431,7 +1432,7 @@ class NoMeaningPrefixOperator(PrefixOperator): https://reference.wolfram.com/language/ref/{operator_name}.html
    -
    '{operator_name}[$x$]' +
    '{operator_name}['$x$']'
    displays {operator_string} $x$
    diff --git a/mathics/core/convert/expression.py b/mathics/core/convert/expression.py index b8acc4e31..60784bfea 100644 --- a/mathics/core/convert/expression.py +++ b/mathics/core/convert/expression.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from typing import Any, Callable, Type, Union +from typing import Any, Callable, Union from mathics.core.convert.python import from_python from mathics.core.element import BaseElement @@ -52,7 +52,7 @@ def to_expression( def to_expression_with_specialization( head: BaseElement, *elements: Any, - elements_conversion_fn: Callable = from_python, + _: Callable = from_python, ) -> Union[ListExpression, Expression]: """ This expression constructor will figure out what the right kind of @@ -69,16 +69,21 @@ def to_mathics_list( elements_conversion_fn: Callable = from_python, ) -> ListExpression: """ - This is an expression constructor for list that can be used when the elements are not Mathics - objects. For example: - to_mathics_list(1, 2, 3) - to_mathics_list(1, 2, 3, elements_conversion_fn=Integer) + This is an expression constructor for list that can be used when + the elements are not Mathics objects. + + For example:: + + to_mathics_list(1, 2, 3) + to_mathics_list(1, 2, 3, elements_conversion_fn=Integer) """ - elements_tuple, elements_properties, _ = convert_expression_elements( + elements_tuple, elements_properties, literal_values = convert_expression_elements( elements, elements_conversion_fn ) list_expression = ListExpression( - *elements_tuple, elements_properties=elements_properties + *elements_tuple, + elements_properties=elements_properties, + literal_values=literal_values, ) return list_expression @@ -99,5 +104,5 @@ def to_numeric_args(mathics_args: BaseElement, evaluation) -> tuple: expression_constructor_map = { - SymbolList: lambda head, *args, **kwargs: ListExpression(*args, **kwargs) + SymbolList: lambda _, *args, **kwargs: ListExpression(*args, **kwargs) } diff --git a/mathics/core/convert/regex.py b/mathics/core/convert/regex.py index 7af3145a6..0e468961e 100644 --- a/mathics/core/convert/regex.py +++ b/mathics/core/convert/regex.py @@ -156,7 +156,7 @@ def recurse(x: Expression, quantifiers=q) -> Optional[str]: return REGEXP_FOR_SYMBOLS.get(expr) if expr.has_form("CharacterRange", 2): - (start, stop) = (element.get_string_value() for element in expr.elements) + start, stop = (element.get_string_value() for element in expr.elements) if all(x is not None and len(x) == 1 for x in (start, stop)): return f"[{re.escape(start)}-{re.escape(stop)}]" diff --git a/mathics/core/convert/sympy.py b/mathics/core/convert/sympy.py index 59994ff3c..89a36ff73 100644 --- a/mathics/core/convert/sympy.py +++ b/mathics/core/convert/sympy.py @@ -129,7 +129,7 @@ def to_sympy_matrix(data, **kwargs) -> Optional[sympy.MutableDenseMatrix]: return None -class SympyExpression(BasicSympy): +class SympyExpression(sympy.Expr): """A Sympy expression with an associated Mathics expression""" is_Function = True diff --git a/mathics/core/definitions.py b/mathics/core/definitions.py index 0109ea421..fbe01b36a 100644 --- a/mathics/core/definitions.py +++ b/mathics/core/definitions.py @@ -18,7 +18,6 @@ from mathics.core.attributes import A_NO_ATTRIBUTES from mathics.core.convert.expression import to_mathics_list from mathics.core.element import BaseElement, fully_qualified_symbol_name -from mathics.core.load_builtin import definition_contribute, mathics3_builtins_modules from mathics.core.rules import BaseRule, Rule from mathics.core.symbols import Atom, Symbol, strip_context from mathics.core.util import canonic_filename @@ -413,7 +412,7 @@ def lookup_name(self, name: str) -> str: return ctx_name return with_context - def get_package_names(self) -> List[str]: + def get_package_names(self) -> List[Optional[str]]: """Return the list of names of the packages loaded in the system.""" try: packages = self.get_ownvalue("System`$Packages") @@ -421,7 +420,11 @@ def get_package_names(self) -> List[str]: return [] assert packages.has_form("System`List", None) - return [c.get_string_value() for c in packages.get_elements()] + return [ + c.get_string_value() + for c in packages.get_elements() + if c.get_string_value() is not None + ] # return sorted({name.split("`")[0] for name in self.get_names()}) def shorten_name(self, name_with_ctx: str) -> str: @@ -1066,6 +1069,10 @@ def load_builtin_definitions( """ Load definitions from Builtin classes, autoload files and extension modules. """ + from mathics.core.load_builtin import ( + definition_contribute, + mathics3_builtins_modules, + ) from mathics.eval.files_io.files import get_file_time from mathics.eval.pymathics import PyMathicsLoadException, load_pymathics_module from mathics.session import autoload_files diff --git a/mathics/core/element.py b/mathics/core/element.py index 1b4971bb3..9054dc5c1 100644 --- a/mathics/core/element.py +++ b/mathics/core/element.py @@ -359,7 +359,7 @@ def get_sequence(self) -> Sequence["BaseElement"]: else: return tuple([self]) - def get_string_value(self): + def get_string_value(self) -> Optional[str]: return None @property @@ -431,13 +431,13 @@ def user_hash(self, update) -> None: raise NotImplementedError def to_python(self, *args, **kwargs): - # Returns a native builtin Python object - # something in (int, float, complex, str, tuple, list or dict.). - # (See discussions in - # https://github.com/Mathics3/mathics-core/discussions/550 - # and - # https://github.com/Mathics3/mathics-core/pull/551 - # + """Returns a native builtin Python object + something in (int, float, complex, str, tuple, list or dict.). + (See discussions in + https://github.com/Mathics3/mathics-core/discussions/550 + and + https://github.com/Mathics3/mathics-core/pull/551 + """ raise NotImplementedError def to_mpmath(self): diff --git a/mathics/core/evaluation.py b/mathics/core/evaluation.py index 52fde33d3..e6d686fe7 100644 --- a/mathics/core/evaluation.py +++ b/mathics/core/evaluation.py @@ -6,7 +6,7 @@ from abc import ABC from typing import Any, Callable, Dict, List, Optional, Tuple, Union, overload -from mathics_scanner import TranslateError +from mathics_scanner.errors import SyntaxError from mathics import settings from mathics.core.atoms import Integer, String @@ -161,16 +161,20 @@ def parse_feeder_returning_code_and_messages(self, feeder) -> tuple: Parse a single expression from feeder, print the messages it produces and return the result, the source code for this and evaluated messages created in evaluation. + + If there was a SyntaxError, the source code returned is "" and the result is None. """ from mathics.core.parser.util import parse_returning_code try: result, source_code = parse_returning_code(self.definitions, feeder) - except TranslateError: + except SyntaxError: + result = None + source_code = "" + + if result is None: self.recursion_depth = 0 self.stopped = False - source_code = "" - result = None messages = feeder.send_messages(self) return result, source_code, messages @@ -541,16 +545,17 @@ def publish(self, tag: str, *args, **kwargs) -> None: class Message(_Out): def __init__(self, symbol: Union[Symbol, str], tag: str, text: str) -> None: """ - A Mathics3 message of some sort. symbol_or_string can either be a symbol or a - string. + A Mathics3 message of some sort. ``symbol`` can either + be a symbol or a string. + + ``symbol``: classifies which predefined or variable this comes + from? If there is none use a string. - Symbol: classifies which predefined or variable this comes from? If there is none - use a string. - tag: a short slug string that indicates the kind of message + ``tag``: a short slug string that indicates the kind of message In Django we need to use a string for symbol, since we need - something that is JSON serializable and a Mathics3 Symbol is not - like this. + something that is JSON serializable and a Mathics3 Symbol is + not like this. """ super(Message, self).__init__() self.is_message = True # Why do we need this? @@ -625,8 +630,10 @@ class Result: In particular, there are the following fields: result: the actual result produced. - out: a list of additional output strings. These are warning or error messages. See "form" - for exactly what they are. + + out: a list of additional output strings. These are warning or + error messages. See "form" for exactly what they are. + form: is the *format* of the result which tags the kind of result . Think of this as something like a mime/type. Some formats: diff --git a/mathics/core/expression.py b/mathics/core/expression.py index 80de31c6a..97f6bc4aa 100644 --- a/mathics/core/expression.py +++ b/mathics/core/expression.py @@ -4,6 +4,7 @@ import math from bisect import bisect_left from itertools import chain +from types import MethodType from typing import ( Any, Callable, @@ -18,6 +19,7 @@ ) import sympy +from mathics_scanner.location import SourceRange, SourceRange2 from mathics.core.atoms import Integer1, String from mathics.core.attributes import ( @@ -127,8 +129,6 @@ def eval_SameQ(self, other): # The next element in the tree. Maybe should be an iterator? def next_elem(): nonlocal len_elements - nonlocal parents - nonlocal pos while pos and pos[-1] == len_elements: pos.pop() @@ -256,14 +256,15 @@ class Expression(BaseElement, NumericOperators, EvalMixin): function. positional Arguments: - - head -- The head of the M-Expression - - *elements - optional: the remaining elements - - *literal_values - optional: if this is not None, then all elements - are (Python) literal values and literal_values - contains these literals. + + - ``head`` -- The head of the M-Expression + - ``*elements`` - optional: the remaining elements + - ``*literal_values`` - optional: if this is not ``None``, then all elements + are (Python) literal values and ``literal_values`` contains these literals. Keyword Arguments: - - elements_properties -- properties of the collection of elements + + - ``elements_properties`` -- properties of the collection of elements """ @@ -274,6 +275,7 @@ class Expression(BaseElement, NumericOperators, EvalMixin): elements_properties: Optional[ElementsProperties] options: Optional[Dict[str, Any]] pattern_sequence: bool + location: Optional[Union[SourceRange, SourceRange2, MethodType]] def __init__( self, @@ -299,6 +301,7 @@ def __init__( self._sequences = None self._cache = None + self.location = None # self.copy creates this self.original: Optional[Expression] = None @@ -352,9 +355,7 @@ def _build_elements_properties(self): values = [] for element in self._elements: # Test for the literalness, and the three properties mentioned above - if element.is_literal: - values.append(element.value) - else: + if not element.is_literal: self.elements_properties.elements_fully_evaluated = False if isinstance(element, Expression): @@ -662,35 +663,43 @@ def flatten_with_respect_to_head( self, head: Symbol, pattern_only=False, callback=None, level=100 ) -> "Expression": """ - Flatten elements in self which have `head` in them. + Flatten elements in ``self`` which have ``head`` in them. The idea is that in an expression like: Expression(Plus, 1, Expression(Plus, 2, 3), 4) - when "Plus" is specified as the head, this expression should get changed to: + when "Plus" is specified as the head, this expression should + get changed to:: Expression(Plus, 1, 2, 3, 4) - In other words, all of the Plus operands are collected to together into one operation. - This is more efficiently evaluated. Note that we only flatten Plus functions, not other functions, - whether or not they contain Plus. + In other words, all of the ``Plus`` operands are collected to + together into one operation. This is more efficiently + evaluated. Note that we only flatten ``Plus`` functions, not other + functions, whether or not they contain ``Plus``. + + So in:: - So in: Expression(Plus, Times(1, 2, Plus(3, 4))) the expression is unchanged. - head: head element to be consider flattening on. Only expressions with this will be flattened. - This is always the head element or the next head element of the expression that the - elements are drawn from + ``head``: head element to be consider flattening on. Only + expressions with this will be flattened. This is always + the head element or the next head element of the + expression that the elements are drawn from + ``callback``: a callback function called each time a element + is flattened. - callback: a callback function called each time a element is flattened. - level: maximum depth to flatten. This often isn't used and seems to have been put in - as a potential safety measure possibly for the future. If you don't want a limit - on flattening pass a negative number. - pattern_only: if True, just apply to elements that are pattern_sequence (see ExpressionPattern.get_wrappings) + ``level``: maximum depth to flatten. This often isn't used and + seems to have been put in as a potential safety + measure possibly for the future. If you don't want a + limit on flattening pass a negative number. + + ``pattern_only``: if ``True``, just apply to elements that are + pattern_sequence (see ``ExpressionPattern.get_wrappings``) """ from mathics.core.convert.expression import to_expression_with_specialization @@ -1018,7 +1027,7 @@ def is_literal(self) -> bool: `is_uncertain_final_definitions()` we don't need a `definitions` parameter. """ - # Right now we are pessimisitic. We might consider changing this for + # Right now we are pessimistic. We might consider changing this for # Lists. Lists definitions can't be changed right? return False # If we have a List we may do something like: @@ -1112,7 +1121,7 @@ def has_symbol(self, symbol_name: str) -> bool: ) def restructure(self, head, elements, evaluation, structure_cache=None, deps=None): - """Faster equivalent of: Expression(head, *elements) + """Faster equivalent of: ``Expression(head, *elements)`` The caller guarantees that _all_ elements are either from self.elements (or its subtrees) or from one of the expression given @@ -1125,6 +1134,9 @@ def restructure(self, head, elements, evaluation, structure_cache=None, deps=Non if deps is None: deps = self + if structure_cache is None: + structure_cache = {} + # FIXME: look over s = structure(head, deps, evaluation, structure_cache=structure_cache) return s(list(elements)) @@ -1171,17 +1183,17 @@ def rewrite_apply_eval_step(self, evaluation) -> Tuple[BaseElement, bool]: self._build_elements_properties() assert self.elements_properties is not None + recompute_properties = False + # @timeit def eval_elements(): - nonlocal recompute_properties - # @timeit def eval_range(indices): nonlocal recompute_properties recompute_properties = False for index in indices: element = elements[index] - if not element.has_form("Unevaluated", 1): + if not (element.is_literal or element.has_form("Unevaluated", 1)): if isinstance(element, EvalMixin): new_value = element.evaluate(evaluation) # We need id() because != by itself is too permissive @@ -1197,7 +1209,7 @@ def rest_range(indices): return for index in indices: element = elements[index] - if element.has_form("Evaluate", 1): + if not element.is_literal and element.has_form("Evaluate", 1): if isinstance(element, EvalMixin): new_value = element.evaluate(evaluation) # We need id() because != by itself is too permissive @@ -1223,7 +1235,6 @@ def rest_range(indices): # * evaluate elements, # * run to_python() on them in Expression construction, or # * convert Expression elements from a tuple to a list and back - recompute_properties = False elements: Sequence[BaseElement] if self.elements_properties.elements_fully_evaluated: elements = self._elements @@ -1240,6 +1251,9 @@ def rest_range(indices): head, *elements, elements_properties=self.elements_properties ) + if hasattr(self, "location") and self.location is not None: + new.location = self.location + # Step 3: Now, process the attributes of head # If there are sequence, flatten them if the attributes allow it. if ( @@ -1535,7 +1549,7 @@ def slice(self, head, py_slice, evaluation): def to_mpmath(self): return None - def to_python(self, *args, **kwargs): + def to_python(self, *args, **kwargs) -> Any: """ Convert the Expression to a Python object: List[...] -> Python list @@ -1551,6 +1565,13 @@ def to_python(self, *args, **kwargs): """ from mathics.core.builtin import mathics_to_python + # When self.value of is None, it might mean either it is + # not set or it is legitamately the None value. + # If self.value is legitimately None, we'll + # catch further down. + if hasattr(self, "value") and self.value is not None: + return self.value + n_evaluation = kwargs.get("n_evaluation", None) assert n_evaluation is None @@ -1645,10 +1666,12 @@ def sort(self, pattern=False): def do_apply_rules(self, rules, evaluation, level=0, options=None): """ - for rule in rules: - result = rule.apply(self, evaluation, fully=False) - if result is not None: - return result + .. code-block:: python + + for rule in rules: + result = rule.apply(self, evaluation, fully=False) + if result is not None: + return result """ from mathics.core.convert.expression import to_expression_with_specialization @@ -1913,7 +1936,7 @@ def _is_neutral_head(head, cache, evaluation): return _is_neutral_symbol(head.get_name(), cache, evaluation) -def structure(head, origins, evaluation, structure_cache=None): +def structure(head, origins, evaluation, structure_cache={}): """ Creates a Structure for building Expressions with head "head" and elements originating (exclusively) from "origins" (elements are passed into the functions @@ -1931,22 +1954,20 @@ def structure(head, origins, evaluation, structure_cache=None): if isinstance(origins, (Expression, Structure)): cache = origins._cache - if cache is not None and not _is_neutral_head( - head, structure_cache, evaluation - ): - cache = None + if cache and not _is_neutral_head(head, structure_cache, evaluation): + cache = {} elif isinstance(origins, (list, tuple)): if _is_neutral_head(head, structure_cache, evaluation): cache = ExpressionCache.union(origins, evaluation) else: - cache = None + cache = {} else: raise ValueError("expected Expression, Structure, tuple or list as orig param") - if cache is None: - return UnlinkedStructure(head) - else: + if cache: return LinkedStructure(head, cache) + else: + return UnlinkedStructure(head) def atom_list_constructor(evaluation, head, *atom_names): diff --git a/mathics/core/list.py b/mathics/core/list.py index 496779189..f6f411bd6 100644 --- a/mathics/core/list.py +++ b/mathics/core/list.py @@ -4,7 +4,7 @@ """ import reprlib -from typing import Optional, Tuple +from typing import Any, Optional, Tuple from mathics.core.element import ElementsProperties from mathics.core.evaluation import Evaluation @@ -19,14 +19,17 @@ class ListExpression(Expression): A Mathics3 List is a specialization of Expression where the head is SymbolList. positional Arguments: - - *elements - optional: the remaining elements + + - ``*elements`` - optional: the remaining elements Keyword Arguments: - - elements_properties -- properties of the collection of elements - - literal_values -- if this is not None, then it is a tuple of Python values + + - ``elements_properties`` -- properties of the collection of elements + - ``literal_values`` -- if this is not ``None``, then it is a tuple of Python values and the expression is a literal. """ _is_literal: bool + _sympy: Optional[Any] def __init__( self, @@ -37,6 +40,7 @@ def __init__( self.options = None self.pattern_sequence = False self._head = SymbolList + self._sympy = None # For debugging: @@ -47,16 +51,16 @@ def __init__( # call_frame = inspect.getouterframes(curframe, 2) # print("caller name:", call_frame[1][3]) - # from mathics.core.element import BaseElement - # for element in elements: - # if not isinstance(element, BaseElement): - # from trepan.api import debug; debug() - self._elements = elements - self.value = literal_values + + # When self.value is not None it a Python tuple (not Python + # list) sort that is the Python equivalent value for the Mathics3 list. # Check for literalness if it is not known - if literal_values is None: + if literal_values is not None: + self._is_literal = True + self.value = literal_values + else: self._is_literal = True values = [] for element in elements: diff --git a/mathics/core/load_builtin.py b/mathics/core/load_builtin.py index 89121915e..5170d1a12 100644 --- a/mathics/core/load_builtin.py +++ b/mathics/core/load_builtin.py @@ -237,7 +237,7 @@ def import_and_load_builtins(): def import_builtin_module(import_name: str, modules: List[ModuleType]): """ - Imports ``the list of Mathics3 Built-in modules so that inside + Imports the list of Mathics3 Built-in modules so that inside Mathics3 Builtin Functions, like Plus[], List[] are defined. List ``module_names`` is updated. diff --git a/mathics/core/parser/README.md b/mathics/core/parser/README.md index 2128fda69..d9bf7035e 100644 --- a/mathics/core/parser/README.md +++ b/mathics/core/parser/README.md @@ -90,8 +90,8 @@ def parse_binary(self, expr1, token, expr1_precedence: int) -> Node: # handle nonassoc operators if tag in nonassoc_binary_ops and expr1.get_head_name() == tag and not expr1.parenthesised: - self.tokeniser.sntx_message(token.pos) - raise InvalidSyntaxError() + tag, pre_error, post_error = self.tokeniser.sntx_message(token.pos) + raise InvalidSyntaxError(tag, pre_error, post_error) result = Node(tag, expr1, expr2) # construct the result: `BINARY[expr1, expr2]` diff --git a/mathics/core/parser/ast.py b/mathics/core/parser/ast.py index ca9c286ab..292302f50 100644 --- a/mathics/core/parser/ast.py +++ b/mathics/core/parser/ast.py @@ -23,7 +23,7 @@ class Node: expression's leaves and a non-leaf nodes. """ - def __init__(self, head, *children): + def __init__(self, head, *children, location=None): if isinstance(head, Node): self.head = head else: @@ -31,6 +31,7 @@ def __init__(self, head, *children): self.value = None self.children = list(children) self.parenthesised = False + self.location = location def get_head_name(self): if isinstance(self.head, Symbol): @@ -68,11 +69,12 @@ class Atom(Node): their own. You can however compare Atoms for equality. """ - def __init__(self, value): + def __init__(self, value, location=None): self.head = Symbol(self.__class__.__name__) self.value = value self.children = [] self.parenthesised = False + self.location = location def __repr__(self): return "%s[%s]" % (self.head, self.value) @@ -90,7 +92,13 @@ class Number(Atom): """ def __init__( - self, value: str, sign: int = 1, base: int = 10, suffix=None, exp: int = 0 + self, + value: str, + sign: int = 1, + base: int = 10, + suffix=None, + exp: int = 0, + location=None, ): assert isinstance(value, str) assert sign in (-1, 1) @@ -104,6 +112,7 @@ def __init__( self.base = base self.suffix = suffix self.exp = exp + self.location = location def __repr__(self): result = self.value @@ -132,10 +141,11 @@ class Symbol(Atom): are unique as they are say in Lisp, or Python. """ - def __init__(self, value: str, context: Optional[str] = "System"): + def __init__(self, value: str, context: Optional[str] = "System", location=None): self.context = context self.value = value self.children = [] + self.location = location # avoids recursive definition @property diff --git a/mathics/core/parser/convert.py b/mathics/core/parser/convert.py index 4a78e0623..20afce817 100644 --- a/mathics/core/parser/convert.py +++ b/mathics/core/parser/convert.py @@ -10,6 +10,7 @@ from mathics.core.atoms import Integer, MachineReal, PrecisionReal, Rational, String from mathics.core.convert.expression import to_expression, to_mathics_list +from mathics.core.element import BaseElement from mathics.core.number import RECONSTRUCT_MACHINE_PRECISION_DIGITS from mathics.core.parser.ast import ( Filename as AST_Filename, @@ -189,7 +190,7 @@ class Converter(GenericConverter): def __init__(self): self.definitions = None - def convert(self, node, definitions): + def convert(self, node, definitions) -> BaseElement: self.definitions = definitions result = self.do_convert(node) self.definitions = None diff --git a/mathics/core/parser/feed.py b/mathics/core/parser/feed.py index 0661def7d..66160b165 100644 --- a/mathics/core/parser/feed.py +++ b/mathics/core/parser/feed.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +from typing import List + from mathics_scanner import ( FileLineFeeder, LineFeeder, @@ -8,6 +10,8 @@ class MathicsLineFeeder(LineFeeder): + messages: List[str] + def send_messages(self, evaluation) -> list: evaluated_messages = [] for message in self.messages: @@ -17,7 +21,7 @@ def send_messages(self, evaluation) -> list: class MathicsSingleLineFeeder(SingleLineFeeder, MathicsLineFeeder): - "A feeder that feeds lines from an open ``File`` object" + "A feeder that feeds lines from an open location container object" class MathicsFileLineFeeder(FileLineFeeder, MathicsLineFeeder): @@ -25,4 +29,4 @@ class MathicsFileLineFeeder(FileLineFeeder, MathicsLineFeeder): class MathicsMultiLineFeeder(MultiLineFeeder, MathicsLineFeeder): - "A feeder that feeds lines from an open ``File`` object" + "A feeder that feeds lines from an open contianer object" diff --git a/mathics/core/parser/location.py b/mathics/core/parser/location.py new file mode 100644 index 000000000..a4c9275ff --- /dev/null +++ b/mathics/core/parser/location.py @@ -0,0 +1,116 @@ +""" +Provides location tracking in parser. +""" + +from typing import Callable, Optional + +import mathics_scanner +from mathics_scanner.location import ( + EVAL_METHODS, + ContainerKind, + SourceRange, + SourceRange2, +) + +from mathics.core.parser.ast import Node + + +def track_location(func: Callable) -> Callable: + """Python decorator for a parse method that adds location tracking + on non-leaf-nodes when TRACK_LOCATION is set. Otherwise, we just + run the parse method. + + """ + + def wrapper(self, *args) -> Optional[Node]: + if not mathics_scanner.location.TRACK_LOCATIONS: + return func(self, *args) + + # Save location information + # For expressions which make their way to + # FunctionApplyRule, saving a position here is + # extraneous because the FunctionApplyRule is + # the position. But deal with this redundancy + # after the dust settles, and we have experience + # on what is desired. + start_column = self.tokeniser.pos + start_line = self.feeder.lineno + parsed_node = func(self, *args) + + if parsed_node is not None and hasattr(parsed_node, "location"): + if self.feeder.container_kind == ContainerKind.PYTHON: + parsed_node.location = self.feeder.container + if self.feeder.container not in EVAL_METHODS: + EVAL_METHODS.add(parsed_node.location) + else: + end_pos = self.tokeniser.pos + end_line = self.feeder.lineno + if start_line == end_line: + parsed_node.location = SourceRange2( + start_line=start_line, + start_pos=start_column, + end_pos=end_pos, + container=self.feeder.container_index, + ) + else: + parsed_node.location = SourceRange( + start_line=start_line, + start_pos=start_column, + end_line=end_line, + end_pos=end_pos, + container=self.feeder.container_index, + ) + + return parsed_node + + return wrapper + + +def track_token_location(func: Callable) -> Callable: + """Python decorator for a parse method that adds location + tracking to leaf-nodes, i.e. tokens. This happens though only TRACK_LOCATION is set. Otherwise, we just run the + normal parse method. + + """ + + def wrapper(self, token) -> Optional[Node]: + if not mathics_scanner.location.TRACK_LOCATIONS: + return func(self, token) + + # Save location information + # For expressions which make their way to + # FunctionApplyRule, saving a position here is + # extraneous because the FunctionApplyRule is + # the position. But deal with this redundancy + # after the dust settles, and we have experience + # on what is desired. + start_column = token.pos + start_line = self.feeder.lineno + parsed_node = func(self, token) + + if ( + self.feeder.container_kind == ContainerKind.PYTHON + and self.feeder.container not in EVAL_METHODS + ): + location = self.feeder.container + EVAL_METHODS.add(location) + + end_line = self.feeder.lineno + if start_line == end_line: + parsed_node.location = SourceRange2( + start_line=start_line, + start_pos=start_column, + end_pos=start_column + len(token.text) - 1, + container=self.feeder.container_index, + ) + else: + parsed_node.location = SourceRange( + start_line=start_line, + start_pos=start_column, + end_line=self.feeder.lineno, + end_pos=start_column + len(token.text) - 1, + container=self.feeder.container_index, + ) + return parsed_node + + return wrapper diff --git a/mathics/core/parser/parser.py b/mathics/core/parser/parser.py index 6cc017e30..a53679f8f 100644 --- a/mathics/core/parser/parser.py +++ b/mathics/core/parser/parser.py @@ -10,7 +10,12 @@ import string from typing import Optional, Union -from mathics_scanner import InvalidSyntaxError, TranslateError +from mathics_scanner.errors import ( + EscapeSyntaxError, + InvalidSyntaxError, + NamedCharacterSyntaxError, + SyntaxError, +) from mathics_scanner.tokeniser import Token, Tokeniser, is_symbol_name from mathics.core.convert.op import builtin_constants @@ -25,6 +30,7 @@ String, Symbol, ) +from mathics.core.parser.location import track_location, track_token_location from mathics.core.parser.operators import ( all_operators, binary_operators, @@ -44,7 +50,7 @@ # FIXME: should rework so we don't have to do this # We have the character name ImaginaryI and ImaginaryJ, but we should # have the *operator* name, "I". -special_symbols["\uF74F"] = special_symbols["\uF74E"] = "I" +special_symbols["\uf74f"] = special_symbols["\uf74e"] = "I" # An operator precedence value that will ensure that whatever operator @@ -92,6 +98,7 @@ def __init__(self): "DifferentialD", ] ) + self.location = None def backtrack(self, pos): """ @@ -122,11 +129,11 @@ def expect(self, expected_tag: str): if token.tag == expected_tag: self.consume() else: - self.tokeniser.sntx_message(token.pos) - raise InvalidSyntaxError() + tag, pre_error, post_error = self.tokeniser.sntx_message(token.pos) + raise InvalidSyntaxError(tag, pre_error, post_error) - def incomplete(self, pos: int): - self.tokeniser.incomplete() + def get_more_input(self, pos: int): + self.tokeniser.get_more_input() self.backtrack(pos) @property @@ -148,7 +155,7 @@ def next_noend(self) -> Token: token = self.next() if token.tag != "END": return token - self.incomplete(token.pos) + self.get_more_input(token.pos) def parse(self, feeder) -> Optional[Node]: """ @@ -161,8 +168,10 @@ def parse(self, feeder) -> Optional[Node]: self.current_token = None self.bracket_depth = 0 self.box_depth = 0 + return self.parse_e() + @track_location def parse_e(self) -> Optional[Node]: """ Parse the single top-level or "start" expression. @@ -178,6 +187,7 @@ def parse_e(self) -> Optional[Node]: else: return None + @track_location def parse_binary_operator( self, expr1, token: Token, expr1_precedence: int ) -> Optional[Node]: @@ -225,8 +235,8 @@ def parse_binary_operator( and expr1.get_head_name() == tag and not expr1.parenthesised ): - self.tokeniser.sntx_message(token.pos) - raise InvalidSyntaxError() + tag, pre_error, post_error = self.tokeniser.sntx_message(token.pos) + raise InvalidSyntaxError(tag, pre_error, post_error) result = Node(tag, expr1, expr2) @@ -266,7 +276,7 @@ def parse_box_expr(self, precedence: int) -> Union[String, Node]: elif tag in ("OtherscriptBox", "RightRowBox"): break elif tag == "END": - self.incomplete(token.pos) + self.get_more_input(token.pos) elif result is None and tag != "END": self.consume() # TODO: handle non-box expressions inside RowBox @@ -349,6 +359,7 @@ def parse_box_operator( return result + @track_location def parse_comparison( self, expr1, token: Token, expr1_precedence: int ) -> Optional[Node]: @@ -404,6 +415,7 @@ def parse_comparison( expr1 = Node(tag, expr1, expr2).flatten() return expr1 + @track_location def parse_expr(self, precedence: int) -> Optional[Node]: """ Parse an expression returning an AST Node tree for this. @@ -446,10 +458,18 @@ def parse_expr(self, precedence: int) -> Optional[Node]: if self.is_inside_rowbox: break else: - self.tokeniser.sntx_message(token.pos) - raise InvalidSyntaxError() + tag, pre_error, post_error = self.tokeniser.sntx_message( + token.pos + ) + raise InvalidSyntaxError(tag, pre_error, post_error) else: - token = self.next() + try: + token = self.next() + except (NamedCharacterSyntaxError, EscapeSyntaxError) as escape_error: + self.tokeniser.feeder.message( + escape_error.name, escape_error.tag, *escape_error.args + ) + raise tag = token.tag method = getattr(self, "e_" + tag, None) @@ -489,6 +509,7 @@ def parse_expr(self, precedence: int) -> Optional[Node]: result = new_result return result + @track_location def parse_p(self): """Parse a "p_"-tagged expression. "p_" tags include prefix operators, left-bracketed expressions @@ -508,8 +529,8 @@ def parse_p(self): elif self.is_inside_rowbox: return None else: - self.tokeniser.sntx_message(token.pos) - raise InvalidSyntaxError() + tag, pre_error, post_error = self.tokeniser.sntx_message(token.pos) + raise InvalidSyntaxError(tag, pre_error, post_error) def parse_postfix( self, expr1, token: Token, expr1_precedence: int @@ -539,6 +560,7 @@ def parse_postfix( # Note: returning a list is different from how most other parse_ routines # work and it makes the type system more complicated. + @track_location def parse_seq(self) -> list: result: list = [] while True: @@ -700,7 +722,7 @@ def e_Alternatives(self, expr1, token: Token, p: int) -> Optional[Node]: expr2 = self.parse_expr(q + 1) return Node("Alternatives", expr1, expr2).flatten() - def e_ApplyList(self, expr1, token: Token, p: int) -> Optional[Node]: + def e_ApplyList(self, expr1, _: Token, p: int) -> Optional[Node]: operator_precedence = right_binary_operators["Apply"] if operator_precedence < p: return None @@ -709,7 +731,7 @@ def e_ApplyList(self, expr1, token: Token, p: int) -> Optional[Node]: expr3 = Node("List", Number1) return Node("Apply", expr1, expr2, expr3) - def e_Derivative(self, expr1, token: Token, p: int) -> Optional[Node]: + def e_Derivative(self, expr1, _: Token, p: int) -> Optional[Node]: q = postfix_operators["Derivative"] if q < p: return None @@ -720,7 +742,7 @@ def e_Derivative(self, expr1, token: Token, p: int) -> Optional[Node]: head = Node("Derivative", Number(str(n))) return Node(head, expr1) - def e_Divide(self, expr1, token: Token, expr1_precedence: int): + def e_Divide(self, expr1, _: Token, expr1_precedence: int): """ Implements parsing and transformation of Divide expr1 / expr2 @@ -755,7 +777,8 @@ def e_Divide(self, expr1, token: Token, expr1_precedence: int): expr2 = self.parse_expr(operator_precedence + 1) return Node("Times", expr1, Node("Power", expr2, NumberM1)).flatten() - def e_Infix(self, expr1, token: Token, expr1_precedence) -> Optional[Node]: + @track_location + def e_Infix(self, expr1, _: Token, expr1_precedence) -> Optional[Node]: """ Used to implement the rule: expr : expr1 '~' expr2 '~' expr3 @@ -805,12 +828,12 @@ def e_MessageName(self, expr1, token: Token, p: int) -> Node: elif token.tag == "String": element = self.p_String(token) else: - self.tokeniser.sntx_message(token.pos) - raise InvalidSyntaxError() + tag, pre, post = self.tokeniser.sntx_message(token.pos) + raise InvalidSyntaxError(tag, pre, post) elements.append(element) return Node("MessageName", *elements) - def e_Minus(self, expr1, token: Token, p: int) -> Optional[Node]: + def e_Minus(self, expr1, _: Token, p: int) -> Optional[Node]: q = left_binary_operators["Subtract"] if q < p: return None @@ -822,7 +845,7 @@ def e_Minus(self, expr1, token: Token, p: int) -> Optional[Node]: expr2 = Node("Times", NumberM1, expr2).flatten() return Node("Plus", expr1, expr2).flatten() - def e_Prefix(self, expr1, token: Token, expr1_precedence: int) -> Optional[Node]: + def e_Prefix(self, expr1, _: Token, expr1_precedence: int) -> Optional[Node]: """ Used to parse: expr1 @ expr2 @@ -848,7 +871,7 @@ def e_Prefix(self, expr1, token: Token, expr1_precedence: int) -> Optional[Node] expr2 = self.parse_expr(operator_precedence) return Node(expr1, expr2) - def e_Postfix(self, expr1, token: Token, expr1_precedence: int) -> Optional[Node]: + def e_Postfix(self, expr1, _: Token, expr1_precedence: int) -> Optional[Node]: """ Used to parse expr1 // expr2 @@ -878,7 +901,7 @@ def e_Postfix(self, expr1, token: Token, expr1_precedence: int) -> Optional[Node expr2 = self.parse_expr(operator_precedence + 1) return Node(expr2, expr1) - def e_RawColon(self, expr1, token: Token, p: int) -> Optional[Node]: + def e_RawColon(self, expr1, _: Token, p: int) -> Optional[Node]: head_name = expr1.get_head_name() if head_name == "Symbol": head = "Pattern" @@ -899,6 +922,7 @@ def e_RawColon(self, expr1, token: Token, p: int) -> Optional[Node]: expr2 = self.parse_expr(q + 1) return Node(head, expr1, expr2) + @track_location def e_RawLeftBracket(self, expr, token: Token, p: int) -> Optional[Node]: q = all_operators["Part"] if q < p: @@ -927,7 +951,8 @@ def e_RawLeftBracket(self, expr, token: Token, p: int) -> Optional[Node]: result.parenthesised = True return result - def e_Semicolon(self, expr1, token: Token, expr1_precedence: int) -> Optional[Node]: + @track_location + def e_Semicolon(self, expr1, _: Token, expr1_precedence: int) -> Optional[Node]: """ Used to parse expr1 ; expr2 @@ -966,12 +991,13 @@ def e_Semicolon(self, expr1, token: Token, expr1_precedence: int) -> Optional[No # XXX look for next expr otherwise backtrack try: expr2 = self.parse_expr(operator_precedence + 1) - except TranslateError: + except SyntaxError: self.backtrack(pos) self.feeder.messages = messages expr2 = NullSymbol return Node("CompoundExpression", expr1, expr2).flatten() + @track_location def e_Span(self, expr1, token: Token, p) -> Optional[Node]: q = ternary_operators["Span"] if q < p: @@ -993,7 +1019,7 @@ def e_Span(self, expr1, token: Token, p) -> Optional[Node]: messages = list(self.feeder.messages) try: expr2 = self.parse_expr(q + 1) - except TranslateError: + except SyntaxError: expr2 = Symbol("All") self.backtrack(token.pos) self.feeder.messages = messages @@ -1004,7 +1030,7 @@ def e_Span(self, expr1, token: Token, p) -> Optional[Node]: try: expr3 = self.parse_expr(q + 1) return Node("Span", expr1, expr2, expr3) - except TranslateError: + except SyntaxError: self.backtrack(token.pos) self.feeder.messages = messages return Node("Span", expr1, expr2) @@ -1025,15 +1051,16 @@ def e_TagSet(self, expr1, token: Token, p: int) -> Optional[Node]: elif tag == "Unset": head = "TagUnset" else: - self.tokeniser.sntx_message(token.pos) - raise InvalidSyntaxError() + tag, pre_error, post_error = self.tokeniser.sntx_message(token.pos) + raise InvalidSyntaxError(tag, pre_error, post_error) self.consume() if head == "TagUnset": return Node(head, expr1, expr2) expr3 = self.parse_expr(q + 1) return Node(head, expr1, expr2, expr3) - def e_Unset(self, expr1, token: Token, p: int) -> Optional[Node]: + @track_location + def e_Unset(self, expr1, _: Token, p: int) -> Optional[Node]: q = all_operators["Set"] if q < p: return None @@ -1048,27 +1075,27 @@ def e_Unset(self, expr1, token: Token, p: int) -> Optional[Node]: # can uniquely identified by a prefix character or string. # FIXME DRY with pre_Decrement - def p_Decrement(self, token: Token) -> Node: + def p_Decrement(self, _: Token) -> Node: self.consume() q = prefix_operators["PreDecrement"] return Node("PreDecrement", self.parse_expr(q)) - def p_Increment(self, token: Token) -> Node: + def p_Increment(self, _: Token) -> Node: self.consume() q = prefix_operators["PreIncrement"] return Node("PreIncrement", self.parse_expr(q)) - def p_Information(self, token: Token) -> Node: + def p_Information(self, _: Token) -> Node: self.consume() q = prefix_operators["Information"] child = self.parse_expr(q) if child.__class__ is not Symbol: - raise InvalidSyntaxError() + return Node("Missing", String("UnknownSymbol"), child) return Node( "Information", child, Node("Rule", Symbol("LongForm"), Symbol("True")) ) - def p_Integral(self, token: Token) -> Node: + def p_Integral(self, _: Token) -> Node: self.consume() inner_prec, outer_prec = all_operators["Sum"] + 1, all_operators["Power"] - 1 expr1 = self.parse_expr(inner_prec) @@ -1076,21 +1103,24 @@ def p_Integral(self, token: Token) -> Node: expr2 = self.parse_expr(outer_prec) return Node("Integrate", expr1, expr2) - def p_Factorial2(self, token: Token) -> Node: + def p_Factorial2(self, _: Token) -> Node: self.consume() q = prefix_operators["Not"] child = self.parse_expr(q) return Node("Not", Node("Not", child)) + @track_token_location def p_Filename(self, token: Token) -> Filename: result = Filename(token.text) self.consume() return result + @track_token_location def p_LeftRowBox(self, token: Token) -> Union[Node, String]: self.consume() children = [] self.box_depth += 1 + self.tokeniser.is_inside_box = True token = self.next() while token.tag not in ("RightRowBox", "OtherscriptBox"): newnode = self.parse_box_expr(NEVER_ADD_PARENTHESIS) @@ -1105,10 +1135,12 @@ def p_LeftRowBox(self, token: Token) -> Union[Node, String]: result = Node("RowBox", Node("List", *children)) self.expect("RightRowBox") self.box_depth -= 1 + self.tokeniser.is_inside_box = self.box_depth > 0 result.parenthesised = True return result - def p_Minus(self, token: Token) -> Optional[Node]: + @track_token_location + def p_Minus(self, _: Token) -> Optional[Node]: """ Used to parse: - expr1 @@ -1125,7 +1157,8 @@ def p_Minus(self, token: Token) -> Optional[Node]: else: return Node("Times", NumberM1, expr).flatten() - def p_MinusPlus(self, token: Token) -> Node: + @track_token_location + def p_MinusPlus(self, _: Token) -> Node: """ Used to parse: ∓ expr1 @@ -1138,7 +1171,8 @@ def p_MinusPlus(self, token: Token) -> Node: operator_precedence = operator_precedences["UnaryMinusPlus"] return Node("MinusPlus", self.parse_expr(operator_precedence)) - def p_Not(self, token: Token) -> Node: + @track_token_location + def p_Not(self, _: Token) -> Node: self.consume() operator_precedence = prefix_operators["Not"] child = self.parse_expr(operator_precedence) @@ -1150,6 +1184,7 @@ def p_Not(self, token: Token) -> Node: # See if we can fix this mess. p_Factorial = p_Not + @track_token_location def p_Number(self, token: Token) -> Number: s = token.text @@ -1169,8 +1204,8 @@ def p_Number(self, token: Token) -> Number: base, s = int(base_parts[0]), base_parts[1] if not 2 <= base <= 36: self.tokeniser.feeder.message("General", "base", base, token.text, 36) - self.tokeniser.sntx_message(token.pos) - raise InvalidSyntaxError() + _, pre_error, post_error = self.tokeniser.sntx_message(token.pos) + raise InvalidSyntaxError("General", "base", pre_error, post_error) # mantissa mantissa_parts = s.split("*^") @@ -1190,8 +1225,8 @@ def p_Number(self, token: Token) -> Number: for i, c in enumerate(s.lower()): if permitted_digits[c] >= base: self.tokeniser.feeder.message("General", "digit", i + 1, s, base) - self.tokeniser.sntx_message(token.pos) - raise InvalidSyntaxError() + _, pre_error, post_error = self.tokeniser.sntx_message(token.pos) + raise InvalidSyntaxError("General", "digit", pre_error, post_error) result = Number(s, sign=sign, base=base, suffix=suffix, exp=exp) self.consume() @@ -1245,7 +1280,8 @@ def p_PatternTest(self, token: Token) -> Node: "Information", child, Node("Rule", Symbol("LongForm"), Symbol("False")) ) - def p_Plus(self, token: Token): + @track_token_location + def p_Plus(self, _: Token): """ Used to parse: + expr1 @@ -1324,7 +1360,7 @@ def p_Span(self, token): return self.e_Span(Number1, token, 0) def p_String(self, token: Token) -> String: - result = String(unescape_string(token.text)) + result = String(token.text[1:-1]) self.consume() return result diff --git a/mathics/core/parser/util.py b/mathics/core/parser/util.py index 505162862..ece35aa21 100644 --- a/mathics/core/parser/util.py +++ b/mathics/core/parser/util.py @@ -1,17 +1,22 @@ -#!/usr/bin/env python3 # -*- coding: utf-8 -*- -from typing import Any, FrozenSet, Tuple +from typing import FrozenSet, Optional, Tuple +import mathics_scanner.location +from mathics_scanner.feed import LineFeeder +from mathics_scanner.location import ContainerKind + +from mathics.core.definitions import Definitions +from mathics.core.element import BaseElement from mathics.core.parser.convert import convert from mathics.core.parser.feed import MathicsSingleLineFeeder from mathics.core.parser.parser import Parser -from mathics.core.symbols import ensure_context +from mathics.core.symbols import Symbol, ensure_context parser = Parser() -def parse(definitions, feeder) -> Any: +def parse(definitions, feeder: LineFeeder) -> Optional[BaseElement]: """ Parse input (from the frontend, -e, input files, ToExpression etc). Look up symbols according to the Definitions instance supplied. @@ -21,19 +26,63 @@ def parse(definitions, feeder) -> Any: return parse_returning_code(definitions, feeder)[0] -def parse_returning_code(definitions, feeder) -> Tuple[Any, str]: +def parse_incrementally_by_line( + definitions: Definitions, feeder: LineFeeder +) -> Optional[BaseElement]: + """Parse input incrementally by line. This is in contrast to parse() or + parser_returning_code(), which parse the *entire* + input which could be many line. + + This routine is called via Read[] which parses by line, possibly + leaving of the input unparsed, depending on whether Read[] + requires more expressions. + + By working incrementally, we may avoid reading lots of input that + is not going to be needed. + + As a result, we do *not* handle exceptions raised. Instead, we leave that for the + eval_Read() routine to handle, so it can ask for another line. + + Feeder must implement the feed and empty methods. + + The result is the AST parsed or syhmbols like $Failed or NullType. Or there can be + an exception raised in parse which filters through this routine. + """ - Parse input (from the frontend, -e, input files, ToExpression etc). + + ast = parser.parse(feeder) + if ast is None or isinstance(ast, Symbol): + return ast + return convert(ast, definitions) + + +def parse_returning_code( + definitions: Definitions, feeder: LineFeeder +) -> Tuple[Optional[BaseElement], str]: + """Parse input (from the frontend, -e, input files, ToExpression etc). Look up symbols according to the Definitions instance supplied. - Feeder must implement the feed and empty methods, see core/parser/feed.py. + ``feeder`` must implement the ``feed()`` and ``empty()`` + methods. See the mathics_scanner.feed module. + """ ast = parser.parse(feeder) - source_code = parser.tokeniser.code if hasattr(parser.tokeniser, "code") else "" - if ast is not None: - return convert(ast, definitions), source_code - else: - return None, source_code + + source_text = parser.tokeniser.source_text + if ( + mathics_scanner.location.TRACK_LOCATIONS + and feeder.container_kind == ContainerKind.STREAM + ): + feeder.container.append(source_text) + + if ast is None: + return None, source_text + + converted = convert(ast, definitions) + + if hasattr(converted, "location") and ast.location: + converted.location = ast.location + return converted, source_text class SystemDefinitions: @@ -82,9 +131,12 @@ def lookup_name(self, name): return ensure_context(name, context) -def parse_builtin_rule(string, definitions=SystemDefinitions()): +def parse_builtin_rule(string, definitions=SystemDefinitions(), location=None): """ Parse rules specified in builtin docstrings/attributes. Every symbol in the input is created in the System` context. """ - return parse(definitions, MathicsSingleLineFeeder(string, "")) + return parse( + definitions, + MathicsSingleLineFeeder(string, location, ContainerKind.PYTHON), + ) diff --git a/mathics/core/pattern.py b/mathics/core/pattern.py index 274cafe45..ac5a67bf9 100644 --- a/mathics/core/pattern.py +++ b/mathics/core/pattern.py @@ -399,6 +399,12 @@ def get_match_count(self, vars_dict: Optional[dict] = None) -> Tuple[int, int]: """The number of matches""" return (1, 1) + @property + def short_name(self) -> str: + return ( + self.atom.short_name if hasattr(self.atom, "short_name") else str(self.atom) + ) + # class StopGenerator_ExpressionPattern_match(StopGenerator): # pass @@ -421,6 +427,7 @@ def __init__( evaluation: Optional[Evaluation] = None, ): self.expr = expr + self.location = expr.location if hasattr(expr, "location") else None head = expr.head if attributes is None and evaluation: attributes = head.get_attributes(evaluation.definitions) diff --git a/mathics/core/rules.py b/mathics/core/rules.py index 85a5b3d17..18e67844c 100644 --- a/mathics/core/rules.py +++ b/mathics/core/rules.py @@ -19,16 +19,15 @@ On the other hand, suppose that we define a `FunctionApplyRule` that associates `F[x_]` with the function: -``` -... -class MyFunction(Builtin): - ... - def eval_f(self, x, evaluation) -> Optional[Expression]: - "F[x_]" # pattern part of FunctionApplyRule - if x>3: - return Expression(SymbolPower, x, Integer2) - return None -``` +.. code-block:: python + + class MyFunction(Builtin): + ... + def eval_f(self, x, evaluation) -> Optional[Expression]: + "F[x_]" # pattern part of FunctionApplyRule + if x>3: + return Expression(SymbolPower, x, Integer2) + return None Then, if we apply the rule to `F[2]`, the function is evaluated returning `None`. Then, in the evaluation loop, we get the same effect as if the pattern didn't match with the expression. The loop continues then with the next rule associated with `F`. @@ -99,6 +98,7 @@ def __init__( evaluation: Optional[Evaluation] = None, attributes: Optional[int] = None, ) -> None: + self.location: Optional[Callable] = None self.pattern = BasePattern.create( pattern, attributes=attributes, evaluation=evaluation ) @@ -180,6 +180,12 @@ def yield_match(vars, rest): expr._elements_fully_evaluated = False expr._is_flat = False # I think this is fully updated expr._is_ordered = False + if ( + hasattr(expression, "location") + and hasattr(expr, "location") + and expression.location is not None + ): + expr.location = expression.location return expr if return_list: @@ -217,14 +223,13 @@ class Rule(BaseRule): finishes. Here is an example of a Rule:: - F[x_] -> x^2 (* The same thing as: Rule[x_, x^2] *) + F[x_] -> x^2 (* The same thing as: Rule[x_, x^2] *) ``F[x_]`` is a pattern and ``x^2`` is the replacement term. When applied to the expression ``G[F[1.], F[a]]`` the result is ``G[1.^2, a^2]`` - Note: we want Rules to be serializable so that we can dump and restore Rules in order to make startup time faster. @@ -282,44 +287,44 @@ def __repr__(self) -> str: class FunctionApplyRule(BaseRule): """ - A FunctionApplyRule is a rule that has a replacement term that - is associated a Python function rather than a Mathics Expression - as happens in a transformation Rule. - - Each time the Pattern part of the Rule matches an Expression, the - matching subexpression is replaced by the expression returned - by application of that function to the remaining terms. + A FunctionApplyRule is a rule that has a replacement term that + is associated a Python function rather than a Mathics Expression + as happens in a transformation Rule. - Parameters for the function are bound to parameters matched by the pattern. + Each time the Pattern part of the Rule matches an Expression, the + matching subexpression is replaced by the expression returned + by application of that function to the remaining terms. - Here is an example taken from the symbol ``System`Plus``. - It has has associated a FunctionApplyRule:: + Parameters for the function are bound to parameters matched by the pattern. - Plus[items___] -> mathics.builtin.arithfns.basic.Plus.apply + Here is an example taken from the symbol ``System`Plus``. + It has has associated a FunctionApplyRule:: - The pattern ``items___`` matches a list of Expressions. + Plus[items___] -> mathics.builtin.arithfns.basic.Plus.apply - When applied to the expression ``F[a+a]`` the method - ``mathics.builtin.arithfns.basic.Plus.apply`` is called - binding the parameter ``items`` to the value ``Sequence[a,a]``. + The pattern ``items___`` matches a list of Expressions. - The return value of this function is ``Times[2, a]`` (or more compactly: ``2*a``). - When replaced in the original expression, the result is: ``F[2*a]``. + When applied to the expression ``F[a+a]`` the method + ``mathics.builtin.arithfns.basic.Plus.apply`` is called + binding the parameter ``items`` to the value ``Sequence[a,a]``. - In contrast to (transformation) Rules, FunctionApplyRules can - change the state of definitions in the the system. + The return value of this function is ``Times[2, a]`` (or more compactly: ``2*a``). + When replaced in the original expression, the result is: ``F[2*a]``. - For example, the rule:: + In contrast to (transformation) Rules, FunctionApplyRules can + change the state of definitions in the the system. + p + For example, the rule:: - SetAttributes[a_,b_] -> mathics.builtin.attributes.SetAttributes.apply + SetAttributes[a_,b_] -> mathics.builtin.attributes.SetAttributes.apply - when applied to the expression ``SetAttributes[F, NumericFunction]`` + when applied to the expression ``SetAttributes[F, NumericFunction]`` - sets the attribute ``NumericFunction`` in the definition of the symbol ``F`` and - returns Null (``SymbolNull`)`. + sets the attribute ``NumericFunction`` in the definition of the symbol + ``F`` and returns Null (``SymbolNull``). - This will cause `Expression.evaluate() to perform an additional - ``rewrite_apply_eval()`` step. + This will cause `Expression.evaluate() to perform an additional + ``rewrite_apply_eval()`` step. """ @@ -337,7 +342,7 @@ def __init__( pattern, system=system, attributes=attributes, evaluation=evaluation ) self.name = name - self.function = function + self.location = self.function = function self.check_options = check_options # If you update this, you must also update traced_apply_function diff --git a/mathics/core/streams.py b/mathics/core/streams.py index 2b98e92dc..d4f6a73fe 100644 --- a/mathics/core/streams.py +++ b/mathics/core/streams.py @@ -85,7 +85,7 @@ def path_search(filename: str) -> Tuple[Optional[str], bool]: result = urlsave_tmp(filename) is_temporary_file = True else: - for p in PATH_VAR + [""]: + for p in list(PATH_VAR) + [""]: path = canonic_filename(osp.join(p, filename)) if osp.exists(path): result = path diff --git a/mathics/core/structure.py b/mathics/core/structure.py index 3602d6afd..2f434e5fb 100644 --- a/mathics/core/structure.py +++ b/mathics/core/structure.py @@ -46,7 +46,8 @@ def slice(self, expr, py_slice): class UnlinkedStructure(Structure): """ UnlinkedStructure produces Expressions that are not linked to "origins" in terms of cache. - This produces the same thing as doing Expression(head, *elements). + + This produces the same thing as doing ``Expression(head, *elements)``. """ def __init__(self, head): diff --git a/mathics/core/symbols.py b/mathics/core/symbols.py index a612c112b..5a71bacc5 100644 --- a/mathics/core/symbols.py +++ b/mathics/core/symbols.py @@ -29,17 +29,18 @@ class NumericOperators: """ This is a mixin class for Element-like objects that might have numeric values. - It adds or "mixes in" numeric functions for these objects like round_to_float(). + It adds or "mixes in" numeric functions for these objects like ``round_to_float()``. It also adds methods to the class to facilite building - ``Expression``s in the Mathics Python code using Python syntax. + ``Expression`` s in the Mathics Python code using Python syntax. - So for example, instead of writing in Python: + So for example, instead of writing in Python:: to_expression("Abs", -8) Expression(SymbolPlus, Integer1, Integer2) - you can instead have: + you can instead have:: + abs(Integer(-8)) Integer(1) + Integer(2) """ @@ -494,6 +495,8 @@ def evaluate(self, evaluation): for rule in rules: result = rule.apply(self, evaluation, fully=True) if result is not None and not result.sameQ(self): + if result.is_literal: + return result return result.evaluate(evaluation) return self @@ -742,7 +745,12 @@ class BooleanType(SymbolConstant): the constant is either SymbolTrue or SymbolFalse. """ - pass + @property + def is_literal(self) -> bool: + """ + We don't allow changing Boolean values True and False. + """ + return True def symbol_set(*symbols: Symbol) -> FrozenSet[Symbol]: diff --git a/mathics/doc/common_doc.py b/mathics/doc/common_doc.py index a397b2b90..4080d3d40 100644 --- a/mathics/doc/common_doc.py +++ b/mathics/doc/common_doc.py @@ -21,7 +21,6 @@ DL_ITEM_RE, DL_RE, HYPERTEXT_RE, - IMG_PNG_RE, IMG_RE, LATEX_RE, LIST_ITEM_RE, @@ -76,7 +75,6 @@ "Documentation", "DocumentationEntry", "HYPERTEXT_RE", - "IMG_PNG_RE", "IMG_RE", "LATEX_RE", "LIST_ITEM_RE", diff --git a/mathics/doc/doc_entries.py b/mathics/doc/doc_entries.py index 201d4ae19..8fd21100d 100644 --- a/mathics/doc/doc_entries.py +++ b/mathics/doc/doc_entries.py @@ -9,8 +9,9 @@ import logging import re +from abc import ABC from os import getenv -from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Sequence +from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Sequence, Tuple from mathics.core.evaluation import Message, Print, _Out @@ -32,7 +33,6 @@ "i", "ol", "li", - "con", "console", "img", "imgpng", @@ -51,7 +51,9 @@ # The regular expressions below (strings ending with _RE # pull out information from docstring or text in a file. Ghetto parsing. -CONSOLE_RE = re.compile(r"(?s)<(?Pcon|console)>(?P.*?)") +# <(?console)> in the following rule is just keep for compatibility +# with Mathics-Django documentation. +CONSOLE_RE = re.compile(r"(?m)(?s)<(?Pconsole)>(?P[\s\S]+?)") DL_ITEM_RE = re.compile( r"(?s)<(?Pd[td])>(?P.*?)(?:|)\s*(?:(?=)|$)" ) @@ -59,15 +61,18 @@ HYPERTEXT_RE = re.compile( r"(?s)<(?Pem|url)>(\s*:(?P.*?):\s*)?(?P.*?)" ) -IMG_PNG_RE = re.compile( - r'' -) IMG_RE = re.compile( r'' ) # Preserve space before and after in-line code variables. LATEX_RE = re.compile(r"(\s?)\$(\w+?)\$(\s?)") +LATEX_DISPLAY_EQUATION_RE = re.compile(r"(?m)(?.*?)\}\{(?P.*?)\}") +LATEX_URL_RE = re.compile(r"(?s)\\url\{(?P.*?)\}") + + LIST_ITEM_RE = re.compile(r"(?s)
  • (.*?)(?:
  • |(?=
  • )|$)") LIST_RE = re.compile(r"(?s)<(?Pul|ol)>(?P.*?)") MATHICS_RE = re.compile(r"(?#SX])>[ ](.*) # test-code indicator + ^\s*([>#SX])>[ ](.*) # test-code indicator ((?:\n\s*(?:[:|=.][ ]|\.).*)*) # test-code results""" ) TESTCASE_OUT_RE = re.compile(r"^\s*([:|=])(.*)$") @@ -160,9 +165,11 @@ def filter_comments(doc: str) -> str: POST_SUBSTITUTION_TAG = "_POST_SUBSTITUTION%d_" -def pre_sub(regexp, text: str, repl_func: Callable): +def pre_sub( + regexp, text: str, repl_func: Callable, prev_subst: Tuple = tuple() +) -> Tuple[str, Tuple]: """apply substitutions previous to parse the text""" - post_substitutions: List[str] = [] + post_substitutions: List[str] = list(prev_subst) def repl_pre(match): repl = repl_func(match) @@ -172,12 +179,22 @@ def repl_pre(match): text = regexp.sub(repl_pre, text) - return text, post_substitutions + return text, tuple(post_substitutions) -def post_sub(text: str, post_substitutions) -> str: +def post_sub(text: str, post_substitutions: Tuple) -> str: """apply substitutions after parsing the doctests.""" - for index, sub in enumerate(post_substitutions): + + # Substitutions must be applied in reverse order, + # because one substitution can contain previous sustititions. + # For instance ``"A link":http://example.org + # first is replaced by + # ``_POST_SUBSTITUTION0_:http://example.org + # with ``_POST_SUBSTITUTION0_`` storing ``"A link"`` + # and then by + # POST_SUBSTITUTION1_ + substitutions = tuple(enumerate(post_substitutions)) + for index, sub in substitutions[::-1]: text = text.replace(POST_SUBSTITUTION_TAG % index, sub) return text @@ -216,10 +233,7 @@ def parse_docstring_to_DocumentationEntry_items( logging.warning("``key_part`` is deprecated. Its value is discarded.") # Remove commented lines. - doc = filter_comments(doc).strip(r"\s") - - # Remove leading
    ...
    - # doc = DL_RE.sub("", doc) + doc = filter_comments(doc) # .strip("\s") # pre-substitute Python code because it might contain tests doc, post_substitutions = pre_sub( @@ -260,6 +274,37 @@ def parse_docstring_to_DocumentationEntry_items( return items +class BaseDocElement(ABC): + """Base class for elements of the documentation system.""" + + def get_ancestors(self) -> list: + """ + Get a list of the DocElements such that + each element is the parent of the following. + """ + ancestors = [] + parent = self.parent + while isinstance(parent, BaseDocElement): + ancestors.append(parent) + parent = parent.parent + + ancestors = ancestors[::-1] + return ancestors + + def get_children(self) -> list: + raise NotImplementedError + + @property + def parent(self): + "the container where the element is" + raise NotImplementedError + + @parent.setter + def parent(self, value): + "the container where the section is" + raise TypeError("parent is a read-only property") + + class DocTest: """ Class to hold a single doctest. @@ -278,6 +323,14 @@ class DocTest: `|` Prints output. """ + index: int + outs: List[_Out] + test: str + result: str + private: bool + ignore: bool + _key: Optional[tuple] + def __init__( self, index: int, @@ -303,7 +356,7 @@ def strip_sentinal(line: str): self.index = index self.outs: List[_Out] = [] - self.result = None + result_value = None # Private test cases are executed, but NOT shown as part of the docs self.private = testcase[0] == "#" @@ -318,7 +371,7 @@ def strip_sentinal(line: str): self.ignore = False self.test = strip_sentinal(testcase[1]) - self._key: Optional[tuple] = key_prefix + (index,) if key_prefix else None + self._key = key_prefix + (index,) if key_prefix else None outs = testcase[2].splitlines() for line in outs: @@ -329,8 +382,8 @@ def strip_sentinal(line: str): if text.startswith(" "): text = text[1:] text = "\n" + text - if self.result is not None: - self.result += text + if result_value is not None: + result_value += text elif self.outs: self.outs[-1].text += text continue @@ -341,11 +394,12 @@ def strip_sentinal(line: str): symbol, text = match.group(1), match.group(2) text = text.strip() if symbol == "=": - self.result = text + result_value = text elif symbol == ":": self.outs.append(Message("", "", text)) elif symbol == "|": self.outs.append(Print(text)) + self.result = result_value or "" def __str__(self) -> str: return self.test @@ -357,6 +411,32 @@ def compare(self, result: Optional[str], out: tuple = tuple()) -> bool: """ return self.compare_result(result) and self.compare_out(out) + def compare_out(self, outs: tuple = tuple()) -> bool: + """Compare messages and warnings produced during the evaluation of + the test with the expected messages and warnings.""" + # Check out + wanted_outs = self.outs + if len(wanted_outs) == 1 and wanted_outs[0].text == "...": + # If we have ... don't check + return True + if len(outs) != len(wanted_outs): + # Mismatched number of output lines, and we don't have "..." + return False + + # Python 3.13 replaces tabs by a single space in docstrings. + # In doctests we replace tabs by sequences of four spaces. + def tabs_to_spaces(val): + return val.text.replace("\t", 4 * " ") + + # Need to check all output line by line + for got, wanted in zip(outs, wanted_outs): + if wanted.text == "...": + return True + if not tabs_to_spaces(got) == tabs_to_spaces(wanted): + return False + + return True + def compare_result(self, result: Optional[str]): """Compare a result with the expected result""" wanted = self.result @@ -364,8 +444,9 @@ def compare_result(self, result: Optional[str]): if wanted in ("...", result): return True - if result is None or wanted is None: - return False + if result is None: + return wanted == "" + result_list = result.splitlines() wanted_list = wanted.splitlines() if result_list == [] and wanted_list == ["#<--#"]: @@ -382,27 +463,6 @@ def compare_result(self, result: Optional[str]): return False return True - def compare_out(self, outs: tuple = tuple()) -> bool: - """Compare messages and warnings produced during the evaluation of - the test with the expected messages and warnings.""" - # Check out - wanted_outs = self.outs - if len(wanted_outs) == 1 and wanted_outs[0].text == "...": - # If we have ... don't check - return True - if len(outs) != len(wanted_outs): - # Mismatched number of output lines, and we don't have "..." - return False - - # Need to check all output line by line - for got, wanted in zip(outs, wanted_outs): - if wanted.text == "...": - return True - if not got == wanted: - return False - - return True - @property def key(self): """key identifier of the test""" @@ -425,6 +485,9 @@ def __init__(self): self.tests = [] self.text = "" + def __str__(self) -> str: + return "\n".join(str(test) for test in self.tests) + def get_tests(self) -> list: """ Returns lists test objects. @@ -435,9 +498,6 @@ def get_tests(self) -> list: # """Returns True if this test is "private" not supposed to be visible as example documentation.""" # return all(test.private for test in self.tests) - def __str__(self) -> str: - return "\n".join(str(test) for test in self.tests) - def test_indices(self) -> List[int]: """indices of the tests""" return [test.index for test in self.tests] @@ -477,7 +537,7 @@ def test_indices(self) -> List[int]: # Former XMLDoc -class DocumentationEntry: +class DocumentationEntry(BaseDocElement): """ A class to hold the content of a documentation entry, in our custom XML-like format. @@ -536,6 +596,48 @@ def _set_classes(self): def __str__(self) -> str: return "\n\n".join(str(item) for item in self.items) + def get_children(self) -> list: + """Get children""" + return [] + + def get_tests(self) -> List["DocTest"]: + """retrieve a list of tests in the documentation entry""" + tests = [] + for item in self.items: + tests.extend(item.get_tests()) + return tests + + @property + def parent(self): + "the container where the element is" + return self._parent + + @parent.setter + def parent(self, value): + "the container where the section is" + raise TypeError("parent is a read-only property") + + def set_parent_path(self, parent): + """Set the parent path""" + self._parent = parent + if parent is None: + return self + + path_objs = parent.get_ancestors()[1:] + [parent] + path = [element.title for element in path_objs] + # Set the key on each test + for test in self.get_tests(): + assert test.key is None + # For backward compatibility, we need + # to reduce this to three fields. + # TODO: remove me and ensure that this + # works here and in Mathics Django + if len(path) > 3: + path = path[:2] + [path[-1]] + test.key = tuple(path) + (test.index,) + + return self + def text(self) -> str: """text version of the documentation entry""" # used for introspection @@ -549,42 +651,19 @@ def text(self) -> str: item = item.replace("
  • ", "") item = item.replace("
    ", " ") item = item.replace("
    ", "") + item = item.replace("\\$", "_DOLARSIGN_") + item = ( + item.replace("\\'", "_SINGLEQUOTE_") + .replace("'", "") + .replace("_SINGLEQUOTE_", "'") + ) item = "\n".join(line for line in item.split("\n") if not line.isspace()) item = re.sub(r"\$([0-9a-zA-Z]*)\$", r"\1", item) - return item - def get_tests(self) -> List["DocTest"]: - """retrieve a list of tests in the documentation entry""" - tests = [] - for item in self.items: - tests.extend(item.get_tests()) - return tests - - def set_parent_path(self, parent): - """Set the parent path""" - self.path = None - path = [] - while hasattr(parent, "parent"): - path = [parent.title] + path - parent = parent.parent - - if hasattr(parent, "title"): - path = [parent.title] + path - - if path: - self.path = path - # Set the key on each test - for test in self.get_tests(): - assert test.key is None - # For backward compatibility, we need - # to reduce this to three fields. - # TODO: remove me and ensure that this - # works here and in Mathics Django - if len(path) > 3: - path = path[:2] + [path[-1]] - test.key = tuple(path) + (test.index,) - - return self + item = re.sub(r"\$([0-9a-zA-Z]*)\_\{([0-9a-zA-Z]*)\}\$", r"\1\2", item) + item = re.sub(r"\$([0-9a-zA-Z]*)\_([0-9a-zA-Z]*)\$", r"\1\2", item) + item = item.replace("_DOLARSIGN_", "$") + return item class Tests: diff --git a/mathics/doc/documentation/1-Manual.mdoc b/mathics/doc/documentation/1-Manual.mdoc index 7c5f27ffd..231aebb29 100644 --- a/mathics/doc/documentation/1-Manual.mdoc +++ b/mathics/doc/documentation/1-Manual.mdoc @@ -13,8 +13,8 @@ See the :installation instructions:https://mathics-development-guide.readth For implementation details, please refer to the :Developers Guide:https://mathics-development-guide.readthedocs.io/en/latest. -
    -\Mathematica is great, but it has a couple of disadvantages. +
    +\Mathematica is great, but it might have some disadvantages, depending on on your point of view.
    • It is not open source. @@ -22,8 +22,6 @@ For implementation details, please refer to the :Developers Guide:https://m
    • It can't hook into different kinds of open-source packages that have independently developed algorithms and methods
    -The second point some may find an advantage. - However, even if you are willing to pay hundreds of dollars for the software, you would not be able to see what\'s going on "inside" the program if that is your interest. That\'s what free, open-source, and community-supported software is for! \Mathics combines the beauty of \Mathematica implemented in an open-source environment written in Python. The Python ecosystem includes libraries and tools like: @@ -35,7 +33,7 @@ However, even if you are willing to pay hundreds of dollars for the software, yo
  • :SciPy: https://www.scipy.org/ for Scientific calculations. -Performance of \Mathics is not, right now, practical in large-scale projects and calculations. However, it can be used as a tool for exploration and education. There is promise that it can provide better debugging. +Performance of \Mathics is not, right now, practical in large-scale projects and calculations. However, it can be used as a tool for exploration and education. There is promise that it can provide better debugging, since we can be completely transparent about every aspect of its operation.
  • @@ -52,8 +50,10 @@ Outside of the "core" \Mathics kernel (which has only a primitive command-line i
    • a :command-line interface:https://pypi.org/project/mathicsscript/ using either :prompt-toolkit:https://python-prompt-toolkit.readthedocs.io/en/master/, or GNU Readline
    • a :Django-based web server:https://pypi.org/project/Mathics-Django/ +
    • a :A browser-based no-install online front-end:https://mathics3.github.io/Mathics3-live/
    • a :Mathics3 module for Graphs:https://pypi.org/project/pymathics-graph/ (via :NetworkX:https://networkx.org/),
    • a :Mathics3 module for NLP:https://pypi.org/project/pymathics-natlang/ (via :nltk:https://www.nltk.org/, :spacy:https://spacy.io/, and others) +
    • a :Mathics3 Debugger Module:https://pypi.org/project/Mathics3-trepan/ (experimental)
    • a :A docker container:https://hub.docker.com/r/mathicsorg/mathics which bundles all of the above
    @@ -69,12 +69,12 @@ A :docker image of the v.9 release: https://hub.docker.com/r/arkadi/mathics Around 2017, the project was largely abandoned in its largely Python 2.7 state, with some support for Python 3.2-3.5 via six. Subsequently, around mid 2020, it was picked up by the current developers. A list of authors and contributors can be found in the -:AUTHORS.txt: +:AUTHORS.txt: https://github.com/Mathics3/mathics-core/blob/master/AUTHORS.txt file.
    -There are lots of ways in which \Mathics could still be improved. :FUTURE.rst: https://github.com/Mathics3/mathics-core/blob/master/FUTURE.rst has the current roadmap. +There are lots of ways in which \Mathics could still be improved. :FUTURE.rst: https://github.com/Mathics3/mathics-core/blob/master/FUTURE.rst has the current roadmap. We always could use help in Python programming and improving the documentation. But there are other ways to help. For example: @@ -586,25 +586,25 @@ In fact, functions in \Mathics are just one aspect of patterns
    '_' or 'Blank[]'
    matches one expression. -
    'Pattern[$x$, $p$]' +
    'Pattern'[$x$, $p$]
    matches the pattern $p$ and stores the matching sub-expression into $x$. -
    '$x$_' or 'Pattern[$x$, Blank[]]' +
    $x$'_' or 'Pattern['$x$, 'Blank[]]'
    matches one expression and stores it in $x$.
    '__' or 'BlankSequence[]'
    matches a sequence of one or more expressions.
    '___' or 'BlankNullSequence[]'
    matches a sequence of zero or more expressions. -
    '_$h$' or 'Blank[$h$]' +
    '_'$h$ or 'Blank'[$h$]
    matches one expression with head $h$. -
    '$x$_$h$' or 'Pattern[$x$, Blank[$h$]]' +
    $x$'_'$h$ or 'Pattern['$x$, 'Blank['$h$']]'
    matches one expression with head $h$ and stores it in $x$. -
    '$p$ | $q$' or 'Alternatives[$p$, $q$]' +
    $p$ | $q$ or 'Alternatives['$p$, $q$']'
    matches either pattern $p$ or $q$. -
    '$p$ ? $t$' or 'PatternTest[$p$, $t$]' -
    matches $p$ if the test '$t$[$p$]' yields 'True'. -
    '$p$ /; $c$' or 'Condition[$p$, $c$]' +
    $p$ '?' $t$ or 'PatternTest['$p$, $t$']' +
    matches $p$ if the test $t[p]$ yields 'True'. +
    $p$ '/;' $c$ or 'Condition['$p$, $c$']'
    matches $p$ if condition $c$ holds. -
    'Verbatim[$p$]' +
    'Verbatim'[$p$]
    matches an expression that equals $p$, without regarding patterns inside $p$.
    @@ -696,22 +696,22 @@ Functions can be applied using prefix or postfix notation, in addition to using
    Like most programming languages, \Mathics has common program-flow control statements for conditions, loops, etc.:
    -
    'If[$cond$, $pos$, $neg$]' +
    'If'[$cond$, $pos$, $neg$]
    returns $pos$ if $cond$ evaluates to 'True', and $neg$ if it evaluates to 'False'. -
    'Which[$cond1$, $expr1$, $cond2$, $expr2$, ...]' -
    yields $expr1$ if $cond1$ evaluates to 'True', $expr2$ if $cond2$ evaluates to 'True', etc. -
    'Do[$expr$, {$i$, $max$}]' +
    'Which'[$cond_1$, $expr_1$, $cond_2$, $expr_2$, ...] +
    yields $expr_1$ if $cond_1$ evaluates to 'True', $expr_2$ if $cond_2$ evaluates to 'True', etc. +
    'Do'[$expr$, {$i$, $max$}]
    evaluates $expr$ $max$ times, substituting $i$ in $expr$ with values from 1 to $max$. -
    'For[$start$, $test$, $incr$, $body$]' +
    'For'[$start$, $test$, $incr$, $body$]
    evaluates $start$, and then iteratively $body$ and $incr$ as long as $test$ evaluates to 'True'. -
    'While[$test$, $body$]' +
    'While'[$test$, $body$]
    evaluates $body$ as long as $test$ evaluates to 'True'. -
    'Nest[$f$, $expr$, $n$]' +
    'Nest'[$f$, $expr$, $n$]
    returns an expression with $f$ applied $n$ times to $expr$. -
    'NestWhile[$f$, $expr$, $test$]' +
    'NestWhile'[$f$, $expr$, $test$]
    applies a function $f$ repeatedly on an expression $expr$, until applying $test$ on the result no longer yields 'True'. -
    'FixedPoint[$f$, $expr$]' +
    'FixedPoint'[$f$, $expr$]
    starting with $expr$, repeatedly applies $f$ until the result no longer changes.
    @@ -744,12 +744,12 @@ However, sometimes "local" variables are needed in order not to disturb the glob
  • dynamic scoping by 'Block'.
    -
    'Module[{$vars$}, $expr$]' +
    'Module'[{$vars$}, $expr$]
    localizes variables by giving them a temporary name of the form - 'name$number', where number is the current value of '$ModuleNumber'. Each time a module - is evaluated, '$ModuleNumber' is incremented. + 'name\$number', where number is the current value of '\$ModuleNumber'. Each time a module + is evaluated, '\$ModuleNumber' is incremented. -
    'Block[{$vars$}, $expr$]' +
    'Block'[{$vars$}, $expr$]
    temporarily stores the definitions of certain variables, evaluates $expr$ with reset values and restores the original definitions afterward.
    @@ -834,13 +834,13 @@ Special formats might not be very relevant for individual symbols, but rather fo = You can use several helper functions to format expressions:
    -
    'Infix[$expr$, $op$]' +
    'Infix'[$expr$, $op$]
    formats the arguments of $expr$ with infix operator $op$. -
    'Prefix[$expr$, $op$]' +
    'Prefix'[$expr$, $op$]
    formats the argument of $expr$ with prefix operator $op$. -
    'Postfix[$expr$, $op$]' +
    'Postfix'[$expr$, $op$]
    formats the argument of $expr$ with postfix operator $op$. -
    'StringForm[$form$, $arg1$, $arg2$, ...]' +
    'StringForm'[$form$, $arg1$, $arg2$, ...]
    formats arguments using a format string.
    @@ -856,9 +856,9 @@ There are several methods to display expressions in 2-D:
    displays expressions in a row.
    'Grid[{{...}}]'
    displays a matrix in two-dimensional form. -
    'Subscript[$expr$, $i1$, $i2$, ...]' -
    displays $expr$ with subscript indices $i1$, $i2$, ... -
    'Superscript[$expr$, $exp$]' +
    'Subscript'[$expr$, $i_1$, $i_2$, ...] +
    displays $expr$ with subscript indices $i_1$, $i_2$, ... +
    'Superscript'[$expr$, $exp$]
    displays $expr$ with superscript (exponent) $exp$.
  • @@ -919,7 +919,7 @@ For instance, you can override 'MakeBoxes' to format lists in a different way: However, this will not be accepted as input to \Mathics anymore: >> [1 2 3] - : Expression cannot begin with "[1 2 3]" (line 1 of ""). + : Expression cannot begin with "[1 2 3]" (line 1 of ""). >> Clear[MakeBoxes] @@ -961,21 +961,21 @@ The list elements in this 'RowBox' are strings, though string delimiters are not
    Two-dimensional graphics can be created using the function 'Graphics' and a list of graphics primitives. For three-dimensional graphics see the following section. The following primitives are available:
    -
    'Circle[{$x$, $y$}, $r$]' +
    'Circle'[{$x$, $y$}, $r$]
    draws a circle. -
    'Disk[{$x$, $y$}, $r$]' +
    'Disk'[{$x$, $y$}, $r$]
    draws a filled disk. -
    'Rectangle[{$x1$, $y1$}, {$x2$, $y2$}]' +
    'Rectangle'[{$x_1$, $y_1$}, {$x_2$, $y_2$}]
    draws a filled rectangle. -
    'Polygon[{{$x1$, $y1$}, {$x2$, $y2$}, ...}]' +
    'Polygon'[{{$x_1$, $y_1$}, {$x_2$, $y_2$}, ...}]
    draws a filled polygon. -
    'Line[{{$x1$, $y1$}, {$x2$, $y2$}, ...}]' +
    'Line'[{{$x_1$, $y_1$}, {$x_2$, $y_2$}, ...}]
    draws a line. -
    'Text[$text$, {$x$, $y$}]' +
    'Text'[$text$, {$x$, $y$}]
    draws text in a graphics.
    @@ -987,16 +987,16 @@ Two-dimensional graphics can be created using the function 'Graphics' and a list Colors can be added in the list of graphics primitives to change the drawing color. The following ways to specify colors are supported:
    -
    'RGBColor[$r$, $g$, $b$]' +
    'RGBColor'[$r$, $g$, $b$]
    specifies a color using red, green, and blue. -
    'CMYKColor[$c$, $m$, $y$, $k$]' +
    'CMYKColor'[$c$, $m$, $y$, $k$]
    specifies a color using cyan, magenta, yellow, and black. -
    'Hue[$h$, $s$, $b$]' +
    'Hue'[$h$, $s$, $b$]
    specifies a color using hue, saturation, and brightness. -
    'GrayLevel[$l$]' +
    'GrayLevel'[$l$]
    specifies a color using a gray level.
    @@ -1014,11 +1014,11 @@ Table of hues: Colors can be mixed and altered using the following functions:
    -
    'Blend[{$color1$, $color2$}, $ratio$]' +
    'Blend'[{$color1$, $color2$}, $ratio$]
    mixes $color1$ and $color2$ with $ratio$, where a ratio of 0 returns $color1$ and a ratio of 1 returns $color2$. -
    'Lighter[$color$]' +
    'Lighter'[$color$]
    makes $color$ lighter (mixes it with 'White'). -
    'Darker[$color$]' +
    'Darker'[$color$]
    makes $color$ darker (mixes it with 'Black').
    @@ -1035,11 +1035,11 @@ Colors can be mixed and altered using the following functions:
    Three-dimensional graphics are created using the function 'Graphics3D' and a list of 3D primitives. The following primitives are supported so far:
    -
    'Polygon[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z3$}, ...}]' +
    'Polygon'[{{$x_1$, $y_1$, $z_1$}, {$x_2$, $y_2$, $z_3$}, ...}]
    draws a filled polygon. -
    'Line[{{$x1$, $y1$, $z1$}, {$x2$, $y2$, $z3$}, ...}]' +
    'Line'[{{$x_1$, $y_1$, $z_1$}, {$x_2$, $y_2$, $z_3$}, ...}]
    draws a line. -
    'Point[{$x1$, $y1$, $z1$}]' +
    'Point'[{$x_1$, $y_1$, $z_1$}]
    draws a point.
    @@ -1281,7 +1281,7 @@ When you enter Mathics in the top after the Mathics logo and the word "Mathics" It looks like this: - + These save and load worksheets, share sessions, run a gallery of examples, go to the GitHub organization page, and provide information about the particular Mathics3 installation. @@ -1314,7 +1314,7 @@ Assuming your are running locally or on a host called 'localhost' using the defa Worksheets exist in the browser window only and are not stored on the server, by default. To save all your queries and results, use the Save button which is the middle graphic of the menu bar. It looks like this: - + Depending on browser, desktop, and OS-settings, the "Ctrl+S" key combination may do the same thing. @@ -1322,7 +1322,7 @@ Depending on browser, desktop, and OS-settings, the "Ctrl+S" key combination may Saved worksheets can be loaded or deleted using the File Open button which is the left-most button in the menu bar. It looks like this: - + Depending on browser, desktop, and OS-settings, the "Ctrl+O" key combination may do the same thing. @@ -1334,7 +1334,7 @@ A pop-up menu should appear with the list of saved worksheets with an option to We have a number of examples showing off briefly some of the capabilities of the system. These are run when you hit the button that looks like this: - + It is also shown in the pop-up text that appears when Mathics3 is first run. @@ -1346,19 +1346,19 @@ When you use the Django-based Web interface of \Mathics, a browser session is cr This implies that you should not store sensitive, private information in \Mathics variables when using the online Web interface. In addition to their values being stored in a database on the server, your queries might be saved for debugging purposes. However, the fact that they are transmitted over plain HTTP should make you aware that you should not transmit any sensitive information. When you want to do calculations with that kind of stuff, simply install \Mathics locally! -If you are using a public terminal, to erase all your definitions and close the browser window. When you use \Mathics in a browser, use the command Quit[] or its alias, Exit[]. +If you are using a public terminal, to erase all your definitions and close the browser window. When you use \Mathics in a browser, use the command 'Quit[]' or its alias, 'Exit[]'. -When you reload the current page in a browser using the default URL, e.g., http:localhost:8000, all of the previous input and output disappears. +When you reload the current page in a browser using the default URL, e.g., http:localhost:8000, all of the previous input and output disappears. -On the other hand, Definitions as described above do not, unless Quit[] or Exit[] is entered as described above. +On the other hand, Definitions as described above do not, unless 'Quit[]' or 'Exit[]' is entered as described above. If you want a URL that records the input entered, the Generate Input Hash button does this. The button looks like this: - + -For example, assuming you have a \Mathics server running at port 8000 on localhost, and you enter the URL http://localhost:8000/#cXVlcmllcz14, you should see a single line of input containing x entered. +For example, assuming you have a \Mathics server running at port 8000 on localhost, and you enter the URL http://localhost:8000/#cXVlcmllcz14, you should see a single line of input containing 'x' entered. -Of course, what the value of this is when evaluated depends on whether x has been previously defined. +Of course, what the value of this is when evaluated depends on whether 'x' has been previously defined.
    diff --git a/mathics/doc/latex/1-Manual.mdoc b/mathics/doc/latex/1-Manual.mdoc deleted file mode 120000 index f23c9aa64..000000000 --- a/mathics/doc/latex/1-Manual.mdoc +++ /dev/null @@ -1 +0,0 @@ -../documentation/1-Manual.mdoc \ No newline at end of file diff --git a/mathics/doc/latex/Makefile b/mathics/doc/latex/Makefile index 6a8404dc9..825b3f50b 100644 --- a/mathics/doc/latex/Makefile +++ b/mathics/doc/latex/Makefile @@ -43,7 +43,7 @@ logo-heptatom.pdf logo-text-nodrop.pdf: (cd .. && $(BASH) ./images.sh) #: The build of the documentation which is derived from docstrings in the Python code and doctest data -documentation.tex: $(DOCTEST_LATEX_DATA_PCL) 1-Manual.mdoc +documentation.tex: $(DOCTEST_LATEX_DATA_PCL) ../documentation/1-Manual.mdoc $(PYTHON) ./doc2latex.py $(MATHICS3_MODULE_OPTION) && $(BASH) ./sed-hack.sh #: Same as mathics.pdf diff --git a/mathics/doc/latex/testing-sample.tex b/mathics/doc/latex/testing-sample.tex index 543d3cf78..c4f5bc246 100644 --- a/mathics/doc/latex/testing-sample.tex +++ b/mathics/doc/latex/testing-sample.tex @@ -30,7 +30,7 @@ \section*{TestSection} import solids; size(6.6667cm, 6.6667cm); currentprojection=perspective(2.6,-4.8,4.0); -currentlight=light(rgb(0.5,0.5,1), specular=red, (2,0,2), (2,2,2), (0,2,2)); +currentlight=light(rgb(0.5,0.5,0.5), specular=red, (2,0,2), (2,2,2), (0,2,2)); // Sphere3DBox draw(surface(sphere((0, 0, 0), 1)), rgb(0.0,0.6666666666666667,0.0)); draw(((-1,-1,-1)--(1,-1,-1)), rgb(0.4, 0.4, 0.4)+linewidth(1)); diff --git a/mathics/doc/latex_doc.py b/mathics/doc/latex_doc.py index 32c3cc090..a2ba2aee7 100644 --- a/mathics/doc/latex_doc.py +++ b/mathics/doc/latex_doc.py @@ -12,9 +12,12 @@ DL_ITEM_RE, DL_RE, HYPERTEXT_RE, - IMG_PNG_RE, IMG_RE, + LATEX_DISPLAY_EQUATION_RE, + LATEX_HREF_RE, + LATEX_INLINE_EQUATION_RE, LATEX_RE, + LATEX_URL_RE, LIST_ITEM_RE, LIST_RE, MATHICS_RE, @@ -58,6 +61,7 @@ LATEX_CONSOLE_RE = re.compile(r"\\console\{(.*?)\}") LATEX_INLINE_END_RE = re.compile(r"(?s)(?P\\lstinline'[^']*?'\}?[.,;:])") + LATEX_TEXT_RE = re.compile( r"(?s)\\text\{([^{}]*?(?:[^{}]*?\{[^{}]*?(?:[^{}]*?\{[^{}]*?\}[^{}]*?)*?" r"[^{}]*?\}[^{}]*?)*?[^{}]*?)\}" @@ -69,6 +73,7 @@ LATEX_TESTOUT_DELIM_RE = re.compile(r", ") +MATHICS_VARIABLE_NAME = re.compile(r"[\$\`A-Za-z0-9]*") # The goal of the following pattern is to enclose the numbers included in # expressions produced by tests between ```\allowbreak{}```. The pattern matches # with negative numbers or positive numbers preceded by a space character. @@ -91,7 +96,55 @@ def escape_latex_code(text) -> str: def escape_latex(text): - """Escape documentation text""" + """ + Escape documentation text. + + A block of text in the docstring documentation system + is a mixture of XML, LaTeX, and *literal* Python and + WL code, in a mixture that is not fully compatible + with Markdown or RST text, so we are not able to use + an standard parser. + + To convert this into pure LaTeX code, this function + collects certain parts like LaTeX equations or verbatim + WL code using Python regular expressions. These blocks + are processed and stored, and replaced in the original + text by numerated placeholders. + + The remaining text is then parsed to replace or escape + special characters, and some special markers. + + Finally, the placeholders are replaced by the processed + blocks, to get a valid LaTeX code. + + Notice that to use the `$` character as a character and + not as an equation marker, it should be escaped. + + An special case is the one of variable names. In that case, + that consists of numbers, alphabetic characters, and + the special characters '`' and '$' is treated different, + because they come from Symbol names and not from docstrings. + + For general, multiline code, the processing is done in the + following order: + + * First the verbatim Python code is extracted. + * Then, URLs are and references are collected. + * After that, anything surrounded by '$' or '$$' + is processed. + * Then, some LaTeX special characters, like brackets, + are escaped. + * After that, the remaining WL code and XML code is translated + to LaTeX. + * Finally, all the placeholders are replaced to the postprocessed + form. + + """ + # Single line, no spaces, maybe a Symbol name + if "\n" not in text and " " not in text: + if MATHICS_VARIABLE_NAME.match(text): + text = text.replace("$", r"\$") + return text def repl_python(match): return ( @@ -101,12 +154,97 @@ def repl_python(match): % match.group(1).strip() ) + def repl_eq(match): + return "$" + match.group(1) + "$" + + # Protect Python code from further replacements. text, post_substitutions = pre_sub(PYTHON_RE, text, repl_python) + # Process pictures + def repl_img(match): + src = match.group("src") + return r"\includegraphics[scale=1.0]{images/%(src)s}" % {"src": src} + + text, post_substitutions = pre_sub( + IMG_RE, text, repl_img, tuple(post_substitutions) + ) + + # Protect LaTeX equations from further replacements. + text, post_substitutions = pre_sub( + LATEX_DISPLAY_EQUATION_RE, text, repl_eq, tuple(post_substitutions) + ) + text, post_substitutions = pre_sub( + LATEX_INLINE_EQUATION_RE, text, repl_eq, tuple(post_substitutions) + ) + + # Process quotations + def repl_quotation(match): + return r"``%s''" % match.group(1) + + text, post_substitutions = pre_sub( + QUOTATIONS_RE, text, repl_quotation, tuple(post_substitutions) + ) + + # Process hyperrefs + def ensure_sharp_escape_in_url(content) -> str: + content = content.replace(" ", "").replace("\n", "") + return content.replace("#", r"\#").replace(r"\\#", r"\#") + + def repl_hypertext(match) -> str: + tag = match.group("tag") + content = ensure_sharp_escape_in_url(match.group("content")) + # + # Sometimes it happens that the URL does not + # fit in 80 characters. Then, to avoid that + # flake8 complains, and also to have a + # nice and readable ASCII representation, + # we would like to split the URL in several, + # lines, having indentation spaces. + # + # The following line removes these extra + # characters, which would spoil the URL, + # producing a single line, space-free string. + # + if tag == "em": + return r"\emph{%s}" % content + elif tag == "url": + text = match.group("text") + if text is None: + return "\\url{%s}" % content + else: + # If we have "/doc" as the beginning the URL link + # then is is a link to a section + # in this manual, so use "\ref" rather than "\href'. + if content.find("/doc/") == 0: + slug = "/".join(content.split("/")[2:]).rstrip("/") + return "%s \\ref{%s}" % (text, latex_label_safe(slug)) + # slug = "/".join(content.split("/")[2:]).rstrip("/") + # return "%s of section~\\ref{%s}" % (text, latex_label_safe(slug)) + else: + return "\\href{%s}{%s}" % (content, text) + return "\\href{%s}{%s}" % (content, text) + + def repl_href(match) -> str: + content = ensure_sharp_escape_in_url(match.group("content")) + return r"\href{%s}{%s}" % (content, match.group("text")) + + def repl_url(match) -> str: + content = ensure_sharp_escape_in_url(match.group("content")) + return r"\url{%s}" % (content,) + + text, post_substitutions = pre_sub( + HYPERTEXT_RE, text, repl_hypertext, tuple(post_substitutions) + ) + text, post_substitutions = pre_sub( + LATEX_HREF_RE, text, repl_href, tuple(post_substitutions) + ) + text, post_substitutions = pre_sub( + LATEX_URL_RE, text, repl_url, tuple(post_substitutions) + ) + text = replace_all( text, [ - ("\\", "\\\\"), ("{", "\\{"), ("}", "\\}"), ("~", "\\~{ }"), @@ -119,7 +257,7 @@ def repl_python(match): def repl(match): text = match.group(1) if text: - text = replace_all(text, [("\\'", "'"), ("^", "\\^")]) + text = replace_all(text, [(r"\'", "'"), ("^", r"\^")]) escape_char = get_latex_escape_char(text) text = LATEX_RE.sub( lambda m: "%s%s\\codevar{\\textit{%s}}%s\\lstinline%s" @@ -137,17 +275,16 @@ def repl(match): text = MATHICS_RE.sub(repl, text) - text = LATEX_RE.sub( - lambda m: "%s\\textit{%s}%s" % (m.group(1), m.group(2), m.group(3)), text - ) - text = text.replace("\\\\'", "'") def repl_dl(match): text = match.group(1) - text = DL_ITEM_RE.sub( - lambda m: "\\%(tag)s{%(content)s}\n" % m.groupdict(), text - ) + + def repl_dd_dt(match): + match_dict = match.groupdict() + return "\\%(tag)s{%(content)s}\n" % match_dict + + text = DL_ITEM_RE.sub(repl_dd_dt, text) return "\\begin{definitions}%s\\end{definitions}" % text text = DL_RE.sub(repl_dl, text) @@ -161,36 +298,6 @@ def repl_list(match): text = LIST_RE.sub(repl_list, text) - # FIXME: get this from MathicsScanner - text = replace_all( - text, - [ - ("$", r"\$"), - ("\00f1", r"\~n"), - ("\u00e7", r"\c{c}"), - ("\u2216", r"\\"), - ("\u00e9", r"\'e"), - ("\u00ea", r"\^e"), - ("\u03b3", r"$\gamma$"), - ("\u03b8", r"$\theta$"), - ("\u03bc", r"$\mu$"), - ("\u03c0", r"$\pi$"), - ("\u03d5", r"$\phi$"), - ("\u2107", r"$\mathrm{e}$"), - ("\u222b", r"\int"), - ("\u2243", r"$\simeq$"), - ("\u2026", r"$\dots$"), - ("\u2260", r"$\ne$"), - ("\u2264", r"$\le$"), - ("\u2265", r"$\ge$"), - ("\u22bb", r"$\oplus$"), # The WL veebar-looking symbol isn't in AMSLaTeX - ("\u22bc", r"$\barwedge$"), - ("\u22bd", r"$\veebar$"), - ("\u21d2", r"$\Rightarrow$"), - ("\uf74c", r"d"), - ], - ) - def repl_char(match): char = match.group(1) return { @@ -199,82 +306,15 @@ def repl_char(match): text = LATEX_CHAR_RE.sub(repl_char, text) - def repl_img(match): - src = match.group("src") - title = match.group("title") - label = match.group("label") - return r"""\begin{figure*}[htp] -\centering -\includegraphics[width=\textwidth]{images/%(src)s} -\caption{%(title)s} -\label{%(label)s} -\end{figure*}""" % { - "src": src, - "title": title, - "label": label, - } - - text = IMG_RE.sub(repl_img, text) - - def repl_imgpng(match): - src = match.group("src") - return r"\includegraphics[scale=1.0]{images/%(src)s}" % {"src": src} - - text = IMG_PNG_RE.sub(repl_imgpng, text) - def repl_ref(match): return r"figure \ref{%s}" % match.group("label") text = REF_RE.sub(repl_ref, text) - def repl_quotation(match): - return r"``%s''" % match.group(1) - - def repl_hypertext(match) -> str: - tag = match.group("tag") - content = match.group("content") - # - # Sometimes it happens that the URL does not - # fit in 80 characters. Then, to avoid that - # flake8 complains, and also to have a - # nice and readable ASCII representation, - # we would like to split the URL in several, - # lines, having indentation spaces. - # - # The following line removes these extra - # characters, which would spoil the URL, - # producing a single line, space-free string. - # - content = content.replace(" ", "").replace("\n", "") - if tag == "em": - return r"\emph{%s}" % content - elif tag == "url": - text = match.group("text") - if text is None: - return "\\url{%s}" % content - else: - # If we have "/doc" as the beginning the URL link - # then is is a link to a section - # in this manual, so use "\ref" rather than "\href'. - if content.find("/doc/") == 0: - slug = "/".join(content.split("/")[2:]).rstrip("/") - return "%s \\ref{%s}" % (text, latex_label_safe(slug)) - # slug = "/".join(content.split("/")[2:]).rstrip("/") - # return "%s of section~\\ref{%s}" % (text, latex_label_safe(slug)) - else: - return "\\href{%s}{%s}" % (content, text) - return "\\href{%s}{%s}" % (content, text) - - text = QUOTATIONS_RE.sub(repl_quotation, text) - text = HYPERTEXT_RE.sub(repl_hypertext, text) - def repl_console(match): - tag = match.group("tag") content = match.group("content") content = content.strip() content = content.replace(r"\$", "$") - if tag == "con": - return "\\console{%s}" % content return "\\begin{lstlisting}\n%s\n\\end{lstlisting}" % content text = CONSOLE_RE.sub(repl_console, text) @@ -303,8 +343,7 @@ def repl_subsection(match): text = SUBSECTION_END_RE.sub("", text) for key, (xml, tex) in SPECIAL_COMMANDS.items(): - # "\" has been escaped already => 2 \ - text = text.replace("\\\\" + key, tex) + text = text.replace("\\" + key, tex) text = post_sub(text, post_substitutions) diff --git a/mathics/doc/structure.py b/mathics/doc/structure.py index 5b04e5a09..f4ed8b5e7 100644 --- a/mathics/doc/structure.py +++ b/mathics/doc/structure.py @@ -17,7 +17,13 @@ builtins_by_module as global_builtins_by_module, mathics3_builtins_modules, ) -from mathics.doc.doc_entries import DocTest, DocumentationEntry, Tests, filter_comments +from mathics.doc.doc_entries import ( + BaseDocElement, + DocTest, + DocumentationEntry, + Tests, + filter_comments, +) from mathics.doc.utils import slugify from mathics.eval.pymathics import pymathics_builtins_by_module, pymathics_modules @@ -42,7 +48,7 @@ # DocSection has to appear before DocGuideSection which uses it. -class DocSection: +class DocSection(BaseDocElement): """An object for a Documented Section. A Section is part of a Chapter. It can contain subsections. """ @@ -97,6 +103,16 @@ def __lt__(self, other) -> bool: def __str__(self) -> str: return f" == {self.title} ==\n{self.doc}" + def get_children(self) -> list: + """Get children""" + return list(self.subsections) + + def get_tests(self): + """yield tests""" + if self.installed: + for test in self.doc.get_tests(): + yield test + @property def parent(self): "the container where the section is" @@ -107,15 +123,9 @@ def parent(self, value): "the container where the section is" raise TypeError("parent is a read-only property") - def get_tests(self): - """yield tests""" - if self.installed: - for test in self.doc.get_tests(): - yield test - # DocChapter has to appear before DocGuideSection which uses it. -class DocChapter: +class DocChapter(BaseDocElement): """An object for a Documented Chapter. A Chapter is part of a Part[dChapter. It can contain (Guide or plain) Sections. """ @@ -163,6 +173,10 @@ def all_sections(self): "guides and normal sections" return sorted(self.guide_sections) + sorted(self.sections) + def get_children(self) -> list: + """Get children""" + return self.all_sections + @property def parent(self): "the container where the chapter is" @@ -196,7 +210,7 @@ def __init__( print(" DEBUG Creating Guide Section", title) -class DocPart: +class DocPart(BaseDocElement): """ Represents one of the main parts of the document. Parts can be loaded from a mdoc file, generated automatically from @@ -222,8 +236,22 @@ def __str__(self) -> str: str(chapter) for chapter in sorted_chapters(self.chapters) ) + def get_children(self) -> list: + """Get children""" + return self.chapters + + @property + def parent(self): + "the container where the element is" + return self.documentation -class Documentation: + @parent.setter + def parent(self, value): + "the container where the section is" + raise TypeError("parent is a read-only property") + + +class Documentation(BaseDocElement): """ `Documentation` describes an object containing the whole documentation system. Documentation @@ -381,9 +409,8 @@ def doc_part(self, title, start): builtin_part = self.part_class(self, title, is_reference=start) self.parts.append(builtin_part) - def get_part(self, part_slug): - """return a section from part key""" - return self.parts_by_slug.get(part_slug) + def get_children(self): + return self.parts def get_chapter(self, part_slug, chapter_slug): """return a section from part and chapter keys""" @@ -392,6 +419,10 @@ def get_chapter(self, part_slug, chapter_slug): return part.chapters_by_slug.get(chapter_slug) return None + def get_part(self, part_slug): + """return a section from part key""" + return self.parts_by_slug.get(part_slug) + def get_section(self, part_slug, chapter_slug, section_slug): """return a section from part, chapter and section keys""" part = self.parts_by_slug.get(part_slug) @@ -523,15 +554,7 @@ def load_part_from_file( chapter, title, text, operator=None, installed=True ) chapter.sections.append(section) - subsections = SUBSECTION_RE.findall(text) - for subsection_title in subsections: - subsection = self.subsection_class( - chapter, - section, - subsection_title, - text, - ) - section.subsections.append(subsection) + # Subsections are processed inside the Documentation entry. else: section = None if not chapter.doc: @@ -547,8 +570,18 @@ def load_part_from_file( self.parts.append(part) return chapter_order + @property + def parent(self): + "the container where the element is" + return None + + @parent.setter + def parent(self, value): + "the container where the section is" + raise TypeError("parent is a read-only property") + -class DocSubsection: +class DocSubsection(BaseDocElement): """An object for a Documented Subsection. A Subsection is part of a Section. """ @@ -626,6 +659,16 @@ def __init__( def __str__(self) -> str: return f"=== {self.title} ===\n{self.doc}" + def get_children(self) -> list: + """Get children""" + return list(self.subsections) + + def get_tests(self): + """yield tests""" + if self.installed: + for test in self.doc.get_tests(): + yield test + @property def parent(self): """the chapter where the section is""" @@ -633,14 +676,9 @@ def parent(self): @parent.setter def parent(self, value): + "the container where the section is" raise TypeError("parent is a read-only property") - def get_tests(self): - """yield tests""" - if self.installed: - for test in self.doc.get_tests(): - yield test - class MathicsMainDocumentation(Documentation): """MathicsMainDocumentation specializes ``Documentation`` by providing the attributes @@ -685,7 +723,7 @@ def __init__(self): def gather_doctest_data(self): """ - Populates the documentatation. + Populates the documentation. (deprecated) """ logging.warning( @@ -698,9 +736,9 @@ def sorted_chapters(chapters: List[DocChapter]) -> List[DocChapter]: """Return chapters sorted by title""" return sorted( chapters, - key=lambda chapter: str(chapter.sort_order) - if chapter.sort_order is not None - else chapter.title, + key=lambda chapter: ( + str(chapter.sort_order) if chapter.sort_order is not None else chapter.title + ), ) @@ -709,7 +747,7 @@ def sorted_modules(modules) -> list: exists, or the module's name if not.""" return sorted( modules, - key=lambda module: module.sort_order - if hasattr(module, "sort_order") - else module.__name__, + key=lambda module: ( + module.sort_order if hasattr(module, "sort_order") else module.__name__ + ), ) diff --git a/mathics/docpipeline.py b/mathics/docpipeline.py index c7b16d839..bebe1145f 100644 --- a/mathics/docpipeline.py +++ b/mathics/docpipeline.py @@ -200,6 +200,7 @@ def show_test(self, test: DocTest, index: int, subindex: int): def test_case( test: DocTest, + src_name: str, test_pipeline: DocTestPipeline, fail: Callable, ) -> bool: @@ -213,7 +214,7 @@ def test_case( test_parameters = test_pipeline.parameters try: time_start = datetime.now() - result = test_pipeline.session.evaluate_as_in_cli(test.test, src_name="") + result = test_pipeline.session.evaluate_as_in_cli(test.test, src_name=src_name) out = result.out result = result.result except Exception as exc: @@ -428,6 +429,7 @@ def test_section_in_chapter( continue section_name_for_print = test_status.section_name_for_print(doctest) test_status.show_section(doctest) + assert doctest.key is not None key = list(doctest.key)[1:-1] if key != test_status.prev_key: index = 1 @@ -451,6 +453,7 @@ def fail_message(why): success = test_case( doctest, + f"", test_pipeline, fail=fail_message, ) @@ -643,6 +646,7 @@ def test_sections( # show_test_summary(test_pipeline, "sections", section_names) # return + assert section_names is not None show_test_summary(test_pipeline, "sections", section_names) return diff --git a/mathics/eval/arithfns/basic.py b/mathics/eval/arithfns/basic.py index 3d8acb86b..ab78c09a2 100644 --- a/mathics/eval/arithfns/basic.py +++ b/mathics/eval/arithfns/basic.py @@ -157,8 +157,7 @@ def eval_Times(*items: BaseElement) -> Optional[BaseElement]: exp, ) continue - else: - item = item + # Otherwise, just append the element... elements.append(item) diff --git a/mathics/eval/arithmetic.py b/mathics/eval/arithmetic.py index 8eef8ebae..ecea65238 100644 --- a/mathics/eval/arithmetic.py +++ b/mathics/eval/arithmetic.py @@ -2,7 +2,7 @@ # FIXME: rewrite this and split up to # have eval functions for mathics.builtin.arithmetic. # Those other functions that remain, e.g tracing functions -# put somewher else. +# put somewhere else. """ arithmetic-related evaluation functions. diff --git a/mathics/eval/binary/io.py b/mathics/eval/binary/io.py new file mode 100644 index 000000000..170777e46 --- /dev/null +++ b/mathics/eval/binary/io.py @@ -0,0 +1,43 @@ +""" +evaluation functions for mathics.builtin.binary.io +""" + +import struct + +from mathics.core.list import ListExpression +from mathics.core.streams import Stream +from mathics.eval.files_io.read import SymbolEndOfFile + + +def eval_BinaryReadList( + stream: Stream, readers: dict, kinds: list, return_list: bool, count: int +): + """ + Evaluation function for BinaryRead[] and BinaryReadList[] + + Read binary data from stream. `kinds` is a list of kinds to read. + If return_list is True, then the result is a list + """ + + result = [] + while count > 0 or count <= -1: + count -= 1 + for t in kinds: + try: + result.append(readers[t](stream.io)) + except struct.error: + result.append(SymbolEndOfFile) + if len(result) > 0 and result[-1] == SymbolEndOfFile: + break + + if return_list: + # If we were doing BinaryReadList[], i.e. return_list is True, + # then strip off the EndOfFile at the end + if count < 0: + result = result[:-1] + + return ListExpression(*result) + elif len(result) == 1: + return result[0] + else: + return ListExpression(*result) diff --git a/mathics/eval/drawing/plot.py b/mathics/eval/drawing/plot.py index 9459744a1..c814f871a 100644 --- a/mathics/eval/drawing/plot.py +++ b/mathics/eval/drawing/plot.py @@ -131,7 +131,7 @@ def get_plot_range_option( "System`Automatic", "System`All", ) - or isinstance(pr, list) + or isinstance(pr, (list, tuple)) for pr in plotrange ) return plotrange diff --git a/mathics/eval/drawing/plot3d.py b/mathics/eval/drawing/plot3d.py index 1dbde17de..341cddfff 100644 --- a/mathics/eval/drawing/plot3d.py +++ b/mathics/eval/drawing/plot3d.py @@ -49,441 +49,435 @@ def eval_plot3d( ): """%(name)s[functions_, {x_Symbol, xstart_, xstop_}, {y_Symbol, ystart_, ystop_}, OptionsPattern[%(name)s]]""" - if True: - xexpr_limits = ListExpression(x, xstart, xstop) - yexpr_limits = ListExpression(y, ystart, ystop) - expr = Expression( - Symbol(self.get_name()), - functions, - xexpr_limits, - yexpr_limits, - *options_to_rules(options), - ) - - functions = self.get_functions_param(functions) - plot_name = self.get_name() - - def convert_limit(value, limits): - result = value.round_to_float(evaluation) - if result is None: - evaluation.message(plot_name, "plln", value, limits) - return result - xstart = convert_limit(xstart, xexpr_limits) - xstop = convert_limit(xstop, xexpr_limits) - ystart = convert_limit(ystart, yexpr_limits) - ystop = convert_limit(ystop, yexpr_limits) - if None in (xstart, xstop, ystart, ystop): - return - - if ystart >= ystop: - evaluation.message(plot_name, "plln", ystop, expr) - return - - if xstart >= xstop: - evaluation.message(plot_name, "plln", xstop, expr) - return + xexpr_limits = ListExpression(x, xstart, xstop) + yexpr_limits = ListExpression(y, ystart, ystop) + expr = Expression( + Symbol(self.get_name()), + functions, + xexpr_limits, + yexpr_limits, + *options_to_rules(options), + ) - # Mesh Option - mesh_option = self.get_option(options, "Mesh", evaluation) - mesh = mesh_option.to_python() - if mesh not in ["System`None", "System`Full", "System`All"]: - evaluation.message("Mesh", "ilevels", mesh_option) - mesh = "System`Full" - - # PlotPoints Option - plotpoints_option = self.get_option(options, "PlotPoints", evaluation) - plotpoints = plotpoints_option.to_python() - - def check_plotpoints(steps): - if isinstance(steps, int) and steps > 0: - return True - return False - - if plotpoints == "System`None": - plotpoints = [7, 7] - elif check_plotpoints(plotpoints): - plotpoints = [plotpoints, plotpoints] - - if not ( - isinstance(plotpoints, list) - and len(plotpoints) == 2 - and check_plotpoints(plotpoints[0]) - and check_plotpoints(plotpoints[1]) - ): - evaluation.message(self.get_name(), "invpltpts", plotpoints) - plotpoints = [7, 7] - - # MaxRecursion Option - maxrec_option = self.get_option(options, "MaxRecursion", evaluation) - max_depth = maxrec_option.to_python() - if isinstance(max_depth, int): - if max_depth < 0: - max_depth = 0 - evaluation.message(self.get_name(), "invmaxrec", max_depth, 15) - elif max_depth > 15: - max_depth = 15 - evaluation.message(self.get_name(), "invmaxrec", max_depth, 15) - else: - pass # valid - elif max_depth == float("inf"): + functions = self.get_functions_param(functions) + plot_name = self.get_name() + + def convert_limit(value, limits): + result = value.round_to_float(evaluation) + if result is None: + evaluation.message(plot_name, "plln", value, limits) + return result + + xstart = convert_limit(xstart, xexpr_limits) + xstop = convert_limit(xstop, xexpr_limits) + ystart = convert_limit(ystart, yexpr_limits) + ystop = convert_limit(ystop, yexpr_limits) + if None in (xstart, xstop, ystart, ystop): + return + + if ystart >= ystop: + evaluation.message(plot_name, "plln", ystop, expr) + return + + if xstart >= xstop: + evaluation.message(plot_name, "plln", xstop, expr) + return + + # Mesh Option + mesh_option = self.get_option(options, "Mesh", evaluation) + mesh = mesh_option.to_python() + if mesh not in ["System`None", "System`Full", "System`All"]: + evaluation.message("Mesh", "ilevels", mesh_option) + mesh = "System`Full" + + # PlotPoints Option + plotpoints_option = self.get_option(options, "PlotPoints", evaluation) + plotpoints = plotpoints_option.to_python() + + def check_plotpoints(steps): + if isinstance(steps, int) and steps > 0: + return True + return False + + if plotpoints == "System`None": + plotpoints = (7, 7) + elif check_plotpoints(plotpoints): + plotpoints = (plotpoints, plotpoints) + + if not ( + isinstance(plotpoints, (list, tuple)) + and len(plotpoints) == 2 + and check_plotpoints(plotpoints[0]) + and check_plotpoints(plotpoints[1]) + ): + evaluation.message(self.get_name(), "invpltpts", plotpoints) + plotpoints = (7, 7) + + # MaxRecursion Option + maxrec_option = self.get_option(options, "MaxRecursion", evaluation) + max_depth = maxrec_option.to_python() + if isinstance(max_depth, int): + if max_depth < 0: + max_depth = 0 + evaluation.message(self.get_name(), "invmaxrec", max_depth, 15) + elif max_depth > 15: max_depth = 15 evaluation.message(self.get_name(), "invmaxrec", max_depth, 15) else: - max_depth = 0 - evaluation.message(self.get_name(), "invmaxrec", max_depth, 15) + pass # valid + elif max_depth == float("inf"): + max_depth = 15 + evaluation.message(self.get_name(), "invmaxrec", max_depth, 15) + else: + max_depth = 0 + evaluation.message(self.get_name(), "invmaxrec", max_depth, 15) - # Plot the functions - graphics = [] - for indx, f in enumerate(functions): - stored = {} + # Plot the functions + graphics = [] + for _, f in enumerate(functions): + stored = {} - compiled_fn = compile_quiet_function( - f, [x.get_name(), y.get_name()], evaluation, False - ) + compiled_fn = compile_quiet_function( + f, [x.get_name(), y.get_name()], evaluation, False + ) - def apply_fn(compiled_fn: Callable, x_value, y_value): - try: - # Try to used cached value first - return stored[(x_value, y_value)] - except KeyError: - value = compiled_fn(x_value, y_value) - if value is not None: - value = float(value) - stored[(x_value, y_value)] = value - return value - - triangles = [] - - split_edges = set() # subdivided edges - - def triangle(x1, y1, x2, y2, x3, y3, depth=0): - v1, v2, v3 = ( - apply_fn(compiled_fn, x1, y1), - apply_fn(compiled_fn, x2, y2), - apply_fn(compiled_fn, x3, y3), - ) + def apply_fn(compiled_fn: Callable, x_value, y_value): + try: + # Try to used cached value first + return stored[(x_value, y_value)] + except KeyError: + value = compiled_fn(x_value, y_value) + if value is not None: + value = float(value) + stored[(x_value, y_value)] = value + return value + + triangles = [] + + split_edges = set() # subdivided edges + + def triangle(x1, y1, x2, y2, x3, y3, depth=0): + v1, v2, v3 = ( + apply_fn(compiled_fn, x1, y1), + apply_fn(compiled_fn, x2, y2), + apply_fn(compiled_fn, x3, y3), + ) - if (v1 is v2 is v3 is None) and (depth > max_depth // 2): - # fast finish because the entire region is undefined but - # recurse 'a little' to avoid missing well defined regions - return - elif v1 is None or v2 is None or v3 is None: - # 'triforce' pattern recursion to find the edge of defined region - # 1 - # /\ - # 4 /__\ 6 - # /\ /\ - # /__\/__\ - # 2 5 3 - if depth < max_depth: - x4, y4 = 0.5 * (x1 + x2), 0.5 * (y1 + y2) - x5, y5 = 0.5 * (x2 + x3), 0.5 * (y2 + y3) - x6, y6 = 0.5 * (x1 + x3), 0.5 * (y1 + y3) - split_edges.add( - ((x1, y1), (x2, y2)) - if (x2, y2) > (x1, y1) - else ((x2, y2), (x1, y1)) - ) - split_edges.add( - ((x2, y2), (x3, y3)) - if (x3, y3) > (x2, y2) - else ((x3, y3), (x2, y2)) - ) - split_edges.add( - ((x1, y1), (x3, y3)) - if (x3, y3) > (x1, y1) - else ((x3, y3), (x1, y1)) - ) - triangle(x1, y1, x4, y4, x6, y6, depth + 1) - triangle(x4, y4, x2, y2, x5, y5, depth + 1) - triangle(x6, y6, x5, y5, x3, y3, depth + 1) - triangle(x4, y4, x5, y5, x6, y6, depth + 1) - return - triangles.append(sorted(((x1, y1, v1), (x2, y2, v2), (x3, y3, v3)))) - - # linear (grid) sampling - numx = plotpoints[0] * 1.0 - numy = plotpoints[1] * 1.0 - for xi in range(plotpoints[0]): - for yi in range(plotpoints[1]): - # Decide which way to break the square grid into triangles - # by looking at diagonal lengths. - # - # 3___4 3___4 - # |\ | | /| - # | \ | versus | / | - # |__\| |/__| - # 1 2 1 2 - # - # Approaching the boundary of the well defined region is - # important too. Use first strategy if 1 or 4 are undefined - # and strategy 2 if either 2 or 3 are undefined. - # - (x1, x2, x3, x4) = ( - xstart + value * (xstop - xstart) - for value in ( - xi / numx, - (xi + 1) / numx, - xi / numx, - (xi + 1) / numx, - ) + if (v1 is v2 is v3 is None) and (depth > max_depth // 2): + # fast finish because the entire region is undefined but + # recurse 'a little' to avoid missing well defined regions + return + elif v1 is None or v2 is None or v3 is None: + # 'triforce' pattern recursion to find the edge of defined region + # 1 + # /\ + # 4 /__\ 6 + # /\ /\ + # /__\/__\ + # 2 5 3 + if depth < max_depth: + x4, y4 = 0.5 * (x1 + x2), 0.5 * (y1 + y2) + x5, y5 = 0.5 * (x2 + x3), 0.5 * (y2 + y3) + x6, y6 = 0.5 * (x1 + x3), 0.5 * (y1 + y3) + split_edges.add( + ((x1, y1), (x2, y2)) + if (x2, y2) > (x1, y1) + else ((x2, y2), (x1, y1)) ) - (y1, y2, y3, y4) = ( - ystart + value * (ystop - ystart) - for value in ( - yi / numy, - yi / numy, - (yi + 1) / numy, - (yi + 1) / numy, - ) + split_edges.add( + ((x2, y2), (x3, y3)) + if (x3, y3) > (x2, y2) + else ((x3, y3), (x2, y2)) ) + split_edges.add( + ((x1, y1), (x3, y3)) + if (x3, y3) > (x1, y1) + else ((x3, y3), (x1, y1)) + ) + triangle(x1, y1, x4, y4, x6, y6, depth + 1) + triangle(x4, y4, x2, y2, x5, y5, depth + 1) + triangle(x6, y6, x5, y5, x3, y3, depth + 1) + triangle(x4, y4, x5, y5, x6, y6, depth + 1) + return + triangles.append(sorted(((x1, y1, v1), (x2, y2, v2), (x3, y3, v3)))) + + # linear (grid) sampling + numx = plotpoints[0] * 1.0 + numy = plotpoints[1] * 1.0 + for xi in range(plotpoints[0]): + for yi in range(plotpoints[1]): + # Decide which way to break the square grid into triangles + # by looking at diagonal lengths. + # + # 3___4 3___4 + # |\ | | /| + # | \ | versus | / | + # |__\| |/__| + # 1 2 1 2 + # + # Approaching the boundary of the well defined region is + # important too. Use first strategy if 1 or 4 are undefined + # and strategy 2 if either 2 or 3 are undefined. + # + x1, x2, x3, x4 = ( + xstart + value * (xstop - xstart) + for value in ( + xi / numx, + (xi + 1) / numx, + xi / numx, + (xi + 1) / numx, + ) + ) + y1, y2, y3, y4 = ( + ystart + value * (ystop - ystart) + for value in ( + yi / numy, + yi / numy, + (yi + 1) / numy, + (yi + 1) / numy, + ) + ) - v1 = apply_fn(compiled_fn, x1, y1) - v2 = apply_fn(compiled_fn, x2, y2) - v3 = apply_fn(compiled_fn, x3, y3) - v4 = apply_fn(compiled_fn, x4, y4) - - if v1 is None or v4 is None: - triangle(x1, y1, x2, y2, x3, y3) - triangle(x4, y4, x3, y3, x2, y2) - elif v2 is None or v3 is None: + v1 = apply_fn(compiled_fn, x1, y1) + v2 = apply_fn(compiled_fn, x2, y2) + v3 = apply_fn(compiled_fn, x3, y3) + v4 = apply_fn(compiled_fn, x4, y4) + + if v1 is None or v4 is None: + triangle(x1, y1, x2, y2, x3, y3) + triangle(x4, y4, x3, y3, x2, y2) + elif v2 is None or v3 is None: + triangle(x2, y2, x1, y1, x4, y4) + triangle(x3, y3, x4, y4, x1, y1) + else: + if abs(v3 - v2) > abs(v4 - v1): triangle(x2, y2, x1, y1, x4, y4) triangle(x3, y3, x4, y4, x1, y1) else: - if abs(v3 - v2) > abs(v4 - v1): - triangle(x2, y2, x1, y1, x4, y4) - triangle(x3, y3, x4, y4, x1, y1) - else: - triangle(x1, y1, x2, y2, x3, y3) - triangle(x4, y4, x3, y3, x2, y2) - - # adaptive resampling - # TODO: optimise this - # Cos of the maximum angle between successive line segments - ang_thresh = cos(20 * pi / 180) - for depth in range(1, max_depth): - needs_removal = set() - lent = len(triangles) # number of initial triangles - for i1 in range(lent): - for i2 in range(lent): - # find all edge pairings - if i1 == i2: - continue - t1 = triangles[i1] - t2 = triangles[i2] - - edge_pairing = ( - (t1[0], t1[1]) == (t2[0], t2[1]) - or (t1[0], t1[1]) == (t2[1], t2[2]) - or (t1[0], t1[1]) == (t2[0], t2[2]) - or (t1[1], t1[2]) == (t2[0], t2[1]) - or (t1[1], t1[2]) == (t2[1], t2[2]) - or (t1[1], t1[2]) == (t2[0], t2[2]) - or (t1[0], t1[2]) == (t2[0], t2[1]) - or (t1[0], t1[2]) == (t2[1], t2[2]) - or (t1[0], t1[2]) == (t2[0], t2[2]) - ) - if not edge_pairing: - continue - v1 = [t1[1][i] - t1[0][i] for i in range(3)] - w1 = [t1[2][i] - t1[0][i] for i in range(3)] - v2 = [t2[1][i] - t2[0][i] for i in range(3)] - w2 = [t2[2][i] - t2[0][i] for i in range(3)] - n1 = ( # surface normal for t1 - (v1[1] * w1[2]) - (v1[2] * w1[1]), - (v1[2] * w1[0]) - (v1[0] * w1[2]), - (v1[0] * w1[1]) - (v1[1] * w1[0]), - ) - n2 = ( # surface normal for t2 - (v2[1] * w2[2]) - (v2[2] * w2[1]), - (v2[2] * w2[0]) - (v2[0] * w2[2]), - (v2[0] * w2[1]) - (v2[1] * w2[0]), - ) - try: - angle = ( - n1[0] * n2[0] + n1[1] * n2[1] + n1[2] * n2[2] - ) / sqrt( - (n1[0] ** 2 + n1[1] ** 2 + n1[2] ** 2) - * (n2[0] ** 2 + n2[1] ** 2 + n2[2] ** 2) - ) - except ZeroDivisionError: - angle = 0.0 - if abs(angle) < ang_thresh: - for i, t in ((i1, t1), (i2, t2)): - # subdivide - x1, y1 = t[0][0], t[0][1] - x2, y2 = t[1][0], t[1][1] - x3, y3 = t[2][0], t[2][1] - x4, y4 = 0.5 * (x1 + x2), 0.5 * (y1 + y2) - x5, y5 = 0.5 * (x2 + x3), 0.5 * (y2 + y3) - x6, y6 = 0.5 * (x1 + x3), 0.5 * (y1 + y3) - needs_removal.add(i) - split_edges.add( - ((x1, y1), (x2, y2)) - if (x2, y2) > (x1, y1) - else ((x2, y2), (x1, y1)) - ) - split_edges.add( - ((x2, y2), (x3, y3)) - if (x3, y3) > (x2, y2) - else ((x3, y3), (x2, y2)) - ) - split_edges.add( - ((x1, y1), (x3, y3)) - if (x3, y3) > (x1, y1) - else ((x3, y3), (x1, y1)) - ) - triangle(x1, y1, x4, y4, x6, y6, depth=depth) - triangle(x2, y2, x4, y4, x5, y5, depth=depth) - triangle(x3, y3, x5, y5, x6, y6, depth=depth) - triangle(x4, y4, x5, y5, x6, y6, depth=depth) - # remove subdivided triangles which have been divided - triangles = [ - t for i, t in enumerate(triangles) if i not in needs_removal - ] - - # fix up subdivided edges - # - # look at every triangle and see if its edges need updating. - # depending on how many edges require subdivision we proceede with - # one of two subdivision strategies - # - # TODO possible optimisation: don't look at every triangle again - made_changes = True - while made_changes: - made_changes = False - new_triangles = [] - for i, t in enumerate(triangles): - new_points = [] - if ((t[0][0], t[0][1]), (t[1][0], t[1][1])) in split_edges: - new_points.append([0, 1]) - if ((t[1][0], t[1][1]), (t[2][0], t[2][1])) in split_edges: - new_points.append([1, 2]) - if ((t[0][0], t[0][1]), (t[2][0], t[2][1])) in split_edges: - new_points.append([0, 2]) - - if len(new_points) == 0: + triangle(x1, y1, x2, y2, x3, y3) + triangle(x4, y4, x3, y3, x2, y2) + + # adaptive resampling + # TODO: optimise this + # Cos of the maximum angle between successive line segments + ang_thresh = cos(20 * pi / 180) + for depth in range(1, max_depth): + needs_removal = set() + lent = len(triangles) # number of initial triangles + for i1 in range(lent): + for i2 in range(lent): + # find all edge pairings + if i1 == i2: continue - made_changes = True - # 'triforce' subdivision - # 1 - # /\ - # 4 /__\ 6 - # /\ /\ - # /__\/__\ - # 2 5 3 - # if less than three edges require subdivision bisect them - # anyway but fake their values by averaging - x4 = 0.5 * (t[0][0] + t[1][0]) - y4 = 0.5 * (t[0][1] + t[1][1]) - v4 = stored.get((x4, y4), 0.5 * (t[0][2] + t[1][2])) - - x5 = 0.5 * (t[1][0] + t[2][0]) - y5 = 0.5 * (t[1][1] + t[2][1]) - v5 = stored.get((x5, y5), 0.5 * (t[1][2] + t[2][2])) - - x6 = 0.5 * (t[0][0] + t[2][0]) - y6 = 0.5 * (t[0][1] + t[2][1]) - v6 = stored.get((x6, y6), 0.5 * (t[0][2] + t[2][2])) - - if not (v4 is None or v6 is None): - new_triangles.append(sorted((t[0], (x4, y4, v4), (x6, y6, v6)))) - if not (v4 is None or v5 is None): - new_triangles.append(sorted((t[1], (x4, y4, v4), (x5, y5, v5)))) - if not (v5 is None or v6 is None): - new_triangles.append(sorted((t[2], (x5, y5, v5), (x6, y6, v6)))) - if not (v4 is None or v5 is None or v6 is None): - new_triangles.append( - sorted(((x4, y4, v4), (x5, y5, v5), (x6, y6, v6))) + t1 = triangles[i1] + t2 = triangles[i2] + + edge_pairing = ( + (t1[0], t1[1]) == (t2[0], t2[1]) + or (t1[0], t1[1]) == (t2[1], t2[2]) + or (t1[0], t1[1]) == (t2[0], t2[2]) + or (t1[1], t1[2]) == (t2[0], t2[1]) + or (t1[1], t1[2]) == (t2[1], t2[2]) + or (t1[1], t1[2]) == (t2[0], t2[2]) + or (t1[0], t1[2]) == (t2[0], t2[1]) + or (t1[0], t1[2]) == (t2[1], t2[2]) + or (t1[0], t1[2]) == (t2[0], t2[2]) + ) + if not edge_pairing: + continue + v1 = [t1[1][i] - t1[0][i] for i in range(3)] + w1 = [t1[2][i] - t1[0][i] for i in range(3)] + v2 = [t2[1][i] - t2[0][i] for i in range(3)] + w2 = [t2[2][i] - t2[0][i] for i in range(3)] + n1 = ( # surface normal for t1 + (v1[1] * w1[2]) - (v1[2] * w1[1]), + (v1[2] * w1[0]) - (v1[0] * w1[2]), + (v1[0] * w1[1]) - (v1[1] * w1[0]), + ) + n2 = ( # surface normal for t2 + (v2[1] * w2[2]) - (v2[2] * w2[1]), + (v2[2] * w2[0]) - (v2[0] * w2[2]), + (v2[0] * w2[1]) - (v2[1] * w2[0]), + ) + try: + angle = (n1[0] * n2[0] + n1[1] * n2[1] + n1[2] * n2[2]) / sqrt( + (n1[0] ** 2 + n1[1] ** 2 + n1[2] ** 2) + * (n2[0] ** 2 + n2[1] ** 2 + n2[2] ** 2) ) - triangles[i] = None - - triangles.extend(new_triangles) - triangles = [t for t in triangles if t is not None] - - # add the mesh - mesh_points = [] - if mesh == "System`Full": - for xi in range(plotpoints[0] + 1): - xval = xstart + xi / numx * (xstop - xstart) - mesh_row = [] - for yi in range(plotpoints[1] + 1): - yval = ystart + yi / numy * (ystop - ystart) - z = stored[(xval, yval)] - mesh_row.append((xval, yval, z)) - mesh_points.append(mesh_row) - - for yi in range(plotpoints[1] + 1): - yval = ystart + yi / numy * (ystop - ystart) - mesh_col = [] - for xi in range(plotpoints[0] + 1): - xval = xstart + xi / numx * (xstop - xstart) - z = stored[(xval, yval)] - mesh_col.append((xval, yval, z)) - mesh_points.append(mesh_col) - - # handle edge subdivisions - made_changes = True - while made_changes: - made_changes = False - for mesh_line in mesh_points: - i = 0 - while i < len(mesh_line) - 1: - x1, y1, v1 = mesh_line[i] - x2, y2, v2 = mesh_line[i + 1] - key = ( + except ZeroDivisionError: + angle = 0.0 + if abs(angle) < ang_thresh: + for i, t in ((i1, t1), (i2, t2)): + # subdivide + x1, y1 = t[0][0], t[0][1] + x2, y2 = t[1][0], t[1][1] + x3, y3 = t[2][0], t[2][1] + x4, y4 = 0.5 * (x1 + x2), 0.5 * (y1 + y2) + x5, y5 = 0.5 * (x2 + x3), 0.5 * (y2 + y3) + x6, y6 = 0.5 * (x1 + x3), 0.5 * (y1 + y3) + needs_removal.add(i) + split_edges.add( ((x1, y1), (x2, y2)) if (x2, y2) > (x1, y1) else ((x2, y2), (x1, y1)) ) - if key in split_edges: - x3 = 0.5 * (x1 + x2) - y3 = 0.5 * (y1 + y2) - v3 = stored[(x3, y3)] - mesh_line.insert(i + 1, (x3, y3, v3)) - made_changes = True - i += 1 - i += 1 - - # handle missing regions - old_meshpoints, mesh_points = mesh_points, [] - for mesh_line in old_meshpoints: - mesh_points.extend( - [ - sorted(g) - for k, g in itertools.groupby( - mesh_line, lambda x: x[2] is None + split_edges.add( + ((x2, y2), (x3, y3)) + if (x3, y3) > (x2, y2) + else ((x3, y3), (x2, y2)) + ) + split_edges.add( + ((x1, y1), (x3, y3)) + if (x3, y3) > (x1, y1) + else ((x3, y3), (x1, y1)) ) - ] + triangle(x1, y1, x4, y4, x6, y6, depth=depth) + triangle(x2, y2, x4, y4, x5, y5, depth=depth) + triangle(x3, y3, x5, y5, x6, y6, depth=depth) + triangle(x4, y4, x5, y5, x6, y6, depth=depth) + # remove subdivided triangles which have been divided + triangles = [t for i, t in enumerate(triangles) if i not in needs_removal] + + # fix up subdivided edges + # + # look at every triangle and see if its edges need updating. + # depending on how many edges require subdivision we proceede with + # one of two subdivision strategies + # + # TODO possible optimisation: don't look at every triangle again + made_changes = True + while made_changes: + made_changes = False + new_triangles = [] + for i, t in enumerate(triangles): + new_points = [] + if ((t[0][0], t[0][1]), (t[1][0], t[1][1])) in split_edges: + new_points.append([0, 1]) + if ((t[1][0], t[1][1]), (t[2][0], t[2][1])) in split_edges: + new_points.append([1, 2]) + if ((t[0][0], t[0][1]), (t[2][0], t[2][1])) in split_edges: + new_points.append([0, 2]) + + if len(new_points) == 0: + continue + made_changes = True + # 'triforce' subdivision + # 1 + # /\ + # 4 /__\ 6 + # /\ /\ + # /__\/__\ + # 2 5 3 + # if less than three edges require subdivision bisect them + # anyway but fake their values by averaging + x4 = 0.5 * (t[0][0] + t[1][0]) + y4 = 0.5 * (t[0][1] + t[1][1]) + v4 = stored.get((x4, y4), 0.5 * (t[0][2] + t[1][2])) + + x5 = 0.5 * (t[1][0] + t[2][0]) + y5 = 0.5 * (t[1][1] + t[2][1]) + v5 = stored.get((x5, y5), 0.5 * (t[1][2] + t[2][2])) + + x6 = 0.5 * (t[0][0] + t[2][0]) + y6 = 0.5 * (t[0][1] + t[2][1]) + v6 = stored.get((x6, y6), 0.5 * (t[0][2] + t[2][2])) + + if not (v4 is None or v6 is None): + new_triangles.append(sorted((t[0], (x4, y4, v4), (x6, y6, v6)))) + if not (v4 is None or v5 is None): + new_triangles.append(sorted((t[1], (x4, y4, v4), (x5, y5, v5)))) + if not (v5 is None or v6 is None): + new_triangles.append(sorted((t[2], (x5, y5, v5), (x6, y6, v6)))) + if not (v4 is None or v5 is None or v6 is None): + new_triangles.append( + sorted(((x4, y4, v4), (x5, y5, v5), (x6, y6, v6))) ) - mesh_points = [ - mesh_line - for mesh_line in mesh_points - if not any(x[2] is None for x in mesh_line) - ] - elif mesh == "System`All": - mesh_points = set() - for t in triangles: - mesh_points.add((t[0], t[1]) if t[1] > t[0] else (t[1], t[0])) - mesh_points.add((t[1], t[2]) if t[2] > t[1] else (t[2], t[1])) - mesh_points.add((t[0], t[2]) if t[2] > t[0] else (t[2], t[0])) - mesh_points = list(mesh_points) - - # find the max and min height - v_min = v_max = None - for t in triangles: - for tx, ty, v in t: - if v_min is None or v < v_min: - v_min = v - if v_max is None or v > v_max: - v_max = v - graphics.extend( - self.construct_graphics( - triangles, mesh_points, v_min, v_max, options, evaluation + triangles[i] = None + + triangles.extend(new_triangles) + triangles = [t for t in triangles if t is not None] + + # add the mesh + mesh_points = [] + if mesh == "System`Full": + for xi in range(plotpoints[0] + 1): + xval = xstart + xi / numx * (xstop - xstart) + mesh_row = [] + for yi in range(plotpoints[1] + 1): + yval = ystart + yi / numy * (ystop - ystart) + z = stored[(xval, yval)] + mesh_row.append((xval, yval, z)) + mesh_points.append(mesh_row) + + for yi in range(plotpoints[1] + 1): + yval = ystart + yi / numy * (ystop - ystart) + mesh_col = [] + for xi in range(plotpoints[0] + 1): + xval = xstart + xi / numx * (xstop - xstart) + z = stored[(xval, yval)] + mesh_col.append((xval, yval, z)) + mesh_points.append(mesh_col) + + # handle edge subdivisions + made_changes = True + while made_changes: + made_changes = False + for mesh_line in mesh_points: + i = 0 + while i < len(mesh_line) - 1: + x1, y1, v1 = mesh_line[i] + x2, y2, v2 = mesh_line[i + 1] + key = ( + ((x1, y1), (x2, y2)) + if (x2, y2) > (x1, y1) + else ((x2, y2), (x1, y1)) + ) + if key in split_edges: + x3 = 0.5 * (x1 + x2) + y3 = 0.5 * (y1 + y2) + v3 = stored[(x3, y3)] + mesh_line.insert(i + 1, (x3, y3, v3)) + made_changes = True + i += 1 + i += 1 + + # handle missing regions + old_meshpoints, mesh_points = mesh_points, [] + for mesh_line in old_meshpoints: + mesh_points.extend( + [ + sorted(g) + for k, g in itertools.groupby(mesh_line, lambda x: x[2] is None) + ] ) + mesh_points = [ + mesh_line + for mesh_line in mesh_points + if not any(x[2] is None for x in mesh_line) + ] + elif mesh == "System`All": + mesh_points = set() + for t in triangles: + mesh_points.add((t[0], t[1]) if t[1] > t[0] else (t[1], t[0])) + mesh_points.add((t[1], t[2]) if t[2] > t[1] else (t[2], t[1])) + mesh_points.add((t[0], t[2]) if t[2] > t[0] else (t[2], t[0])) + mesh_points = list(mesh_points) + + # find the max and min height + v_min = v_max = None + for t in triangles: + for tx, ty, v in t: + if v_min is None or v < v_min: + v_min = v + if v_max is None or v > v_max: + v_max = v + graphics.extend( + self.construct_graphics( + triangles, mesh_points, v_min, v_max, options, evaluation ) - return self.final_graphics(graphics, options) + ) + return self.final_graphics(graphics, options) def construct_density_plot( diff --git a/mathics/eval/files_io/files.py b/mathics/eval/files_io/files.py index eed451576..46f2706b5 100644 --- a/mathics/eval/files_io/files.py +++ b/mathics/eval/files_io/files.py @@ -6,20 +6,25 @@ import os from typing import Callable, Literal, Optional -from mathics_scanner import TranslateError -from mathics_scanner.errors import IncompleteSyntaxError, InvalidSyntaxError +from mathics_scanner.errors import ( + IncompleteSyntaxError, + InvalidSyntaxError, + SyntaxError, +) +from mathics_scanner.location import ContainerKind import mathics import mathics.core.parser import mathics.core.streams -from mathics.core.atoms import String +from mathics.core.atoms import Integer, String from mathics.core.builtin import MessageException from mathics.core.convert.expression import to_expression, to_mathics_list from mathics.core.convert.python import from_python from mathics.core.evaluation import Evaluation from mathics.core.expression import BaseElement, Expression -from mathics.core.parser import MathicsFileLineFeeder, MathicsMultiLineFeeder, parse -from mathics.core.streams import stream_manager +from mathics.core.parser import MathicsFileLineFeeder, MathicsMultiLineFeeder +from mathics.core.parser.util import parse_incrementally_by_line +from mathics.core.streams import path_search, stream_manager from mathics.core.symbols import Symbol, SymbolNull from mathics.core.systemsymbols import ( SymbolEndOfFile, @@ -148,7 +153,7 @@ def eval_Get( # Note: we use mathics.core.parser.parse # so that tracing/debugging can intercept parse() query = mathics.core.parser.parse(definitions, feeder) - except TranslateError: + except SyntaxError: return SymbolNull finally: feeder.send_messages(evaluation) @@ -169,6 +174,42 @@ def eval_Get( return result +def eval_Open( + name: String, + mode: str, + stream_type, + encoding: Optional[str], + evaluation: Evaluation, +): + path = name.value + tmp, is_temporary_file = path_search(path) + if tmp is None: + if mode in ["r", "rb"]: + evaluation.message("General", "noopen", name) + return + else: + path = tmp + + try: + opener = MathicsOpen( + path, + mode=mode, + name=name.value, + encoding=encoding, + is_temporary_file=is_temporary_file, + ) + opener.__enter__(is_temporary_file=is_temporary_file) + n = opener.n + except IOError: + evaluation.message("General", "noopen", name) + return + except MessageException as e: + e.message(evaluation) + return + + return Expression(Symbol(stream_type), name, Integer(n)) + + def eval_Read( name: str, n: int, types: tuple, stream, evaluation: Evaluation, options: dict ): @@ -228,14 +269,20 @@ def eval_Read( result.append(tmp) elif typ in (SymbolExpression, SymbolHoldExpression): tmp = next(read_record) + assert isinstance(tmp, str) while True: try: - feeder = MathicsMultiLineFeeder(tmp) - expr = parse(evaluation.definitions, feeder) + feeder = MathicsMultiLineFeeder( + tmp, "", ContainerKind.STREAM + ) + expr = parse_incrementally_by_line( + evaluation.definitions, feeder + ) break except (IncompleteSyntaxError, InvalidSyntaxError): try: nextline = next(read_record) + assert isinstance(nextline, str) tmp = tmp + "\n" + nextline except EOFError: expr = SymbolEndOfFile diff --git a/mathics/eval/files_io/read.py b/mathics/eval/files_io/read.py index dcb69d21c..c76d16584 100644 --- a/mathics/eval/files_io/read.py +++ b/mathics/eval/files_io/read.py @@ -67,11 +67,11 @@ def __init__( # We should not specify an encoding for a binary mode encoding = None elif encoding is None: - raise MessageException("General", "charcode", self.encoding) + raise MessageException("General", "charcode", encoding) self.encoding = encoding if name is None: name = path - super().__init__(name, mode=mode, path=path, encoding=self.encoding) + super().__init__(name, mode=mode, path=path, encoding=encoding) self.is_temporary_file = is_temporary_file # The following are set in __enter__ and __exit__ @@ -168,7 +168,7 @@ def parse_read_options(options) -> dict: record_separators = options["System`RecordSeparators"].to_python( string_quotes=False ) - assert isinstance(record_separators, list) + assert isinstance(record_separators, (list, tuple)) # assert all( # isinstance(s, str) and s[0] == s[-1] == '"' for s in record_separators # ) @@ -180,7 +180,7 @@ def parse_read_options(options) -> dict: word_separators = options["System`WordSeparators"].to_python( string_quotes=False ) - assert isinstance(word_separators, list) + assert isinstance(word_separators, (list, tuple)) result["WordSeparators"] = word_separators # NullRecords @@ -308,7 +308,7 @@ def read_check_options(options: dict, evaluation: Evaluation) -> Optional[dict]: record_separators = options["System`RecordSeparators"].to_python( string_quotes=False ) - assert isinstance(record_separators, list) + assert isinstance(record_separators, (list, tuple)) result["RecordSeparators"] = record_separators # WordSeparators @@ -316,7 +316,7 @@ def read_check_options(options: dict, evaluation: Evaluation) -> Optional[dict]: word_separators = options["System`WordSeparators"].to_python( string_quotes=False ) - assert isinstance(word_separators, list) + assert isinstance(word_separators, (list, tuple)) result["WordSeparators"] = word_separators # NullRecords @@ -334,7 +334,9 @@ def read_check_options(options: dict, evaluation: Evaluation) -> Optional[dict]: # TokenWords if "System`TokenWords" in keys: token_words = options["System`TokenWords"].to_python(string_quotes=False) - if not (isinstance(token_words, list) or isinstance(token_words, String)): + if not ( + isinstance(token_words, (list, tuple)) or isinstance(token_words, String) + ): evaluation.message("ReadList", "opstl", token_words) return None result["TokenWords"] = token_words @@ -344,7 +346,7 @@ def read_check_options(options: dict, evaluation: Evaluation) -> Optional[dict]: def read_get_separators( options, evaluation: Evaluation -) -> Optional[Tuple[dict, dict, dict]]: +) -> Optional[Tuple[list, list, list]]: """Get record and word separators from apply "options".""" # Options # TODO Implement extra options @@ -357,7 +359,7 @@ def read_get_separators( token_words = py_options.get("TokenWords", {}) word_separators = py_options["WordSeparators"] - return record_separators, token_words, word_separators + return list(record_separators), list(token_words), list(word_separators) def read_from_stream( diff --git a/mathics/eval/tensors.py b/mathics/eval/tensors.py index a579fa386..f3fd47ac7 100644 --- a/mathics/eval/tensors.py +++ b/mathics/eval/tensors.py @@ -1,324 +1,352 @@ -from typing import Union - -from sympy.combinatorics import Permutation -from sympy.utilities.iterables import permutations - -from mathics.core.atoms import Integer, Integer0, Integer1, String -from mathics.core.convert.python import from_python -from mathics.core.evaluation import Evaluation -from mathics.core.expression import BaseElement, Expression -from mathics.core.list import ListExpression -from mathics.core.symbols import ( - Atom, - Symbol, - SymbolFalse, - SymbolList, - SymbolTimes, - SymbolTrue, -) -from mathics.core.systemsymbols import ( - SymbolAutomatic, - SymbolInner, - SymbolNormal, - SymbolOuter, - SymbolRule, - SymbolSparseArray, -) -from mathics.eval.parts import get_part - - -def get_default_distance(p): - if all(q.is_numeric() for q in p): - return Symbol("SquaredEuclideanDistance") - elif all(q.get_head_name() == "System`List" for q in p): - dimensions = [get_dimensions(q) for q in p] - if len(dimensions) < 1: - return None - d0 = dimensions[0] - if not all(d == d0 for d in dimensions[1:]): - return None - if len(dimensions[0]) == 1: # vectors? - - def is_boolean(x): - return x.get_head_name() == "System`Symbol" and x in ( - SymbolTrue, - SymbolFalse, - ) - - if all(all(is_boolean(e) for e in q.elements) for q in p): - return Symbol("JaccardDissimilarity") - return Symbol("SquaredEuclideanDistance") - elif all(isinstance(q, String) for q in p): - return Symbol("EditDistance") - else: - from mathics.builtin.colors.color_directives import expression_to_color - - if all(expression_to_color(q) is not None for q in p): - return Symbol("ColorDistance") - - return None - - -def get_dimensions(expr, head=None): - if isinstance(expr, Atom): - return [] - else: - if head is not None and not expr.head.sameQ(head): - return [] - sub_dim = None - sub = [] - for element in expr.elements: - sub = get_dimensions(element, expr.head) - if sub_dim is None: - sub_dim = sub - else: - if sub_dim != sub: - sub = [] - break - return [len(expr.elements)] + sub - - -def to_std_sparse_array(sparse_array, evaluation: Evaluation): - "Get a SparseArray equivalent to input with default value 0." - - if sparse_array.elements[2] == Integer0: - return sparse_array - else: - return Expression( - SymbolSparseArray, Expression(SymbolNormal, sparse_array) - ).evaluate(evaluation) - - -def construct_outer(lists, current, const_etc: tuple) -> Union[list, BaseElement]: - """ - Recursively unpacks lists to construct outer product. - ------------------------------------ - - Unlike direct products, outer (tensor) products require traversing the - lowest level of each list, hence we recursively unpacking lists until - the lowest level is reached. - - Parameters: - - ``item``: the current item to be unpacked (if not at lowest level), - or joined to current (if at lowest level) - - ``rest_lists``: the rest of lists to be unpacked - - ``current``: the current lowest level elements - - ``level``: the current level (unused yet, will be used in - ``Outer[f_, lists__, n_]`` in the future) - - ``const_etc``: a tuple of functions used in unpacking, remains constant - throughout the recursion. - - Format of ``const_etc``: - - ``` - ( - cond_next_list, # return True/False to unpack the next list/this list at next level - get_elements, # get elements of list, tuple, ListExpression, etc. - apply_head, # e.g. lambda elements: Expression(head, *elements) - apply_f, # e.g. lambda current: Expression(f, *current) - join_elem, # join current lowest level elements (i.e. current) with a new one - if_flattened, # True for result as flattened list, False for result as nested list - evaluation, # evaluation: Evaluation - ) - ``` - - For those unfamiliar with ``construct_outer``, ``ConstructOuterTest`` - in ``test/eval/test_tensors.py`` provides a detailed introduction and - several good examples. - """ - ( - cond_next_list, # return True when the next list should be unpacked - get_elements, # get elements of list, tuple, ListExpression, etc. - apply_head, # e.g. lambda elements: Expression(head, *elements) - apply_f, # e.g. lambda current: Expression(f, *current) - join_elem, # join current lowest level elements (i.e. current) with a new one - if_flatten, # True for result as flattened list ({a,b,c,d}), False for result as nested list ({{a,b},{c,d}}) - evaluation, # evaluation: Evaluation - ) = const_etc - - _apply_f = (lambda current: (apply_f(current),)) if if_flatten else apply_f - - # Recursive step of unpacking - def _unpack_outer( - item, rest_lists, current, level: int - ) -> Union[list, BaseElement]: - evaluation.check_stopped() - if cond_next_list(item, level): # unpack next list - if rest_lists: - return _unpack_outer( - rest_lists[0], rest_lists[1:], join_elem(current, item), 1 - ) # unpacking of a list always start from level 1 - else: - return _apply_f(join_elem(current, item)) - else: # unpack this list at next level - elements = [] - action = elements.extend if if_flatten else elements.append - # elements.extend flattens the result as list instead of as ListExpression - for element in get_elements(item): - action(_unpack_outer(element, rest_lists, current, level + 1)) - return apply_head(elements) - - return _unpack_outer(lists[0], lists[1:], current, 1) - - -def eval_Inner(f, list1, list2, g, evaluation: Evaluation): - "Evaluates recursively the inner product of list1 and list2" - - m = get_dimensions(list1) - n = get_dimensions(list2) - - if not m or not n: - evaluation.message( - "Inner", "normal", Integer1, Expression(SymbolInner, list1, list2) - ) - return - if list1.get_head() != list2.get_head(): - evaluation.message("Inner", "heads", list1.get_head(), list2.get_head()) - return - if m[-1] != n[0]: - evaluation.message("Inner", "incom", m[-1], len(m), list1, n[0], list2) - return - - head = list1.get_head() - inner_dim = n[0] - - def rec(i_cur, j_cur, i_rest, j_rest): - evaluation.check_stopped() - if i_rest: - elements = [] - for i in range(1, i_rest[0] + 1): - elements.append(rec(i_cur + [i], j_cur, i_rest[1:], j_rest)) - return Expression(head, *elements) - elif j_rest: - elements = [] - for j in range(1, j_rest[0] + 1): - elements.append(rec(i_cur, j_cur + [j], i_rest, j_rest[1:])) - return Expression(head, *elements) - else: - - def summand(i): - part1 = get_part(list1, i_cur + [i]) - part2 = get_part(list2, [i] + j_cur) - return Expression(f, part1, part2) - - part = Expression(g, *[summand(i) for i in range(1, inner_dim + 1)]) - # cur_expr.elements.append(part) - return part - - return rec([], [], m[:-1], n[1:]) - - -def eval_Outer(f, lists, evaluation: Evaluation): - "Evaluates recursively the outer product of lists" - - if isinstance(lists, Atom): - evaluation.message("Outer", "normal", Integer1, Expression(SymbolOuter, lists)) - return - - # If f=!=Times, or lists contain both SparseArray and List, then convert all SparseArrays to Lists - lists = lists.get_sequence() - head = None - sparse_to_list = f != SymbolTimes - contain_sparse = False - contain_list = False - new_lists = [] - for _list in lists: - if _list.head.sameQ(SymbolSparseArray): - contain_sparse = True - if _list.head.sameQ(SymbolList): - contain_list = True - sparse_to_list = sparse_to_list or (contain_sparse and contain_list) - if sparse_to_list: - break - for i, _list in enumerate(lists): - if isinstance(_list, Atom): - evaluation.message( - "Outer", "normal", Integer(i + 1), Expression(SymbolOuter, lists) - ) - return - if sparse_to_list: - if _list.head.sameQ(SymbolSparseArray): - _list = Expression(SymbolNormal, _list).evaluate(evaluation) - new_lists.append(_list) - if head is None: - head = _list.head - elif not _list.head.sameQ(head): - evaluation.message("Outer", "heads", head, _list.head) - return - - if sparse_to_list: - lists = new_lists - - # head != SparseArray - if not head.sameQ(SymbolSparseArray): - - def cond_next_list(item, level) -> bool: - return isinstance(item, Atom) or not item.head.sameQ(head) - - etc = ( - cond_next_list, - (lambda item: item.elements), # get_elements - (lambda elements: Expression(head, *elements)), # apply_head - (lambda current: Expression(f, *current)), # apply_f - (lambda current, item: current + (item,)), # join_elem - False, # if_flatten - evaluation, - ) - return construct_outer(lists, (), etc) - - # head == SparseArray - dims = [] - val = Integer1 - for _list in lists: - _dims, _val = _list.elements[1:3] - dims.extend(_dims) - val *= _val - dims = ListExpression(*dims) - - def sparse_cond_next_list(item, level) -> bool: - return isinstance(item, Atom) or not item.head.sameQ(head) - - def sparse_apply_Rule(current) -> Expression: - return Expression(SymbolRule, ListExpression(*current[0]), current[1]) - - def sparse_join_elem(current, item) -> tuple: - return (current[0] + item.elements[0].elements, current[1] * item.elements[1]) - - etc = ( - sparse_cond_next_list, - (lambda item: to_std_sparse_array(item, evaluation).elements[3].elements), - (lambda elements: elements), # apply_head - sparse_apply_Rule, # apply_f - sparse_join_elem, # join_elem - True, # if_flatten - evaluation, - ) - return Expression( - SymbolSparseArray, - SymbolAutomatic, - dims, - val, - ListExpression(*construct_outer(lists, ((), Integer1), etc)), - ) - - -def eval_LeviCivitaTensor(d, type): - "Evaluates Levi-Civita tensor of rank d" - - if isinstance(d, Integer) and type == SymbolSparseArray: - d = d.get_int_value() - perms = list(permutations(list(range(1, d + 1)))) - rules = [ - Expression( - SymbolRule, - from_python(p), - from_python(Permutation.from_sequence(p).signature()), - ) - for p in perms - ] - return Expression(SymbolSparseArray, from_python(rules), from_python([d] * d)) +from typing import Union + +from sympy.combinatorics import Permutation +from sympy.utilities.iterables import permutations + +from mathics.core.atoms import Integer, Integer0, Integer1, String +from mathics.core.convert.python import from_python +from mathics.core.evaluation import Evaluation +from mathics.core.expression import BaseElement, Expression +from mathics.core.list import ListExpression +from mathics.core.symbols import ( + Atom, + Symbol, + SymbolFalse, + SymbolList, + SymbolTimes, + SymbolTrue, +) +from mathics.core.systemsymbols import ( + SymbolAutomatic, + SymbolInner, + SymbolNormal, + SymbolOuter, + SymbolRule, + SymbolSparseArray, +) +from mathics.eval.parts import get_part + + +def get_default_distance(p): + if all(q.is_numeric() for q in p): + return Symbol("SquaredEuclideanDistance") + elif all(q.get_head_name() == "System`List" for q in p): + dimensions = [get_dimensions(q) for q in p] + if len(dimensions) < 1: + return None + d0 = dimensions[0] + if not all(d == d0 for d in dimensions[1:]): + return None + if len(dimensions[0]) == 1: # vectors? + + def is_boolean(x): + return x.get_head_name() == "System`Symbol" and x in ( + SymbolTrue, + SymbolFalse, + ) + + if all(all(is_boolean(e) for e in q.elements) for q in p): + return Symbol("JaccardDissimilarity") + return Symbol("SquaredEuclideanDistance") + elif all(isinstance(q, String) for q in p): + return Symbol("EditDistance") + else: + from mathics.builtin.colors.color_directives import expression_to_color + + if all(expression_to_color(q) is not None for q in p): + return Symbol("ColorDistance") + + return None + + +def get_dimensions(expr, head=None): + if isinstance(expr, Atom): + return [] + else: + if head is not None and not expr.head.sameQ(head): + return [] + sub_dim = None + sub = [] + for element in expr.elements: + sub = get_dimensions(element, expr.head) + if sub_dim is None: + sub_dim = sub + else: + if sub_dim != sub: + sub = [] + break + return [len(expr.elements)] + sub + + +def to_std_sparse_array(sparse_array, evaluation: Evaluation): + "Get a SparseArray equivalent to input with default value 0." + + if sparse_array.elements[2] == Integer0: + return sparse_array + else: + return Expression( + SymbolSparseArray, Expression(SymbolNormal, sparse_array) + ).evaluate(evaluation) + + +def construct_outer(lists, current, const_etc: tuple) -> Union[list, BaseElement]: + """ + Recursively unpacks lists to construct outer product. + ------------------------------------ + + Unlike direct products, outer (tensor) products require traversing the + lowest level of each list, hence we recursively unpacking lists until + the lowest level is reached. + + Parameters: + + ``item``: the current item to be unpacked (if not at lowest level), + or joined to current (if at lowest level) + + ``rest_lists``: the rest of lists to be unpacked + + ``current``: the current lowest level elements + + ``level``: the current level (unused yet, will be used in + ``Outer[f_, lists__, n_]`` in the future) + + ``const_etc``: a tuple of functions used in unpacking, remains constant + throughout the recursion. + + Format of ``const_etc``: + + ``` + ( + cond_next_list, # return True/False to unpack the next list/this list at next level + get_elements, # get elements of list, tuple, ListExpression, etc. + apply_head, # e.g. lambda elements: Expression(head, *elements) + apply_f, # e.g. lambda current: Expression(f, *current) + join_elem, # join current lowest level elements (i.e. current) with a new one + if_flattened, # True for result as flattened list, False for result as nested list + evaluation, # evaluation: Evaluation + ) + ``` + + For those unfamiliar with ``construct_outer``, ``ConstructOuterTest`` + in ``test/eval/test_tensors.py`` provides a detailed introduction and + several good examples. + """ + ( + cond_next_list, # return True when the next list should be unpacked + get_elements, # get elements of list, tuple, ListExpression, etc. + apply_head, # e.g. lambda elements: Expression(head, *elements) + apply_f, # e.g. lambda current: Expression(f, *current) + join_elem, # join current lowest level elements (i.e. current) with a new one + if_flatten, # True for result as flattened list ({a,b,c,d}), False for result as nested list ({{a,b},{c,d}}) + evaluation, # evaluation: Evaluation + ) = const_etc + + _apply_f = (lambda current: (apply_f(current),)) if if_flatten else apply_f + + # Recursive step of unpacking + def _unpack_outer( + item, rest_lists, current, level: int + ) -> Union[list, BaseElement]: + evaluation.check_stopped() + if cond_next_list(item, level): # unpack next list + if rest_lists: + return _unpack_outer( + rest_lists[0], rest_lists[1:], join_elem(current, item), 1 + ) # unpacking of a list always start from level 1 + else: + return _apply_f(join_elem(current, item)) + else: # unpack this list at next level + elements = [] + action = elements.extend if if_flatten else elements.append + # elements.extend flattens the result as list instead of as ListExpression + for element in get_elements(item): + action(_unpack_outer(element, rest_lists, current, level + 1)) + return apply_head(elements) + + return _unpack_outer(lists[0], lists[1:], current, 1) + + +def eval_Inner(f, list1, list2, g, evaluation: Evaluation): + "Evaluates recursively the inner product of list1 and list2" + + m = get_dimensions(list1) + n = get_dimensions(list2) + + if not m or not n: + evaluation.message( + "Inner", "normal", Integer1, Expression(SymbolInner, list1, list2) + ) + return + if list1.get_head() != list2.get_head(): + evaluation.message("Inner", "heads", list1.get_head(), list2.get_head()) + return + if m[-1] != n[0]: + evaluation.message("Inner", "incom", m[-1], len(m), list1, n[0], list2) + return + + head = list1.get_head() + inner_dim = n[0] + + def rec(i_cur, j_cur, i_rest, j_rest): + evaluation.check_stopped() + if i_rest: + elements = [] + for i in range(1, i_rest[0] + 1): + elements.append(rec(i_cur + [i], j_cur, i_rest[1:], j_rest)) + return Expression(head, *elements) + elif j_rest: + elements = [] + for j in range(1, j_rest[0] + 1): + elements.append(rec(i_cur, j_cur + [j], i_rest, j_rest[1:])) + return Expression(head, *elements) + else: + + def summand(i): + part1 = get_part(list1, i_cur + [i]) + part2 = get_part(list2, [i] + j_cur) + return Expression(f, part1, part2) + + part = Expression(g, *[summand(i) for i in range(1, inner_dim + 1)]) + # cur_expr.elements.append(part) + return part + + return rec([], [], m[:-1], n[1:]) + + +def eval_Outer(f, lists, evaluation: Evaluation): + "Evaluates recursively the outer product of lists" + + if isinstance(lists, Atom): + evaluation.message("Outer", "normal", Integer1, Expression(SymbolOuter, lists)) + return + + # If f=!=Times, or lists contain both SparseArray and List, then convert all SparseArrays to Lists + lists = lists.get_sequence() + head = None + sparse_to_list = f != SymbolTimes + contain_sparse = False + contain_list = False + new_lists = [] + for _list in lists: + if _list.head.sameQ(SymbolSparseArray): + contain_sparse = True + if _list.head.sameQ(SymbolList): + contain_list = True + sparse_to_list = sparse_to_list or (contain_sparse and contain_list) + if sparse_to_list: + break + for i, _list in enumerate(lists): + if isinstance(_list, Atom): + evaluation.message( + "Outer", "normal", Integer(i + 1), Expression(SymbolOuter, lists) + ) + return + if sparse_to_list: + if _list.head.sameQ(SymbolSparseArray): + _list = Expression(SymbolNormal, _list).evaluate(evaluation) + new_lists.append(_list) + if head is None: + head = _list.head + elif not _list.head.sameQ(head): + evaluation.message("Outer", "heads", head, _list.head) + return + + if sparse_to_list: + lists = new_lists + + # head != SparseArray + if not head.sameQ(SymbolSparseArray): + + def cond_next_list(item, level) -> bool: + return isinstance(item, Atom) or not item.head.sameQ(head) + + etc = ( + cond_next_list, + (lambda item: item.elements), # get_elements + (lambda elements: Expression(head, *elements)), # apply_head + (lambda current: Expression(f, *current)), # apply_f + (lambda current, item: current + (item,)), # join_elem + False, # if_flatten + evaluation, + ) + return construct_outer(lists, (), etc) + + # head == SparseArray + dims = [] + val = Integer1 + for _list in lists: + _dims, _val = _list.elements[1:3] + dims.extend(_dims) + val *= _val + dims = ListExpression(*dims) + + def sparse_cond_next_list(item, level) -> bool: + return isinstance(item, Atom) or not item.head.sameQ(head) + + def sparse_apply_Rule(current) -> Expression: + return Expression(SymbolRule, ListExpression(*current[0]), current[1]) + + def sparse_join_elem(current, item) -> tuple: + return (current[0] + item.elements[0].elements, current[1] * item.elements[1]) + + etc = ( + sparse_cond_next_list, + (lambda item: to_std_sparse_array(item, evaluation).elements[3].elements), + (lambda elements: elements), # apply_head + sparse_apply_Rule, # apply_f + sparse_join_elem, # join_elem + True, # if_flatten + evaluation, + ) + return Expression( + SymbolSparseArray, + SymbolAutomatic, + dims, + val, + ListExpression(*construct_outer(lists, ((), Integer1), etc)), + ) + + +def eval_LeviCivitaTensor(d, type): + "Evaluates Levi-Civita tensor of rank d" + + if isinstance(d, Integer) and type == SymbolSparseArray: + d = d.get_int_value() + perms = list(permutations(list(range(1, d + 1)))) + rules = [ + Expression( + SymbolRule, + from_python(p), + from_python(Permutation.from_sequence(p).signature()), + ) + for p in perms + ] + return Expression(SymbolSparseArray, from_python(rules), from_python([d] * d)) + + +def eval_Transpose2D(m) -> Expression: + "Transpose of a 2D matrix" + + # Below is some skeletal code that might get used in the future. + # NumPy handles complex numbers differently. + # There is a bigger problem in handling literals and + # value. + + # if m.is_literal: + # m.numpy = np.array(m.value) + # transposed = np.transpose(m.numpy) + # transposed_list_of_lists = transposed.tolist() + # mathics_transposed = ListExpression( + # *[to_mathics_list(*row) for row in transposed_list_of_lists] + # ) + # mathics_transposed.numpy = transposed + # return mathics_transposed + + transposed_list_of_lists = [] + for row_index, row in enumerate(m.elements): + for col_index, item in enumerate(row.elements): + if row_index == 0: + transposed_list_of_lists.append([item]) + else: + transposed_list_of_lists[col_index].append(item) + return ListExpression(*[ListExpression(*row) for row in transposed_list_of_lists]) diff --git a/mathics/eval/tracing.py b/mathics/eval/tracing.py index 3333831ce..d458f41f4 100644 --- a/mathics/eval/tracing.py +++ b/mathics/eval/tracing.py @@ -17,42 +17,88 @@ hook_exit_fn: Optional[Callable] = None +def is_performing_rewrite(func) -> bool: + """ " + Returns true if we are in the rewrite expression phase + as opposed to the apply-function/evaluation phase of + evaluation. The way we determine this is highly specific + to the Mathics3 code as it stands right now. So this + code is highly fragile and can change when the + evaluation code changes. However encapsulating this + in a function helps narrows the fragility to one place. + """ + return hasattr(func, "__name__") and func.__name__ == "rewrite_apply_eval_step" + + +def skip_trivial_evaluation(expr, status: str, orig_expr=None) -> bool: + """ + Look for uninteresting evaluations that we should avoid showing + printing tracing status or stopping in a debugger. + + This includes things like: + * the evaluation is a literal that evaluates to the same thing, + * evaluating a Symbol which the Symbol. + * Showing the return value of a ListExpression literal + * Evaluating Pattern[] which define a pattern. + """ + from mathics.core.expression import Expression + from mathics.core.symbols import Symbol, SymbolConstant + from mathics.core.systemsymbols import SymbolBlank, SymbolPattern + + if isinstance(expr, tuple): + expr = expr[0] + + if isinstance(expr, Expression): + if expr.head in (SymbolPattern, SymbolBlank): + return True + + if status == "Returning": + if ( + hasattr(expr, "is_literal") + and expr.is_literal + and hasattr(orig_expr, "is_literal") + and orig_expr.is_literal + ): + return True + pass + if isinstance(expr, Symbol) and not isinstance(expr, SymbolConstant): + # Evaluation of a symbol, like Plus isn't that interesting. + # Right now, SymbolConstant are not literals. If this + # changes, we don't need this clause. + return True + + else: + # Status != "Returning", i.e. executing + + if isinstance(expr, Symbol): + # Evaluation of a symbol, like Plus isn't that interesting + return True + + if orig_expr == expr: + # If the two expressions are the same, there is no point in + # repeating the output. + return True + + return False + + def print_evaluate(expr, evaluation, status: str, fn: Callable, orig_expr=None): """ Called from a decorated Python @trace_evaluate .evaluate() - method when TraceActivate["evaluate" -> True] + method when TraceActivate["evaluate" -> True] or + running TraceEvaluation. """ if evaluation.definitions.timing_trace_evaluation: evaluation.print_out(time.time() - evaluation.start_time) - # Test and dispose of various situations where showing information - # is pretty useless: evaluating a Symbol is the Symbol. - # Showing the return value of a ListExpression literal is - # also useless. - from mathics.core.symbols import Symbol, SymbolConstant - - if isinstance(expr, Symbol) and not isinstance(expr, SymbolConstant): - return - - if ( - status == "Returning" - and hasattr(expr, "is_literal") - and expr.is_literal - and hasattr(orig_expr, "is_literal") - and orig_expr.is_literal - ): - return - - if orig_expr == expr: - # If the two expressions are the same, there is no point in - # repeating the output. + if skip_trivial_evaluation(expr, status, orig_expr): return indents = " " * evaluation.recursion_depth if orig_expr is not None: - if fn.__name__ == "rewrite_apply_eval_step": + if is_performing_rewrite(fn): assert isinstance(expr, tuple) if orig_expr != expr[0]: if status == "Returning": @@ -69,9 +115,12 @@ def print_evaluate(expr, evaluation, status: str, fn: Callable, orig_expr=None): f"{indents}{status}: {expr[0]}" + arrow + str(expr) ) else: + if status == "Returning" and isinstance(expr, tuple): + status = "Evaluating/Replacing" + expr = expr[0] evaluation.print_out(f"{indents}{status}: {orig_expr} = " + str(expr)) - elif fn.__name__ != "rewrite_apply_eval_step": + elif not is_performing_rewrite(fn): evaluation.print_out(f"{indents}{status}: {expr}") return @@ -92,7 +141,11 @@ def trace_evaluate(func: Callable) -> Callable: def wrapper(expr, evaluation) -> Any: from mathics.core.symbols import SymbolConstant - skip_call = False + # trace_evaluate_action allows for trace_evaluate_on_call() + # and trace_evaluate_return() to set the value of the + # expression instead of calling the function or replacing + # of return value of a Mathics3 function call. + trace_evaluate_action: Optional[Any] = None result = None was_boxing = evaluation.is_boxing if ( @@ -102,14 +155,35 @@ def wrapper(expr, evaluation) -> Any: ): # We may use boxing in print_evaluate_fn(). So turn off # boxing temporarily. + phase_name = "Rewriting" if is_performing_rewrite(func) else "Evaluating" evaluation.is_boxing = True - skip_call = trace_evaluate_on_call(expr, evaluation, "Evaluating", func) + trace_evaluate_action = trace_evaluate_on_call( + expr, evaluation, phase_name, func + ) evaluation.is_boxing = was_boxing - if not skip_call: + if trace_evaluate_action is None: result = func(expr, evaluation) if trace_evaluate_on_return is not None and not was_boxing: - trace_evaluate_on_return(result, evaluation, "Returning", func, expr) + trace_evaluate_action = trace_evaluate_on_return( + expr=result, + evaluation=evaluation, + status="Returning", + fn=expr, + orig_expr=expr, + ) + if trace_evaluate_action is not None: + result = ( + (trace_evaluate_action, False) + if is_performing_rewrite(func) + else trace_evaluate_action + ) evaluation.is_boxing = was_boxing + else: + result = ( + (trace_evaluate_action, False) + if is_performing_rewrite(func) + else trace_evaluate_action + ) return result return wrapper diff --git a/mathics/format/asy.py b/mathics/format/asy.py index c055619c9..5c4603738 100644 --- a/mathics/format/asy.py +++ b/mathics/format/asy.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -Lower-level format of Mathics objects as Asymptote strings. +Lower-level format of Mathics objects as Asymptote Vector graphics strings. """ import re @@ -36,10 +36,6 @@ PointSize, RGBColor, ) - -INVERSE_POINT_FACTOR = 1 / DEFAULT_POINT_FACTOR - - from mathics.core.formatter import add_conversion_fn, lookup_method from mathics.format.asy_fns import ( asy_add_bezier_fn, @@ -49,6 +45,9 @@ asy_create_pens, asy_number, ) +from mathics.format.asy_polyhedra import HEDRON_NAME_MAP, unimplimented_polygon + +INVERSE_POINT_FACTOR = 1 / DEFAULT_POINT_FACTOR class _ASYTransform: @@ -97,7 +96,7 @@ def arcbox(self: _ArcBox, **options) -> str: # It is an empty circle return _roundbox(self) - x, y, rx, ry, sx, sy, ex, ey, large_arc = self._arc_params() + x, y, rx, ry, sx, sy, ex, ey, _ = self._arc_params() ry = max(ry, 0.1) # Avoid division by 0 yscale = ry / rx @@ -137,7 +136,7 @@ def create_arc_path(is_closed: bool, yscale: float) -> str: edge_opacity=edge_opacity_value, face_opacity=face_opacity_value, stroke_width=stroke_width, - is_face_element=self.face_element, + is_face_element=bool(self.face_element), ) command = "filldraw" if self.face_element else "draw" arc_path = create_arc_path(self.face_element or False, yscale) @@ -254,27 +253,34 @@ def cone3dbox(self: Cone3DBox, **options) -> str: opacity = self.face_opacity color_str = build_3d_pen_color(face_color, opacity) - # FIXME: currently always drawing around the axis X+Y - axes_point = (1, 1, 0) - asy = "// Cone3DBox\n" i = 0 while i < len(self.points) / 2: try: - point1 = self.points[i * 2].pos()[0] - point2 = self.points[i * 2 + 1].pos()[0] - - # Compute distance between start point and end point. - distance = ( - (point1[0] - point2[0]) ** 2 - + (point1[1] - point2[1]) ** 2 - + (point1[2] - point2[2]) ** 2 + # See https://tex.stackexchange.com/questions/736116/how-to-draw-the-base-geometrical-face-of-a-cone-surface-by-asymptote/736120#736120 + cone_center = self.points[i * 2].pos()[0] + cone_tip = self.points[i * 2 + 1].pos()[0] + if cone_center is None or cone_tip is None: + continue + + # Compute the cone's height : the distance between the center of the cone's base and the + # cone's tip. + cone_height = ( + (cone_center[0] - cone_tip[0]) ** 2 + + (cone_center[1] - cone_tip[1]) ** 2 + + (cone_center[2] - cone_tip[2]) ** 2 ) ** 0.5 - asy += ( - f"draw(surface(cone({tuple(point1)}, {self.radius}, {distance}, {axes_point})), {color_str});" - + "\n" - ) + asy += f""" + triple cone_center = {tuple(cone_center)}; + triple cone_tip = {tuple(cone_tip)}; + real cone_radius = {self.radius}; + real cone_height = {cone_height}; + + path3 cone_circle = circle(cone_center, cone_radius, cone_tip); + draw(surface(cone_circle), {color_str}); + draw(surface(cone(cone_center, cone_radius, cone_height, cone_tip)), {color_str}); + """ except: # noqa pass @@ -299,6 +305,9 @@ def cuboid3dbox(self: Cuboid3DBox, **options) -> str: point1 = self.points[i * 2].pos()[0] point2 = self.points[i * 2 + 1].pos()[0] + if point1 is None or point2 is None: + continue + asy += f""" draw(shift({point1[0]}, {point1[1]}, {point1[2]}) * scale( {point2[0] - point1[0]}, @@ -334,6 +343,10 @@ def cylinder3dbox(self: Cylinder3DBox, **options) -> str: try: point1 = self.points[i * 2].pos()[0] point2 = self.points[i * 2 + 1].pos()[0] + + if point1 is None or point2 is None: + continue + asy += f"real r={self.radius};\n" asy += f"triple A={tuple(point1)}, B={tuple(point2)};\n" asy += "real h=abs(A-B);\n" @@ -739,15 +752,10 @@ def uniform_polyhedron_3d_box(self: UniformPolyhedron3DBox, **options) -> str: face_color = self.face_color.to_js() if self.face_color else (1, 1, 1) opacity = self.face_opacity color_str = build_3d_pen_color(face_color, opacity) - - return ( - "// UniformPolyhedron3DBox\n // Still not really implemented. Draw a sphere instead\n" - + "\n".join( - "draw(surface(sphere({0}, {1})), {2});".format( - tuple(coord.pos()[0]), self.edge_length, color_str - ) - for coord in self.points - ) + render_fn = HEDRON_NAME_MAP.get(self.sub_type, unimplimented_polygon) + return f"// {self.sub_type}\n" + "\n".join( + render_fn(tuple(coord.pos()[0]), self.edge_length, color_str) + for coord in self.points ) diff --git a/mathics/format/asy_fns.py b/mathics/format/asy_fns.py index fbb7f74d6..38d8be189 100644 --- a/mathics/format/asy_fns.py +++ b/mathics/format/asy_fns.py @@ -51,7 +51,7 @@ def cubic(p0, p1, p2, p3): list(chain(p1, p2, p3)) ) - def quadratric(qp0, qp1, qp2): + def quadratic(qp0, qp1, qp2): # asymptote only supports cubic beziers, so we convert this quadratic # bezier to a cubic bezier, see http://fontforge.github.io/bezier.html @@ -75,7 +75,7 @@ def quadratric(qp0, qp1, qp2): def linear(p0, p1): return "--(%.5g,%.5g)" % p1 - forms = (linear, quadratric, cubic) + forms = (linear, quadratic, cubic) def path(max_degree, p): max_degree = min(max_degree, len(forms)) diff --git a/mathics/format/asy_polyhedra.py b/mathics/format/asy_polyhedra.py new file mode 100644 index 000000000..ba0f953eb --- /dev/null +++ b/mathics/format/asy_polyhedra.py @@ -0,0 +1,286 @@ +""" +Functions to draw regular polyhedra in Asymptote vector graphics +""" + +# FIXME: All of these regular polyhedra routine could be table driven +# by putting edge points, and paths into a table. +# The same is also true on the in the mathics-threejs-backend code. + +from typing import Callable, Dict + + +def cube(center: tuple, length: float, color_str: str) -> str: + """ + Return an asymptote program string to draw a cube at `center` + with length `length`. + """ + return f""" + real length={length}; + + triple center={center}; + real unit_corner = sqrt(3) / 4; + triple[] d; + d[0]=center + length*(unit_corner,unit_corner,unit_corner); + d[1]=center + length*(unit_corner,-unit_corner,unit_corner); + d[2]=center + length*(-unit_corner,-unit_corner,unit_corner); + d[3]=center + length*(-unit_corner,unit_corner,unit_corner); + d[4]=center + length*(-unit_corner,unit_corner,-unit_corner); + d[5]=center + length*(-unit_corner,-unit_corner,-unit_corner); + d[6]=center + length*(unit_corner,-unit_corner,-unit_corner); + d[7]=center + length*(unit_corner,unit_corner,-unit_corner); + + path3[] p; + p[0]=d[0]--d[1]--d[2]--d[3]--cycle; + p[1]=d[0]--d[3]--d[4]--d[7]--cycle; + p[2]=d[0]--d[1]--d[6]--d[7]--cycle; + p[3]=d[3]--d[4]--d[5]--d[2]--cycle; + p[4]=d[7]--d[6]--d[5]--d[4]--cycle; + p[5]=d[1]--d[2]--d[5]--d[6]--cycle; + + pen sides={color_str}; + + draw(surface(p[0]),sides); + draw(surface(p[1]),sides); + draw(surface(p[2]),sides); + draw(surface(p[3]),sides); + draw(surface(p[4]),sides); + draw(surface(p[5]),sides); + """ + + +def dodecahedron(center: tuple, length: float, color_str: str) -> str: + """ + Return an asymptote program string to draw a dodecahedron at `center` + with edge length `length`. + """ + return f""" + real phi=(sqrt(5)+1)/2; + real g=(phi-1)/2; + real s=1/2; + real a=sqrt(1-phi*phi/4-g*g)+phi/2; + + triple center={center}; + real length={length} / 2; + triple[] d; + d[0]=center + length*(phi/2,phi/2,phi/2); + d[1]=center + length*(-phi/2,phi/2,phi/2); + d[2]=center + length*(phi/2,-phi/2,phi/2); + d[3]=center + length*(phi/2,phi/2,-phi/2); + d[4]=center + length*(-phi/2,-phi/2,phi/2); + d[5]=center + length*(phi/2,-phi/2,-phi/2); + d[6]=center + length*(-phi/2,phi/2,-phi/2); + d[7]=center + length*(-phi/2,-phi/2,-phi/2); + + triple[] n; + n[0]=center + length*(0,s,a); + n[1]=center + length*(0,-s,a); + n[2]=center + length*(0,s,-a); + n[3]=center + length*(0,-s,-a); + n[4]=center + length*(s,a,0); + n[5]=center + length*(-s,a,0); + n[6]=center + length*(s,-a,0); + n[7]=center + length*(-s,-a,0); + n[8]=center + length*(a,0,s); + n[9]=center + length*(a,0,-s); + n[10]=center + length*(-a,0,s); + n[11]=center + length*(-a,0,-s); + + path3[] p; + p[0]=d[0]--n[0]--d[1]--n[5]--n[4]--cycle; + p[1]=n[0]--n[1]--d[2]--n[8]--d[0]--cycle; + p[2]=n[0]--n[1]--d[4]--n[10]--d[1]--cycle; + p[3]=d[0]--n[4]--d[3]--n[9]--n[8]--cycle; + p[4]=d[3]--n[4]--n[5]--d[6]--n[2]--cycle; + p[5]=d[6]--n[5]--d[1]--n[10]--n[11]--cycle; + p[6]=n[8]--n[9]--d[5]--n[6]--d[2]--cycle; + p[7]=n[10]--n[11]--d[7]--n[7]--d[4]--cycle; + p[8]=d[7]--n[11]--d[6]--n[2]--n[3]--cycle; + p[9]=n[3]--n[2]--d[3]--n[9]--d[5]--cycle; + p[10]=d[7]--n[7]--n[6]--d[5]--n[3]--cycle; + p[11]=n[6]--d[2]--n[1]--d[4]--n[7]--cycle; + + pen sides={color_str}; + + draw(surface(p[0]),sides); + draw(surface(p[1]),sides); + draw(surface(p[2]),sides); + draw(surface(p[3]),sides); + draw(surface(p[4]),sides); + draw(surface(p[5]),sides); + draw(surface(p[6]),sides); + draw(surface(p[7]),sides); + draw(surface(p[8]),sides); + draw(surface(p[9]),sides); + draw(surface(p[10]),sides); + draw(surface(p[11]),sides); + """ + + +# Loosely based on mathics-threejs-backend/src/primitives/uniformPolyhedron.js +def icosahedron(center: tuple, length: float, color_str: str) -> str: + """ + Return an asymptote program string to draw a icosahedron at `center` + with edge length `length`. + """ + return f""" + real v0 = 0.5576 * {length}; + real v1 = 0.9022 * {length}; + + triple center={center}; + triple[] d; + d[0]=center + (v0, v1, 0); + d[1]=center + (0, v0, v1); + d[2]=center + (-v0, v1, 0); + d[3]=center + (-v1, 0, -v0); + d[4]=center + (-v1, 0, v0); + d[5]=center + (0, v0, -v1); + d[6]=center + (0, -v0, -v1); + d[7]=center + (-v0, -v1, 0); + d[8]=center + (v0, -v1, 0); + d[9]=center + (0, -v0, v1); + d[10]=center + (v1, 0, v0); + d[11]=center + (v1, 0, -v0); + + path3[] p; + p[0]=d[0]--d[1]--d[2]--cycle; + p[1]=d[2]--d[1]--d[4]--cycle; + p[2]=d[2]--d[4]--d[3]--cycle; + p[3]=d[0]--d[2]--d[5]--cycle; + p[4]=d[2]--d[5]--d[3]--cycle; + p[5]=d[3]--d[5]--d[6]--cycle; + p[6]=d[3]--d[6]--d[7]--cycle; + p[7]=d[3]--d[4]--d[7]--cycle; + p[8]=d[1]--d[4]--d[9]--cycle; + p[9]=d[4]--d[7]--d[9]--cycle; + p[10]=d[0]--d[1]--d[10]--cycle; + p[11]=d[1]--d[9]--d[10]--cycle; + p[12]=d[7]--d[8]--d[9]--cycle; + p[13]=d[8]--d[9]--d[10]--cycle; + p[14]=d[6]--d[7]--d[8]--cycle; + p[15]=d[0]--d[5]--d[11]--cycle; + p[16]=d[0]--d[10]--d[11]--cycle; + p[17]=d[8]--d[10]--d[11]--cycle; + p[18]=d[5]--d[6]--d[11]--cycle; + p[19]=d[6]--d[8]--d[11]--cycle; + + pen sides={color_str}; + + // dot(d[0]); label("0", d[0]); + // dot(d[1]); label("1", d[1]); + // dot(d[2]); label("2", d[2]); + // dot(d[3]); label("3", d[3]); + // dot(d[4]); label("4", d[4]); + // dot(d[5]); label("5", d[5]); + // dot(d[6]); label("6", d[6]); + // dot(d[7]); label("7", d[7]); + // dot(d[8]); label("8", d[8]); + // dot(d[9]); label("9", d[9]); + // dot(d[10]); label("10", d[10]); + // dot(d[11]); label("11", d[11]); + + draw(surface(p[0]),sides); + draw(surface(p[1]),sides); + draw(surface(p[2]),sides); + draw(surface(p[3]),sides); + draw(surface(p[4]),sides); + draw(surface(p[5]),sides); + draw(surface(p[6]),sides); + draw(surface(p[7]),sides); + draw(surface(p[8]),sides); + draw(surface(p[9]),sides); + draw(surface(p[10]),sides); + draw(surface(p[11]),sides); + draw(surface(p[12]),sides); + draw(surface(p[13]),sides); + draw(surface(p[14]),sides); + draw(surface(p[15]),sides); + draw(surface(p[16]),sides); + draw(surface(p[17]),sides); + draw(surface(p[18]),sides); + draw(surface(p[19]),sides); + """ + + +def octahedron(center: tuple, length: float, color_str: str) -> str: + """ + Return an asymptote program string to draw a tetrahedron at `center` + with edge length `length`. + """ + return f""" + triple center={center}; + real vertex_position = 0.30615 * {length}; + + triple[] d; + path3[] p; + + d[0]=center + (0, vertex_position, 0); + d[1]=center + (0, 0, vertex_position); + d[2]=center + (-vertex_position, 0, 0); + d[3]=center + (0, 0, -vertex_position); + d[4]=center + (vertex_position, 0, 0); + d[5]=center + (0, -vertex_position, 0); + + p[0]=d[0]--d[1]--d[2]--cycle; + p[1]=d[0]--d[2]--d[3]--cycle; + p[2]=d[0]--d[3]--d[4]--cycle; + p[3]=d[0]--d[4]--d[1]--cycle; + + p[4]=d[5]--d[1]--d[2]--cycle; + p[5]=d[5]--d[2]--d[3]--cycle; + p[6]=d[5]--d[3]--d[4]--cycle; + p[7]=d[5]--d[4]--d[1]--cycle; + + pen sides={color_str}; + + draw(surface(p[0]),sides); + draw(surface(p[1]),sides); + draw(surface(p[2]),sides); + draw(surface(p[3]),sides); + draw(surface(p[4]),sides); + draw(surface(p[5]),sides); + draw(surface(p[6]),sides); + draw(surface(p[7]),sides); + """ + + +def tetrahedron(center: tuple, length: float, color_str: str) -> str: + """ + Return an asymptote program string to draw a tetrahedron at `center` + with length `length`. + """ + return f""" + triple center={center}; + real vertex_position = 0.30615 * {length}; + + triple[] d; + path3[] p; + + d[0]=center + (vertex_position, vertex_position, vertex_position); + d[1]=center + (vertex_position, -vertex_position, -vertex_position); + d[2]=center + (-vertex_position, vertex_position, -vertex_position); + d[3]=center + (-vertex_position, -vertex_position, vertex_position); + p[0]=d[0]--d[1]--d[2]--cycle; + p[1]=d[0]--d[2]--d[3]--cycle; + p[2]=d[0]--d[1]--d[3]--cycle; + p[3]=d[1]--d[2]--d[3]--cycle; + + pen sides={color_str}; + + draw(surface(p[0]),sides); + draw(surface(p[1]),sides); + draw(surface(p[2]),sides); + draw(surface(p[3]),sides); + """ + + +def unimplimented_polygon(center: tuple, length: float, color_str: str) -> str: + return f"draw(surface(sphere({center}, {length})), {color_str});" + + +HEDRON_NAME_MAP: Dict[str, Callable] = { + "cube": cube, + "dodecahedron": dodecahedron, + "icosahedron": icosahedron, + "octahedron": octahedron, + "tetrahedron": tetrahedron, +} diff --git a/mathics/format/latex.py b/mathics/format/latex.py index 707e6ec41..86218e1c3 100644 --- a/mathics/format/latex.py +++ b/mathics/format/latex.py @@ -543,7 +543,7 @@ def graphics3dbox(self, elements=None, **options) -> str: path = "--".join(["({0},{1},{2})".format(*coords) for coords in line]) boundbox_asy += "draw(({0}), {1});\n".format(path, pen) - (height, width) = (400, 400) # TODO: Proper size + height, width = (400, 400) # TODO: Proper size # Background color if self.background_color: @@ -559,7 +559,7 @@ def graphics3dbox(self, elements=None, **options) -> str: import tube; size({0}cm, {1}cm); currentprojection=perspective({2[0]},{2[1]},{2[2]}); -currentlight=light(rgb(0.5,0.5,1), {5}specular=red, (2,0,2), (2,2,2), (0,2,2)); +currentlight=light(rgb(0.5,0.5,0.5), {5}specular=red, (2,0,2), (2,2,2), (0,2,2)); {3} {4} \end{{asy}} diff --git a/mathics/main.py b/mathics/main.py index 550ad6fb9..d910e4918 100755 --- a/mathics/main.py +++ b/mathics/main.py @@ -19,6 +19,9 @@ import sys from typing import List +import mathics_scanner.location +from mathics_scanner.location import ContainerKind + import mathics.core as mathics_core from mathics import __version__, license_string, settings, version_string from mathics.builtin.trace import TraceBuiltins, traced_apply_function @@ -79,7 +82,7 @@ def __init__( in_prefix: str = "In", out_prefix: str = "Out", ): - super(TerminalShell, self).__init__("") + super(TerminalShell, self).__init__([], ContainerKind.STREAM) self.input_encoding = locale.getpreferredencoding() self.lineno = 0 self.in_prefix = in_prefix @@ -185,8 +188,9 @@ def read_line(self, prompt): return input(prompt) def print_result(self, result, no_out_prompt=False, strict_wl_output=False): - if result is None: - # FIXME decide what to do here + if result is None or result.last_eval is SymbolNull: + # Following WMA CLI, if the result is `SymbolNull`, just print an empty line. + print("") return form = result.form @@ -249,6 +253,8 @@ def reset_lineno(self): def feed(self): result = self.read_line(self.get_in_prompt()) + "\n" + if mathics_scanner.location.TRACK_LOCATIONS: + self.container.append(self.source_text) if result == "\n": return "" # end of input self.lineno += 1 diff --git a/mathics/session.py b/mathics/session.py index cb566a5a0..807e5487e 100644 --- a/mathics/session.py +++ b/mathics/session.py @@ -14,6 +14,8 @@ from os.path import join as osp_join from typing import Optional +from mathics_scanner.location import ContainerKind + from mathics.core.definitions import Definitions from mathics.core.evaluation import Evaluation, Result from mathics.core.parser import MathicsSingleLineFeeder, parse @@ -140,7 +142,10 @@ def reset(self, add_builtin=True, catch_interrupt=False): def evaluate(self, str_expression, timeout=None, form=None): """Parse str_expression and evaluate using the `evaluate` method of the Expression""" self.evaluation.out.clear() - expr = parse(self.definitions, MathicsSingleLineFeeder(str_expression)) + expr = parse( + self.definitions, + MathicsSingleLineFeeder(str_expression, ContainerKind.STREAM), + ) if form is None: form = self.form self.last_result = expr.evaluate(self.evaluation) diff --git a/mathics/version.py b/mathics/version.py index b86bf91c2..9df2b14e0 100644 --- a/mathics/version.py +++ b/mathics/version.py @@ -5,4 +5,4 @@ # well as importing into Python. That's why there is no # space around "=" below. # fmt: off -__version__="8.0.1.dev0" # noqa +__version__="8.0.2.dev0" # noqa diff --git a/pyproject.toml b/pyproject.toml index cfeba16a9..12f460fd9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,6 +4,8 @@ requires = [ "cython>=0.15.1; implementation_name!='pypy'", # For mathics-generate-json-table "Mathics-Scanner >= 1.4.0", + # "packaging" is needed for testing the SymPy Version + # in PartionsP "packaging", ] build-backend = "setuptools.build_meta" @@ -11,14 +13,13 @@ build-backend = "setuptools.build_meta" [project] description = "A general-purpose computer algebra system." dependencies = [ - "Mathics-Scanner >= 1.4.1", + "Mathics-Scanner > 1.4.1", "mpmath>=1.2.0", - "numpy<1.27", + "numpy<2.3", "palettable", # Pillow 9.1.0 supports BigTIFF with big-endian byte order. # ExampleData image hedy.tif is in this format. # Pillow 9.2 handles sunflowers.jpg - "stopit; platform_system != 'Emscripten'", "pillow >= 9.2", "pint", "python-dateutil", @@ -27,9 +28,11 @@ dependencies = [ "requests", "scipy", "setuptools", + # stopit is needed in TimeRemaining[] + "stopit; platform_system != 'Emscripten'", "sympy>=1.13,<1.14", ] -license = {text = "GPL"} +license = {text = "GPL3"} name = "Mathics3" requires-python = ">=3.8" # Sympy 1.11 is supported only down to 3.8 readme = "README.rst" @@ -90,20 +93,23 @@ include = ["mathics*"] [tool.setuptools.package-data] "mathics" = [ + "Packages/*/*.m", + "Packages/*/Kernel/init.m", + "autoload-cli/*.m", + "autoload/*.m", + "autoload/*/*.m", + "autoload/formats/*/Export.m", + "autoload/formats/*/Import.m", "data/*.csv", "data/*.json", - "data/*.yml", - "data/*.yaml", "data/*.pcl", + "data/*.yaml", + "data/*.yml", "data/ExampleData/*", - "doc/xml/data", - "doc/tex/data", - "autoload/*.m", - "autoload-cli/*.m", - "autoload/formats/*/Import.m", - "autoload/formats/*/Export.m", - "Packages/*/*.m", - "Packages/*/Kernel/init.m", + # Documentation stuff that will be removed in 9.0.0 or before + "doc/latex/mathics.pdf", + # End doc stuff + "test/data/*", ] "mathics.doc" = [ "documentation/*.mdoc", diff --git a/test/builtin/atomic/test_strings.py b/test/builtin/atomic/test_strings.py index bdf4b0d01..959de26da 100644 --- a/test/builtin/atomic/test_strings.py +++ b/test/builtin/atomic/test_strings.py @@ -100,8 +100,8 @@ def test_alphabet(str_expr, str_expected, fail_msg, warnings): "StringContainsQ[{A, Galaxy, Far, Far, Away}, {F ~~ __ ~~ r, aw ~~ ___}]", None, ), - ## Mathematica can detemine correct invalid element in the pattern, it reports error: - ## Element F is not a valid string or pattern element in {F ~~ __ ~~ r, aw ~~ ___}. + # Mathematica can determine correct invalid element in the pattern, it reports error: + # Element F is not a valid string or pattern element in {F ~~ __ ~~ r, aw ~~ ___}. ( 'StringRepeat["x", 0]', ("A positive integer is expected at position 2 in StringRepeat[x, 0].",), diff --git a/test/builtin/atomic/test_strings2.py b/test/builtin/atomic/test_strings2.py index 3196b8dc4..05ba2f7af 100644 --- a/test/builtin/atomic/test_strings2.py +++ b/test/builtin/atomic/test_strings2.py @@ -44,11 +44,11 @@ def test_string_split(): "{{11, 12, 13}, {21, 22, 23}, {31, 32, 33}}", ), ( - 'StringSplit["A tree, an apple, four pears. And more: two sacks", RegularExpression["\\W+"]]', + r'StringSplit["A tree, an apple, four pears. And more: two sacks", RegularExpression["\\W+"]]', "{A, tree, an, apple, four, pears, And, more, two, sacks}", ), ( - 'StringSplit["primes: 2 two 3 three 5 five ...", Whitespace ~~ RegularExpression["\\d"] ~~ Whitespace]', + r'StringSplit["primes: 2 two 3 three 5 five ...", Whitespace ~~ RegularExpression["\\d"] ~~ Whitespace]', "{primes:, two, three, five ...}", ), ('StringSplit["a-b:c-d:e-f-g", {":", "-"}]', "{a, b, c, d, e, f, g}"), diff --git a/test/builtin/calculus/test_integrate.py b/test/builtin/calculus/test_integrate.py index 135e0f932..212e9fb1e 100644 --- a/test/builtin/calculus/test_integrate.py +++ b/test/builtin/calculus/test_integrate.py @@ -17,7 +17,7 @@ def test_integrate(): ( "h=x;Integrate[Do[h=x*h,{5}]; h,x]", "x^7/7", - "a more agressive SymPy translation.", + "a more aggressive SymPy translation.", ), ): session.evaluate("Clear[h]; Clear[g]; Clear[f];") diff --git a/test/builtin/drawing/test_plot.py b/test/builtin/drawing/test_plot.py index 281e2a032..b57e588c6 100644 --- a/test/builtin/drawing/test_plot.py +++ b/test/builtin/drawing/test_plot.py @@ -105,7 +105,7 @@ "import tube;\n" "size(6.6667cm, 6.6667cm);\n" "currentprojection=perspective(2.6,-4.8,4.0);\n" - "currentlight=light(rgb(0.5,0.5,1), background=rgb(1, 0.1, 0.1), specular=red, (2,0,2), (2,2,2), (0,2,2));\n" + "currentlight=light(rgb(0.5,0.5,0.5), background=rgb(1, 0.1, 0.1), specular=red, (2,0,2), (2,2,2), (0,2,2));\n" "// Sphere3DBox\n" "draw(surface(sphere((0, 0, 0), 1)), rgb(1,1,1)+opacity(1));\n" "draw(((-1,-1,-1)--(1,-1,-1)), rgb(0.4, 0.4, 0.4)+linewidth(1));\n" @@ -133,7 +133,7 @@ "import tube;\n" "size(6.6667cm, 6.6667cm);\n" "currentprojection=perspective(2.6,-4.8,4.0);\n" - "currentlight=light(rgb(0.5,0.5,1), specular=red, (2,0,2), (2,2,2), (0,2,2));\n" + "currentlight=light(rgb(0.5,0.5,0.5), specular=red, (2,0,2), (2,2,2), (0,2,2));\n" "// Point3DBox\npath3 g=(0,1,0)--(0.20791,0.97815,0)--(0.40674,0.91355,0)--" "(0.58779,0.80902,0)--(0.74314,0.66913,0)--(0.86603,0.5,0)--(0.95106,0.30902,0)--" "(0.99452,0.10453,0)--(0.99452,-0.10453,0)--(0.95106,-0.30902,0)--(0.86603,-0.5,0)" diff --git a/test/builtin/files_io/test_files.py b/test/builtin/files_io/test_files.py index c1decd9b3..61b98df4d 100644 --- a/test/builtin/files_io/test_files.py +++ b/test/builtin/files_io/test_files.py @@ -111,7 +111,7 @@ def test_close(): ('Close["abc"]', ("abc is not open.",), "Close[abc]", ""), ( "exp = Sin[1]; FilePrint[exp]", - ("File specification Sin[1] is not a string of one or more characters.",), + ("The specified argument, Sin[1], should be a valid string.",), "FilePrint[Sin[1]]", "", ), @@ -123,7 +123,7 @@ def test_close(): ), ( 'FilePrint[""]', - ("File specification is not a string of one or more characters.",), + ("The file name cannot be an empty string.",), "FilePrint[]", "", ), @@ -344,7 +344,12 @@ def test_close(): "Null", "", ), - ('FileDate[tmpfilename, "Access"]', None, "{2002, 1, 1, 0, 0, 0.}", ""), + ( + 'FileDate[tmpfilename, "Access"]', + None, + "{2002, 1, 1, 0, 0, 0.}", + "", + ), ("DeleteFile[tmpfilename]", None, "Null", ""), ], ) @@ -525,18 +530,6 @@ def test_write_string(): # def test_Inputget_and_put(): # stream = Expression('Plus', Symbol('x'), Integer(2)) -# TODO: add these Unix-specific test. Be sure not to test -# sys.platform for not Windows and to test for applicability -# ## writing to dir -# S> x >> /var/ -# : Cannot open /var/. -# = x >> /var/ - -# ## writing to read only file -# S> x >> /proc/uptime -# : Cannot open /proc/uptime. -# = x >> /proc/uptime - # ## writing to full file # S> x >> /dev/full # : No space left on device. diff --git a/test/builtin/list/test_eol.py b/test/builtin/list/test_eol.py index 51338375a..0b7780ee4 100644 --- a/test/builtin/list/test_eol.py +++ b/test/builtin/list/test_eol.py @@ -50,7 +50,7 @@ "x=.;a=.;b=.;c=.;f=.; g=.;d=.;m=.;n=.;Delete[1 + x ^ (a + b + c), {2, 2, 3}]", None, "1 + x ^ (a + b)", - "Faiing?", + "Failing?", ), ("Delete[f[a, g[b, c], d], {{2}, {2, 1}}]", None, "f[a, d]", None), ( diff --git a/test/builtin/list/test_list.py b/test/builtin/list/test_list.py index f8d6b520a..ddbcff8ff 100644 --- a/test/builtin/list/test_list.py +++ b/test/builtin/list/test_list.py @@ -134,13 +134,13 @@ "Union[{1, -1, 2}, {-2, 3}, SameTest -> (Abs[#1] == Abs[#2] &)]", None, "{-2, 1, 3}", - "Union", + "Union with SameTest option", ), ( "Intersection[{1, -1, -2, 2, -3}, {1, -2, 2, 3}, SameTest -> (Abs[#1] == Abs[#2] &)]", None, "{-3, -2, 1}", - "Intersection", + "Intersection with SameTest option", ), ], ) diff --git a/test/builtin/numbers/test_algebra.py b/test/builtin/numbers/test_algebra.py index 701ab4411..826151628 100644 --- a/test/builtin/numbers/test_algebra.py +++ b/test/builtin/numbers/test_algebra.py @@ -23,7 +23,7 @@ def test_collect(): def test_coefficient(): for str_expr, str_expected in ( - # Form 1: Coefficent[expr, form] + # Form 1: Coefficient[expr, form] ( "Coefficient[(x + 2)/(y - 3) + (x + 3)/(y - 2), z, 0]", "(2 + x) / (-3 + y) + (3 + x) / (-2 + y)", @@ -50,7 +50,7 @@ def test_coefficient(): "Coefficient[x^3 - 2 x/y + 3 x z, y]", "0", ), - # Form 2: Coefficent[expr, form, n] + # Form 2: Coefficient[expr, form, n] ( "Coefficient[x^2 + axy^2 - bSin[c], c]", "0", @@ -61,7 +61,7 @@ def test_coefficient(): def test_coefficient_list(): for str_expr, str_expected in ( - # Form 1: Coefficent[expr, form] + # Form 1: Coefficient[expr, form] ( "CoefficientList[x^2 + a x y^2 - b Sin[c], y]", "{-b Sin[c] + x ^ 2, 0, a x}", @@ -359,10 +359,10 @@ def test_fullsimplify(): "Coefficient[3 + x + y, 5]", None, ), - ## This is known bug of Sympy 1.0, next Sympy version will fix it by this commit - ## https://github.com/sympy/sympy/commit/25bf64b64d4d9a2dc563022818d29d06bc740d47 - ("Coefficient[x * y, z, 0]", None, "x y", "Sympy 1.0 retuns 0"), - ## TODO: Support Modulus + # This is known bug of Sympy 1.0, next Sympy version will fix it by this commit + # https://github.com/sympy/sympy/commit/25bf64b64d4d9a2dc563022818d29d06bc740d47 + ("Coefficient[x * y, z, 0]", None, "x y", "Sympy 1.0 returns 0"), + # TODO: Support Modulus # ("Coefficient[(x + 2)^3 + (x + 3)^2, x, 0, {Modulus -> 3, Modulus -> 2, Modulus -> 10}]", # None,"{2, 1, 7}", None), ( diff --git a/test/builtin/numbers/test_diffeqns.py b/test/builtin/numbers/test_diffeqns.py index 7f445957a..b1168ca3a 100644 --- a/test/builtin/numbers/test_diffeqns.py +++ b/test/builtin/numbers/test_diffeqns.py @@ -66,7 +66,7 @@ "DSolve[f[x] == 0, f, {}]", None, ), - # # Order of arguments shoudn't matter + # Order of arguments should not matter ( "DSolve[D[f[x, y], x] == D[f[x, y], y], f, {x, y}]", None, diff --git a/test/builtin/numbers/test_nintegrate.py b/test/builtin/numbers/test_nintegrate.py index b3d9443a0..8e9dee43d 100644 --- a/test/builtin/numbers/test_nintegrate.py +++ b/test/builtin/numbers/test_nintegrate.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -Unit tests for mathics.buitin.numbers.nintegrate +Unit tests for mathics.builtin.numbers.nintegrate NIntegrate[] tests diff --git a/test/builtin/specialfns/test_gamma.py b/test/builtin/specialfns/test_gamma.py index b5d1d4148..3003960d7 100644 --- a/test/builtin/specialfns/test_gamma.py +++ b/test/builtin/specialfns/test_gamma.py @@ -31,6 +31,7 @@ "Overflow", ), ("Gamma[1., 2.]", None, "Gamma[1., 2.]", "needs mpmath for lowergamma"), + ("Gamma[1 + x]", None, "Gamma[1 + x]", "Gamma should not expand to factorial"), ], ) def test_private_doctests_gamma(str_expr, msgs, str_expected, fail_msg): diff --git a/test/builtin/specialfns/test_hypergeom.py b/test/builtin/specialfns/test_hypergeom.py new file mode 100644 index 000000000..7bdbc594c --- /dev/null +++ b/test/builtin/specialfns/test_hypergeom.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- +""" +Unit tests for mathics.builtins.specialfns.hypergeom +""" +from test.helper import check_evaluation + +import pytest + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ( + "N[HypergeometricPFQ[{4},{},1]]", + None, + "ComplexInfinity", + None, + ), + ( + "MeijerG[{{},{}},{{0,0},{0,0}},100^2]", + None, + "MeijerG[{{}, {}}, {{0, 0}, {0, 0}}, 10000]", + None, + ), + ("N[MeijerG[{{},{}},{{0,0},{0,0}},100^2]]", None, "0.000893912", None), + ( + "HypergeometricU[{3,1},{2,4},{7,8}]", + None, + "{MeijerG[{{-2}, {}}, {{0, -1}, {}}, 7] / 2, HypergeometricU[1, 4, 8]}", + None, + ), + ("N[HypergeometricU[{3,1},{2,4},{7,8}]]", None, "{0.00154364, 0.160156}", None), + ("HypergeometricU[0,c,z]", None, "1", None), + ( + "Hypergeometric1F1[{3,5},{7,1},{4,2}]", + None, + "{HypergeometricPFQ[{3}, {7}, 4], HypergeometricPFQ[{5}, {1}, 2]}", + None, + ), + ("N[Hypergeometric1F1[{3,5},{7,1},{4,2}]]", None, "{7.12435, 199.505}", None), + ("Hypergeometric1F1[b,b,z]", None, "E ^ z", None), + ("HypergeometricPFQ[{6},{1},2]", None, "HypergeometricPFQ[{6}, {1}, 2]", None), + ("N[HypergeometricPFQ[{6},{1},2]]", None, "354.182", None), + ("HypergeometricPFQ[{},{},z]", None, "1", None), + ("HypergeometricPFQ[{0},{c1,c2},z]", None, "1", None), + ("HypergeometricPFQ[{c1,c2},{c1,c2},z]", None, "E ^ z", None), + ], +) +def test_private_hypergeom(str_expr, msgs, str_expected, fail_msg): + """ """ + check_evaluation( + str_expr, + str_expected, + to_string_expr=True, + to_string_expected=True, + hold_expected=True, + failure_message=fail_msg, + expected_messages=msgs, + ) diff --git a/test/builtin/test_binary.py b/test/builtin/test_binary.py index 0fdc113f6..0791bb254 100644 --- a/test/builtin/test_binary.py +++ b/test/builtin/test_binary.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import sys -from test.helper import check_evaluation, session +from test.helper import check_evaluation import pytest diff --git a/test/builtin/test_comparison.py b/test/builtin/test_comparison.py index a2fc847c6..fc1c4644c 100644 --- a/test/builtin/test_comparison.py +++ b/test/builtin/test_comparison.py @@ -78,13 +78,13 @@ ("g[a]3', "Wo[x] > 3", "isue #797"), - ('Wo["x"]<3', "Wo[x] < 3", "isue #797"), - ('Wo["x"]==3', "Wo[x] == 3", "isue #797"), - ('3>Wo["x"]', "3 > Wo[x]", "isue #797"), - ('30', "Wo[f[x], 2] > 0", "isue #797"), + ('Wo["x"]>3', "Wo[x] > 3", "issue #797"), + ('Wo["x"]<3', "Wo[x] < 3", "issue #797"), + ('Wo["x"]==3', "Wo[x] == 3", "issue #797"), + ('3>Wo["x"]', "3 > Wo[x]", "issue #797"), + ('30', "Wo[f[x], 2] > 0", "issue #797"), # # chained compare ("a != a != b", "False", "Strange MMA behavior"), @@ -180,8 +180,8 @@ def test_sameq(str_lhs, str_rhs, str_expected): [ # UnsameQ returns True with 0 or 1 arguments ("UnsameQ[]", "True"), ("UnsameQ[expr]", "True"), - # With 2 or more argments, UnsameQ returns True if all expressions are - # structurally distinct and False otherwise + # With 2 or more arguments, UnsameQ returns True if all + # expressions are structurally distinct and False otherwise ("x =!= x", "False"), ("x =!= y", "True"), ("1 =!= 2 =!= 3 =!= 4", "True"), diff --git a/test/builtin/test_datentime.py b/test/builtin/test_datentime.py index 374cf174a..386136d90 100644 --- a/test/builtin/test_datentime.py +++ b/test/builtin/test_datentime.py @@ -34,16 +34,19 @@ def test_timeremaining(): def test_timeconstrained1(): """ This test checks that - * TimeConstrained manages to return $Aborted when the + + - ``TimeConstrained`` manages to return ``$Aborted`` when the evaluated expression exceeds the walltime. - * That the evaluation does not proceeds after the walltime. - If `Pause` and TimeConstrained were absolutely accurate, + - That the evaluation does not proceed after the walltime. + + If ``Pause`` and ``TimeConstrained`` were absolutely accurate, `a` should be always less than 11. However, sometimes - the innacuracies in time could allow to reach more than 10 - iterations before get stopped. 20 iterations should be a safe + the inaccuracies in time could allow to reach more than 10 + iterations before being stopped. 20 iterations should be a safe bound. - After `TimeConstrained` returns `$Abort`, iterations should stop, + + After ``TimeConstrained`` returns ``$Abort``, iterations should stop, so if we check one second after the end of the evaluation, `a` should not change its value. """ diff --git a/test/builtin/test_forms.py b/test/builtin/test_forms.py index 894a9de18..1bc31a0c5 100644 --- a/test/builtin/test_forms.py +++ b/test/builtin/test_forms.py @@ -3,7 +3,7 @@ Unit tests from mathics.builtin.forms. """ -from test.helper import check_evaluation, session +from test.helper import check_evaluation import pytest diff --git a/test/builtin/test_makeboxes.py b/test/builtin/test_makeboxes.py index fdf31e420..c0a853332 100644 --- a/test/builtin/test_makeboxes.py +++ b/test/builtin/test_makeboxes.py @@ -252,7 +252,7 @@ def test_makeboxes_others_fail(str_expr, str_expected, msg): ( r"MakeBoxes[G[F[2.]], StandardForm]", r'RowBox[{"G","[",RowBox[{"F","[","2.","]"}],"]"}]', - "Standard bahaviour", + "Standard behaviour", ), ( r'MakeBoxes[F[x_], fmt_] := "F[" <> ToString[x] <> "]";MakeBoxes[G[F[3.002]], StandardForm]', diff --git a/test/builtin/test_patterns.py b/test/builtin/test_patterns.py index 389dee860..c0b0b4153 100644 --- a/test/builtin/test_patterns.py +++ b/test/builtin/test_patterns.py @@ -49,7 +49,7 @@ def test_replace_all(): "Dispatch[]", "dispatch with 0 arguments", ), - ("Dispatch[a]", None, "Dispatch[a]", "A simbol. Keep unevaluated."), + ("Dispatch[a]", None, "Dispatch[a]", "A symbol. Keep unevaluated."), ("Dispatch[a -> b]", None, "Dispatch[<1>]", "single rule"), ("Dispatch[{}]", None, "{}", "empty rule"), ("Dispatch[{a -> 1}]", None, "Dispatch[<1>]", "single rule"), diff --git a/test/builtin/test_strings.py b/test/builtin/test_strings.py index 06fe91730..061e64925 100644 --- a/test/builtin/test_strings.py +++ b/test/builtin/test_strings.py @@ -323,8 +323,8 @@ def test_private_doctests_operations(str_expr, msgs, str_expected, fail_msg): "StringFreeQ[{A, Galaxy, Far, Far, Away}, {F ~~ __ ~~ r, aw ~~ ___}]", None, ), - ## Mathematica can detemine correct invalid element in the pattern, it reports error: - ## Element F is not a valid string or pattern element in {F ~~ __ ~~ r, aw ~~ ___}. + # Mathematica can determine correct invalid element in the pattern, it reports error: + # Element F is not a valid string or pattern element in {F ~~ __ ~~ r, aw ~~ ___}. ('StringMatchQ["abc1", LetterCharacter]', None, "False", None), ('StringMatchQ["abc", "ABC"]', None, "False", None), ('StringMatchQ["abc", "ABC", IgnoreCase -> True]', None, "True", None), diff --git a/test/builtin/test_system.py b/test/builtin/test_system.py index ed35753ea..c48eefc5f 100644 --- a/test/builtin/test_system.py +++ b/test/builtin/test_system.py @@ -4,21 +4,22 @@ """ -from test.helper import check_evaluation, session +from test.helper import check_evaluation import pytest @pytest.mark.parametrize( - ("str_expr", "str_expected"), + ("str_expr", "str_expected", "assert_tag_message"), [ - ('MemberQ[$Packages, "System`"]', "True"), - ("Head[$ParentProcessID] == Integer", "True"), - ("Head[$ProcessID] == Integer", "True"), - ("Head[$SystemWordLength] == Integer", "True"), + ('MemberQ[$Packages, "System`"]', "True", "$Packages"), + ("Head[$ParentProcessID] == Integer", "True", "$ParentProcessID"), + ("Head[$ProcessID] == Integer", "True", "$ProcessID"), + ("Head[$SessionID] == Integer", "True", "$SessionID"), + ("Head[$SystemWordLength] == Integer", "True", "$SystemWordLength"), ], ) -def test_private_doctests_system(str_expr, str_expected): +def test_private_doctests_system(str_expr, str_expected, assert_tag_message): """ """ check_evaluation( str_expr, @@ -26,4 +27,5 @@ def test_private_doctests_system(str_expr, str_expected): to_string_expr=True, to_string_expected=True, hold_expected=True, + failure_message=assert_tag_message, ) diff --git a/test/builtin/test_trace.py b/test/builtin/test_trace.py index 7f061a4d0..a5c159371 100644 --- a/test/builtin/test_trace.py +++ b/test/builtin/test_trace.py @@ -2,9 +2,9 @@ """ Unit tests for mathics.builtin.trace """ -from inspect import isfunction -from test.helper import evaluate -from typing import Callable +from inspect import isfunction, ismethod +from test.helper import evaluate, session +from typing import Any, Callable, Optional import pytest @@ -12,6 +12,7 @@ from mathics import version_info from mathics.core.evaluation import Evaluation from mathics.core.interrupt import AbortInterrupt +from mathics.eval.tracing import TraceEvent trace_evaluation_calls = 0 @@ -25,17 +26,17 @@ def test_TraceEvaluation(): def counting_print_evaluate( expr, evaluation: Evaluation, status: str, fn: Callable, orig_expr=None - ) -> bool: + ) -> Optional[Any]: """ A replacement for mathics.eval.tracing.print_evaluate() that counts the number of evaluation calls. """ global trace_evaluation_calls trace_evaluation_calls += 1 - assert status in ("Evaluating", "Returning") + assert status in ("Evaluating", "Returning", "Rewriting") if "cython" not in version_info: assert isfunction(fn), "Expecting 4th argument to be a function" - return False + return None try: # Set a small recursion limit, @@ -68,3 +69,79 @@ def counting_print_evaluate( mathics.eval.tracing.print_evaluate = old_evaluation_hook old_recursion_limit = evaluate(f"$RecursionLimit = {old_recursion_limit.value}") assert mathics.eval.tracing.print_evaluate == old_evaluation_hook + + +event_queue = [] + + +def test_skip_trivial_evaluation(): + """ + Test of TraceEvaluate[] to filter events + """ + + def empty_queue(): + global event_queue + event_queue = [] + + def call_event_func(event: TraceEvent, fn: Callable, *args) -> Optional[Any]: + """ + Capture filtered calls in event_queue. + """ + if isinstance(type(fn), type) or ismethod(fn) or isfunction(fn): + name = f"{fn.__module__}.{fn.__qualname__}" + else: + name = str(fn) + event_queue.append(f"{event.name} call : {name}{args[:3]}") + return None + + def return_event_func(event: TraceEvent, result: Any) -> Any: + """ + A somewhat generic function to print a traced call's + return value. + """ + event_queue.append(f"{event.name} result: {result}") + return result + + def capture_print(s: str): + """ + A somewhat generic function to print a traced call's + return value. + """ + event_queue.append(s) + + session.reset() + old_print_out = session.evaluation.print_out + session.evaluation.print_out = capture_print + empty_queue() + + try: + session.evaluate("TraceEvaluation[2 3 + 4]") + assert [ + " Evaluating: System`Plus[System`Times[2, 3], 4]", + " Evaluating: System`Times[2, 3]", + " Evaluating/Replacing: System`Times[2, 3] = 6", + " Returning: System`Times[2, 3] = 6", + " Evaluating/Replacing: System`Plus[System`Times[2, 3], 4] = 10", + " Returning: System`Plus[System`Times[2, 3], 4] = 10", + ] == event_queue + # print() + # for line in event_queue: + # print(line) + + empty_queue() + session.evaluate("TraceEvaluation[(2 + 3) 4]") + assert [ + " Evaluating: System`Times[System`Plus[2, 3], 4]" + " Evaluating: System`Plus[2, 3]", + " Returning: System`Plus[2, 3] = (, False)", + " Returning: System`Plus[2, 3] = 5", + " Returning: System`Times[System`Plus[2, 3], 4] = (, False)", + ] + # print() + # for line in event_queue: + # print(line) + + finally: + # Just in case, restore everything back to what it was before running this test. + session.evaluation.print_out = old_print_out + session.reset() diff --git a/test/consistency-and-style/test_summary_text.py b/test/consistency-and-style/test_summary_text.py index 8b9757fa6..b443ada36 100644 --- a/test/consistency-and-style/test_summary_text.py +++ b/test/consistency-and-style/test_summary_text.py @@ -11,7 +11,9 @@ from mathics import __file__ as mathics_initfile_path from mathics.core.builtin import Builtin from mathics.core.load_builtin import name_is_builtin_symbol +from mathics.doc.doc_entries import MATHICS_RE from mathics.doc.gather import skip_doc +from mathics.doc.latex_doc import LATEX_INLINE_EQUATION_RE # Get file system path name for mathics.builtin mathics_path = osp.dirname(mathics_initfile_path) @@ -172,6 +174,39 @@ def check_well_formatted_docstring(docstr: str, instance: Builtin, module_name: "" ), f"unbalanced tags in {instance.get_name()} from {module_name}" + check_code_and_latex(docstr, instance, module_name) + + +def check_code_and_latex(docstr: str, instance: Builtin, module_name: str): + """ + Check that code blocks does not contains LaTeX equations + """ + equations = [] + docstr = docstr.replace(r"\$", "_dolar_") + docstr = docstr.replace(r"\'", "_quotation_") + + def latex_inline_eq_repl(match): + equations.append(match.group(1)) + return "$equation$" + + docstr = LATEX_INLINE_EQUATION_RE.sub(latex_inline_eq_repl, docstr) + + def mathics_core_repl(match): + assert "$" not in match.group(1), f"'{match.group(1)}' contains equations" + return "" + + for eq in equations: + if eq[-1] in "0123456789" and len(eq) > 1: + assert ( + "_" in eq + ), f"indiced vars must be subindex in {module_name}:{Builtin}" + assert eq[-4:] not in ( + "_min", + "_max", + ), f"subindex with multi characters must be inside brackets, in {module_name}:{Builtin}" + + return + @pytest.mark.skipif( not os.environ.get("MATHICS_LINT"), diff --git a/test/core/parser/test_box_parser.py b/test/core/parser/test_box_parser.py index 7a64dbeab..c6c6dc28a 100644 --- a/test/core/parser/test_box_parser.py +++ b/test/core/parser/test_box_parser.py @@ -7,6 +7,7 @@ from typing import Optional from mathics_scanner import SingleLineFeeder +from mathics_scanner.location import ContainerKind from mathics.core.parser.parser import Parser @@ -14,12 +15,14 @@ # Note we don't import mathics.session here since we # are testing just the parse layer, not the evaluation layer. # Simpler is better. -parser = Parser() +core_parser = Parser() def check_evaluation(str_expr: str, str_expected: str, assert_message: Optional[str]): - def parse(s: str): - return parser.parse(SingleLineFeeder(s)) + def parse(source_text: str): + return core_parser.parse( + SingleLineFeeder(source_text, "", ContainerKind.STRING) + ) result = parse(str_expr) expected = parse(str_expected) diff --git a/test/core/parser/test_convert.py b/test/core/parser/test_convert.py index 9b6e9d3d3..a7010764d 100644 --- a/test/core/parser/test_convert.py +++ b/test/core/parser/test_convert.py @@ -2,26 +2,32 @@ import sys import unittest -from mathics_scanner import ( +from mathics_scanner import SingleLineFeeder +from mathics_scanner.errors import ( IncompleteSyntaxError, InvalidSyntaxError, - ScanError, - SingleLineFeeder, + SyntaxError, ) +from mathics_scanner.location import ContainerKind from mathics.core.atoms import Integer, Integer0, Integer1, Rational, Real, String from mathics.core.definitions import Definitions from mathics.core.expression import Expression -from mathics.core.parser import parse +from mathics.core.load_builtin import import_and_load_builtins +from mathics.core.parser import parse as core_parse from mathics.core.symbols import Symbol from mathics.core.systemsymbols import SymbolDerivative +import_and_load_builtins() definitions = Definitions(add_builtin=True) class ConvertTests(unittest.TestCase): - def parse(self, code): - return parse(definitions, SingleLineFeeder(code)) + def parse(self, source_text): + return core_parse( + definitions, + SingleLineFeeder(source_text, "", ContainerKind.STRING), + ) def check(self, expr1, expr2): if isinstance(expr1, str): @@ -35,7 +41,7 @@ def check(self, expr1, expr2): assert expr1.sameQ(expr2) def scan_error(self, string): - self.assertRaises(ScanError, self.parse, string) + self.assertRaises(SyntaxError, self.parse, string) def incomplete_error(self, string): self.assertRaises(IncompleteSyntaxError, self.parse, string) diff --git a/test/core/parser/test_parser.py b/test/core/parser/test_parser.py index 398e2217c..378306c31 100644 --- a/test/core/parser/test_parser.py +++ b/test/core/parser/test_parser.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # -*- coding: utf-8 -*- @@ -6,12 +5,14 @@ import sys import unittest -from mathics_scanner import ( +from mathics_scanner import SingleLineFeeder +from mathics_scanner.errors import ( IncompleteSyntaxError, InvalidSyntaxError, - ScanError, - SingleLineFeeder, + NamedCharacterSyntaxError, + SyntaxError, ) +from mathics_scanner.location import ContainerKind from mathics.core.parser.ast import Filename, Node, Number, String, Symbol from mathics.core.parser.parser import Parser @@ -22,7 +23,9 @@ def setUp(self): self.parser = Parser() def parse(self, s: str): - return self.parser.parse(SingleLineFeeder(s)) + return self.parser.parse( + SingleLineFeeder(s, "", ContainerKind.STRING) + ) def check(self, expr1, expr2): if isinstance(expr1, str): @@ -37,7 +40,7 @@ def check(self, expr1, expr2): self.assertEqual(expr1, expr2) def scan_error(self, string): - self.assertRaises(ScanError, self.parse, string) + self.assertRaises(SyntaxError, self.parse, string) def incomplete_error(self, string): self.assertRaises(IncompleteSyntaxError, self.parse, string) @@ -45,6 +48,9 @@ def incomplete_error(self, string): def invalid_error(self, string): self.assertRaises(InvalidSyntaxError, self.parse, string) + def named_character_error(self, string): + self.assertRaises(NamedCharacterSyntaxError, self.parse, string) + class PrecedenceTests(ParserTests): def test_minuslike(self): @@ -167,7 +173,7 @@ def testString(self): # self.check(r'"a\"b\\c"', String(r"a\"b\\c")) self.incomplete_error(r'"\"') self.invalid_error(r'\""') - self.invalid_error(r"abc \[fake]") + self.named_character_error(r"abc \[fake]") def testAccuracy(self): self.scan_error("1.5``") @@ -630,7 +636,7 @@ def testInequality(self): def testInformation(self): self.check("??a", "Information[a, LongForm -> True]") self.check("a ?? b", "a Information[b, LongForm -> True]") - self.invalid_error("a ?? + b") + self.check("a ?? + b", 'Times[a, Missing["UnknownSymbol", Plus[b]]]') self.check("a + ?? b", "a + Information[b, LongForm -> True]") self.check("??a + b", "Information[a, LongForm -> True] + b") self.check("??a * b", "Information[a, Rule[LongForm, True]]*b") diff --git a/test/core/parser/test_util.py b/test/core/parser/test_util.py index 65e28dc80..e4e1652f5 100644 --- a/test/core/parser/test_util.py +++ b/test/core/parser/test_util.py @@ -5,16 +5,20 @@ InvalidSyntaxError, MultiLineFeeder, SingleLineFeeder, + SyntaxError, ) +from mathics_scanner.location import ContainerKind from mathics.core.definitions import Definitions -from mathics.core.parser import parse +from mathics.core.load_builtin import import_and_load_builtins +from mathics.core.parser import parse as core_parse +import_and_load_builtins() definitions = Definitions(add_builtin=True) class UtilTests(unittest.TestCase): - def parse(self, code): + def parse(self, source_text: str): raise NotImplementedError def compare(self, expr1, expr2): @@ -37,10 +41,16 @@ def incomplete_error(self, string): def invalid_error(self, string): self.assertRaises(InvalidSyntaxError, self.parse, string) + def syntax_error(self, string): + self.assertRaises(SyntaxError, self.parse, string) + class SingleLineParserTests(UtilTests): - def parse(self, code): - return parse(definitions, SingleLineFeeder(code)) + def parse(self, source_text): + return core_parse( + definitions, + SingleLineFeeder(source_text, "", ContainerKind.STRING), + ) def compare(self, expr1, expr2): assert expr1.sameQ(expr2) @@ -52,19 +62,30 @@ def test_continuation(self): def test_trailing_backslash(self): self.incomplete_error("x \\") - self.check("x \\\ny", "Times[x, y]") + self.syntax_error("X\\n\\t") + + ## TODO see what this should do and why + ## self.check("x \\\ny", "Times[x, y]") class MultiLineParserTests(UtilTests): - def parse(self, code): - return parse(definitions, MultiLineFeeder(code)) + def parse(self, source_text): + return core_parse( + definitions, + MultiLineFeeder( + source_text, "", ContainerKind.STRING + ), + ) def compare(self, expr1, expr2): assert expr1.sameQ(expr2) def test_trailing_backslash(self): self.incomplete_error("x \\") - self.check("x \\\ny", "Times[x, y]") + self.syntax_error("X\\n\\t") + + ## TODO see what this should do and why + ## self.check("x \\\ny", "Times[x, y]") def test_continuation(self): self.incomplete_error("Sin[") @@ -79,14 +100,20 @@ def test_CompoundExpression(self): self.check("a;^b", "Power[CompoundExpression[a, Null], b]") - feeder = MultiLineFeeder("a;\n^b") + feeder = MultiLineFeeder( + "a;\n^b", "", ContainerKind.STRING + ) self.compare( - parse(definitions, feeder), self.parse("CompoundExpression[a, Null]") + core_parse(definitions, feeder), self.parse("CompoundExpression[a, Null]") + ) + self.assertRaises( + InvalidSyntaxError, lambda f: core_parse(definitions, f), feeder ) - self.assertRaises(InvalidSyntaxError, lambda f: parse(definitions, f), feeder) def test_Span(self): self.check("a;;^b", "Power[Span[a, All], b]") - feeder = MultiLineFeeder("a;;\n^b") - self.compare(parse(definitions, feeder), self.parse("Span[a, All]")) - self.assertRaises(InvalidSyntaxError, lambda f: parse(definitions, f), feeder) + feeder = MultiLineFeeder("a;;\n^b", "", ContainerKind.STRING) + self.compare(core_parse(definitions, feeder), self.parse("Span[a, All]")) + self.assertRaises( + InvalidSyntaxError, lambda f: core_parse(definitions, f), feeder + ) diff --git a/test/core/test_elements_properties.py b/test/core/test_elements_properties.py index cdacb77a6..6254ffba0 100644 --- a/test/core/test_elements_properties.py +++ b/test/core/test_elements_properties.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- +from mathics_scanner.location import ContainerKind + from mathics.core.parser import MathicsSingleLineFeeder from mathics.core.parser.convert import convert from mathics.core.parser.parser import Parser @@ -40,7 +42,9 @@ def test_elements_properties(): ]: # fmt: on session.evaluation.out.clear() - feeder = MathicsSingleLineFeeder(str_expression) + feeder = MathicsSingleLineFeeder( + str_expression, "", ContainerKind.STRING + ) ast = parser.parse(feeder) # convert() creates the initial Expression. In that various properties should diff --git a/test/core/test_is_literal.py b/test/core/test_is_literal.py index 439e8fb58..63b932696 100644 --- a/test/core/test_is_literal.py +++ b/test/core/test_is_literal.py @@ -3,6 +3,8 @@ Test mathics.core property on BaseElement is_literal. """ +from mathics_scanner.location import ContainerKind + from mathics.core.parser import MathicsSingleLineFeeder from mathics.core.parser.convert import convert from mathics.core.parser.parser import Parser @@ -33,7 +35,9 @@ def test_is_literal(): ]: # fmt: on session.evaluation.out.clear() - feeder = MathicsSingleLineFeeder(str_expression) + feeder = MathicsSingleLineFeeder( + str_expression, "", ContainerKind.STRING + ) ast = parser.parse(feeder) # print("XXX", ast) diff --git a/test/core/test_streams.py b/test/core/test_streams.py index e7ead1cd1..54fbb8914 100644 --- a/test/core/test_streams.py +++ b/test/core/test_streams.py @@ -23,7 +23,7 @@ def test_path_search(): for expect_find, expect_temporary, filename, assert_msg in ( (True, False, "fortytwo`", "should find with .m extension"), (False, False, "fortytwo", "should not find without backtick (`) added"), - (True, False, "recursive-gcd`", "should find wit .wl extension"), + (True, False, "recursive-gcd`", "should find with .wl extension"), ): resolved_file, is_temporary = path_search(filename) assert expect_find == bool(resolved_file), assert_msg diff --git a/test/core/test_sympy_python_convert.py b/test/core/test_sympy_python_convert.py index d9bd2a241..cae80f38c 100644 --- a/test/core/test_sympy_python_convert.py +++ b/test/core/test_sympy_python_convert.py @@ -225,7 +225,7 @@ def testComplex(self): self.compare(Complex(Integer1, Integer0), 1) def testList(self): - self.compare(ListExpression(Integer1), [1]) + self.compare(ListExpression(Integer1), (1,)) if __name__ == "__main__": diff --git a/test/doc/test_common.py b/test/doc/test_common.py index bf8bf6212..97ba1b680 100644 --- a/test/doc/test_common.py +++ b/test/doc/test_common.py @@ -4,7 +4,6 @@ import os.path as osp -from mathics.core.evaluation import Message, Print from mathics.core.load_builtin import import_and_load_builtins from mathics.doc.common_doc import ( DocChapter, @@ -96,80 +95,6 @@ def test_gather_parse_docstring_to_DocumentationEntry_items(): assert all([t == l for t, l in zip(num_tests, [1, 2, 1, 2, 1])]) -def test_create_doctest(): - """initializing DocTest""" - - key = ( - "Part title", - "Chapter Title", - "Section Title", - ) - test_cases = [ - { - "test": [">", "2+2", "\n = 4"], - "properties": { - "private": False, - "ignore": False, - "result": "4", - "outs": [], - "key": key + (1,), - }, - }, - { - "test": ["#", "2+2", "\n = 4"], - "properties": { - "private": True, - "ignore": False, - "result": "4", - "outs": [], - "key": key + (1,), - }, - }, - { - "test": ["S", "2+2", "\n = 4"], - "properties": { - "private": False, - "ignore": False, - "result": "4", - "outs": [], - "key": key + (1,), - }, - }, - { - "test": ["X", 'Print["Hola"]', "| Hola"], - "properties": { - "private": False, - "ignore": True, - "result": None, - "outs": [Print("Hola")], - "key": key + (1,), - }, - }, - { - "test": [ - ">", - "1 / 0", - "\n : Infinite expression 1 / 0 encountered.\n ComplexInfinity", - ], - "properties": { - "private": False, - "ignore": False, - "result": None, - "outs": [ - Message( - symbol="", text="Infinite expression 1 / 0 encountered.", tag="" - ) - ], - "key": key + (1,), - }, - }, - ] - for index, test_case in enumerate(test_cases): - doctest = DocTest(1, test_case["test"], key) - for property_key, value in test_case["properties"].items(): - assert getattr(doctest, property_key) == value - - def test_load_documentation(): documentation = Documentation() fn = osp.join(DOC_DIR, "1-Manual.mdoc") diff --git a/test/doc/test_doctests.py b/test/doc/test_doctests.py index 6fc15bed0..d721001e1 100644 --- a/test/doc/test_doctests.py +++ b/test/doc/test_doctests.py @@ -2,25 +2,10 @@ Pytests for the documentation system. Basic functions and classes. """ -import os.path as osp - from mathics.core.evaluation import Message, Print from mathics.core.load_builtin import import_and_load_builtins -from mathics.doc.common_doc import ( - DocChapter, - DocPart, - DocSection, - Documentation, - MathicsMainDocumentation, -) -from mathics.doc.doc_entries import ( - DocTest, - DocTests, - DocText, - DocumentationEntry, - parse_docstring_to_DocumentationEntry_items, -) -from mathics.settings import DOC_DIR +from mathics.doc.common_doc import MathicsMainDocumentation +from mathics.doc.doc_entries import DocTest import_and_load_builtins() DOCUMENTATION = MathicsMainDocumentation() @@ -110,4 +95,7 @@ def test_create_doctest(): for index, test_case in enumerate(test_cases): doctest = DocTest(1, test_case["test"], key) for property_key, value in test_case["properties"].items(): - assert getattr(doctest, property_key) == value + if property_key == "result" and value is None: + assert getattr(doctest, property_key) == "" + else: + assert getattr(doctest, property_key) == value diff --git a/test/doc/test_latex.py b/test/doc/test_latex.py index 9541922fc..d15df61e0 100644 --- a/test/doc/test_latex.py +++ b/test/doc/test_latex.py @@ -87,8 +87,8 @@ def test_load_latex_documentation(): r"\begin{testresult}o\end{testresult}\end{testcase}" ) assert ( - doc_in_section.latex(doc_data)[:39] - ).strip() == "Let's sketch the function\n\\begin{tests}" + doc_in_section.latex(doc_data)[:40] + ).strip() == "Let\\'s sketch the function\n\\begin{tests}" assert ( first_section.latex(doc_data)[:30] ).strip() == "\\section{Curve Sketching}{}" diff --git a/test/eval/test_patterns.py b/test/eval/test_patterns.py index bb2ae9efb..1bb1e2bd4 100644 --- a/test/eval/test_patterns.py +++ b/test/eval/test_patterns.py @@ -6,6 +6,7 @@ from test.helper import session import pytest +from mathics_scanner.location import ContainerKind from mathics.core.definitions import Definitions from mathics.core.parser import MathicsSingleLineFeeder, parse @@ -17,10 +18,20 @@ def check_pattern(str_expr, str_pattern): - expr = parse(defintions, MathicsSingleLineFeeder(str_expr)) - pattern = ExpressionPattern(parse(defintions, MathicsSingleLineFeeder(str_pattern))) + expr = parse( + defintions, + MathicsSingleLineFeeder(str_expr, "", ContainerKind.STRING), + ) + pattern = ExpressionPattern( + parse( + defintions, + MathicsSingleLineFeeder( + str_pattern, "", ContainerKind.STRING + ), + ) + ) ret = Matcher(pattern, session.evaluation).match(expr, session.evaluation) - assert ret == True + assert ret is True @pytest.mark.parametrize( diff --git a/test/test_to_python.py b/test/test_to_python.py index 21cd12234..1eb3ae7da 100644 --- a/test/test_to_python.py +++ b/test/test_to_python.py @@ -11,7 +11,7 @@ def test_to_infinity(): ), ( "PythonForm[{1, 2, 3, 4}]", - '"[1, 2, 3, 4]"', + '"(1, 2, 3, 4)"', "Simple List of integers", ), (