diff --git a/.github/workflows/osx.yml b/.github/workflows/osx.yml index 2269693ac..da640f1b2 100644 --- a/.github/workflows/osx.yml +++ b/.github/workflows/osx.yml @@ -9,8 +9,8 @@ on: jobs: build: env: - LDFLAGS: "-L/usr/local/opt/llvm@11/lib" - CPPFLAGS: "-I/usr/local/opt/llvm@11/include" + LDFLAGS: "-L/usr/local/opt/llvm@14/lib" + CPPFLAGS: "-I/usr/local/opt/llvm@14/include" runs-on: macos-latest strategy: matrix: @@ -24,7 +24,7 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install OS dependencies run: | - brew install llvm tesseract + brew install llvm@14 tesseract python -m pip install --upgrade pip - name: Install Mathics3 with full Python dependencies run: | diff --git a/AUTHORS.txt b/AUTHORS.txt index 9dc803a42..03cdcf44b 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -36,6 +36,8 @@ Additional contributions were made by: - Pablo Emilio Escobar Gaviria @GarkGarcia - Rocky Bernstein @rocky - Tiago Cavalcante Trindade @TiagoCavalcante +- Li Xiang @Li-Xiang-Ideal +- Kevin Cao @kejcao Thanks to the authors of all projects that are used in Mathics: - Django diff --git a/CHANGES.rst b/CHANGES.rst index 8e602d47c..2729acab9 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -8,9 +8,11 @@ New Builtins ++++++++++++ -* `Elements` -* `RealAbs` and `RealSign` -* `RealValuedNumberQ` +* ``Elements`` +* ``ConjugateTranspose`` +* ``LeviCivitaTensor`` +* ``RealAbs`` and ``RealSign`` +* ``RealValuedNumberQ`` Compatibility diff --git a/FUTURE.rst b/FUTURE.rst index e37758f22..291e016d2 100644 --- a/FUTURE.rst +++ b/FUTURE.rst @@ -2,9 +2,11 @@ .. contents:: -The following 2023 road map that appears the 6.0.0 hasn't gone through enough discussion. This provisional. -Check the github repository for updates. +2024 Roadmap +============ + +To be decided... 2023 Roadmap ============ diff --git a/SYMBOLS_MANIFEST.txt b/SYMBOLS_MANIFEST.txt index d3ecf4204..43c6e2162 100644 --- a/SYMBOLS_MANIFEST.txt +++ b/SYMBOLS_MANIFEST.txt @@ -574,6 +574,7 @@ System`LessEqual System`LetterCharacter System`LetterNumber System`LetterQ +System`LeviCivitaTensor System`Level System`LevelQ System`LightBlue diff --git a/admin-tools/make-dist.sh b/admin-tools/make-dist.sh index 015477da8..d2f045dd0 100755 --- a/admin-tools/make-dist.sh +++ b/admin-tools/make-dist.sh @@ -25,7 +25,8 @@ for pyversion in $PYVERSIONS; do exit $? fi rm -fr build - python setup.py bdist_egg + # PYPI no longer supports eggs + # python setup.py bdist_egg python setup.py bdist_wheel done diff --git a/mathics/builtin/arithmetic.py b/mathics/builtin/arithmetic.py index 0f5a329cc..5f622282c 100644 --- a/mathics/builtin/arithmetic.py +++ b/mathics/builtin/arithmetic.py @@ -958,14 +958,6 @@ class Sum(IterationFunction, SympyFunction): Verify algebraic identities: >> Sum[x ^ 2, {x, 1, y}] - y * (y + 1) * (2 * y + 1) / 6 = 0 - - - ## Issue #302 - ## The sum should not converge since the first term is 1/0. - #> Sum[i / Log[i], {i, 1, Infinity}] - = Sum[i / Log[i], {i, 1, Infinity}] - #> Sum[Cos[Pi i], {i, 1, Infinity}] - = Sum[Cos[i Pi], {i, 1, Infinity}] """ summary_text = "discrete sum" diff --git a/mathics/builtin/distance/clusters.py b/mathics/builtin/distance/clusters.py index ebd904540..382fce982 100644 --- a/mathics/builtin/distance/clusters.py +++ b/mathics/builtin/distance/clusters.py @@ -35,6 +35,7 @@ ) from mathics.eval.nevaluator import eval_N from mathics.eval.parts import walk_levels +from mathics.eval.tensors import get_default_distance class _LazyDistances(LazyDistances): @@ -139,8 +140,6 @@ def _cluster(self, p, k, mode, evaluation, options, expr): options, "DistanceFunction", evaluation ) if distance_function_string == "Automatic": - from mathics.builtin.tensors import get_default_distance - distance_function = get_default_distance(dist_p) if distance_function is None: name_of_builtin = strip_context(self.get_name()) @@ -462,8 +461,6 @@ def eval( options, "DistanceFunction", evaluation ) if distance_function_string == "Automatic": - from mathics.builtin.tensors import get_default_distance - distance_function = get_default_distance(dist_p) if distance_function is None: evaluation.message( diff --git a/mathics/builtin/files_io/files.py b/mathics/builtin/files_io/files.py index 2c3272af4..200d53406 100644 --- a/mathics/builtin/files_io/files.py +++ b/mathics/builtin/files_io/files.py @@ -204,10 +204,6 @@ class Close(Builtin): Closing a file doesn't delete it from the filesystem >> DeleteFile[file]; - #> Close["abc"] - : abc is not open. - = Close[abc] - #> Clear[file] """ @@ -277,18 +273,6 @@ class FilePrint(Builtin):
prints the raw contents of $file$. - #> exp = Sin[1]; - #> FilePrint[exp] - : File specification Sin[1] is not a string of one or more characters. - = FilePrint[Sin[1]] - - #> FilePrint["somenonexistentpath_h47sdmk^&h4"] - : Cannot open somenonexistentpath_h47sdmk^&h4. - = FilePrint[somenonexistentpath_h47sdmk^&h4] - - #> FilePrint[""] - : File specification is not a string of one or more characters. - = FilePrint[] """ messages = { @@ -394,16 +378,6 @@ class Get(PrefixOperator): ## TODO: Requires EndPackage implemented ## 'Get' can also load packages: ## >> << "VectorAnalysis`" - - #> Get["SomeTypoPackage`"] - : Cannot open SomeTypoPackage`. - = $Failed - - ## Parser Tests - #> Hold[<< ~/some_example/dir/] // FullForm - = Hold[Get["~/some_example/dir/"]] - #> Hold[<<`/.\-_:$*~?] // FullForm - = Hold[Get["`/.\\\\-_:$*~?"]] """ operator = "<<" options = { @@ -528,29 +502,11 @@ class OpenRead(_OpenAction): >> OpenRead["ExampleData/EinsteinSzilLetter.txt", CharacterEncoding->"UTF8"] = InputStream[...] - #> Close[%]; - - S> Close[OpenRead["https://raw.githubusercontent.com/Mathics3/mathics-core/master/README.rst"]]; - - #> OpenRead[] - : OpenRead called with 0 arguments; 1 argument is expected. - = OpenRead[] - #> OpenRead[y] - : File specification y is not a string of one or more characters. - = OpenRead[y] + The stream must be closed after using it to release the resource: + >> Close[%]; - #> OpenRead[""] - : File specification is not a string of one or more characters. - = OpenRead[] - - #> OpenRead["MathicsNonExampleFile"] - : Cannot open MathicsNonExampleFile. - = OpenRead[MathicsNonExampleFile] - - #> OpenRead["ExampleData/EinsteinSzilLetter.txt", BinaryFormat -> True, CharacterEncoding->"UTF8"] - = InputStream[...] - #> Close[%]; + S> Close[OpenRead["https://raw.githubusercontent.com/Mathics3/mathics-core/master/README.rst"]]; """ summary_text = "open a file for reading" @@ -569,11 +525,7 @@ class OpenWrite(_OpenAction): >> OpenWrite[] = OutputStream[...] - #> DeleteFile[Close[%]]; - - #> OpenWrite[BinaryFormat -> True] - = OutputStream[...] - #> DeleteFile[Close[%]]; + >> DeleteFile[Close[%]]; """ summary_text = ( @@ -594,14 +546,8 @@ class OpenAppend(_OpenAction): >> OpenAppend[] = OutputStream[...] - #> DeleteFile[Close[%]]; + >> DeleteFile[Close[%]]; - #> appendFile = OpenAppend["MathicsNonExampleFile"] - = OutputStream[MathicsNonExampleFile, ...] - - #> Close[appendFile] - = MathicsNonExampleFile - #> DeleteFile["MathicsNonExampleFile"] """ mode = "a" @@ -757,17 +703,7 @@ class PutAppend(BinaryOperator): | 265252859812191058636308480000000 | 8320987112741390144276341183223364380754172606361245952449277696409600000000000000 | "string" - #> DeleteFile["factorials"]; - - ## writing to dir - #> x >>> /var/ - : Cannot open /var/. - = x >>> /var/ - - ## writing to read only file - #> x >>> /proc/uptime - : Cannot open /proc/uptime. - = x >>> /proc/uptime + >> DeleteFile["factorials"]; """ operator = ">>>" @@ -842,20 +778,12 @@ class Read(Builtin):
  • Word - ## Malformed InputString - #> Read[InputStream[String], {Word, Number}] - = Read[InputStream[String], {Word, Number}] - - ## Correctly formed InputString but not open - #> Read[InputStream[String, -1], {Word, Number}] - : InputStream[String, -1] is not open. - = Read[InputStream[String, -1], {Word, Number}] ## Reading Strings >> stream = StringToStream["abc123"]; >> Read[stream, String] = abc123 - #> Read[stream, String] + >> Read[stream, String] = EndOfFile #> Close[stream]; @@ -865,60 +793,19 @@ class Read(Builtin): = abc >> Read[stream, Word] = 123 - #> Read[stream, Word] - = EndOfFile - #> Close[stream]; - #> stream = StringToStream[""]; - #> Read[stream, Word] - = EndOfFile - #> Read[stream, Word] + >> Read[stream, Word] = EndOfFile #> Close[stream]; - ## Number >> stream = StringToStream["123, 4"]; >> Read[stream, Number] = 123 >> Read[stream, Number] = 4 - #> Read[stream, Number] + >> Read[stream, Number] = EndOfFile #> Close[stream]; - #> stream = StringToStream["123xyz 321"]; - #> Read[stream, Number] - = 123 - #> Quiet[Read[stream, Number]] - = $Failed - - ## Real - #> stream = StringToStream["123, 4abc"]; - #> Read[stream, Real] - = 123. - #> Read[stream, Real] - = 4. - #> Quiet[Read[stream, Number]] - = $Failed - #> Close[stream]; - #> stream = StringToStream["1.523E-19"]; Read[stream, Real] - = 1.523×10^-19 - #> Close[stream]; - #> stream = StringToStream["-1.523e19"]; Read[stream, Real] - = -1.523×10^19 - #> Close[stream]; - #> stream = StringToStream["3*^10"]; Read[stream, Real] - = 3.×10^10 - #> Close[stream]; - #> stream = StringToStream["3.*^10"]; Read[stream, Real] - = 3.×10^10 - #> Close[stream]; - - ## Expression - #> stream = StringToStream["x + y Sin[z]"]; Read[stream, Expression] - = x + y Sin[z] - #> Close[stream]; - ## #> stream = Quiet[StringToStream["Sin[1 123"]; Read[stream, Expression]] - ## = $Failed ## HoldExpression: >> stream = StringToStream["2+2\\n2+3"]; @@ -930,7 +817,7 @@ class Read(Builtin): >> Read[stream, Expression] = 5 - >> Close[stream]; + #> Close[stream]; Reading a comment however will return the empty list: >> stream = StringToStream["(* ::Package:: *)"]; @@ -938,28 +825,16 @@ class Read(Builtin): >> Read[stream, Hold[Expression]] = {} - >> Close[stream]; + #> Close[stream]; ## Multiple types >> stream = StringToStream["123 abc"]; >> Read[stream, {Number, Word}] = {123, abc} - #> Read[stream, {Number, Word}] + >> Read[stream, {Number, Word}] = EndOfFile - #> lose[stream]; - - #> stream = StringToStream["123 abc"]; - #> Quiet[Read[stream, {Word, Number}]] - = $Failed - #> Close[stream]; - - #> stream = StringToStream["123 123"]; Read[stream, {Real, Number}] - = {123., 123} #> Close[stream]; - #> Quiet[Read[stream, {Real}]] - = Read[InputStream[String, ...], {Real}] - Multiple lines: >> stream = StringToStream["\\"Tengo una\\nvaca lechera.\\""]; Read[stream] = Tengo una @@ -1232,15 +1107,7 @@ class ReadList(Read): = {abc123} >> InputForm[%] = {"abc123"} - - #> ReadList[stream, "Invalid"] - : Invalid is not a valid format specification. - = ReadList[..., Invalid] #> Close[stream]; - - - #> ReadList[StringToStream["a 1 b 2"], {Word, Number}, 1] - = {{a, 1}} """ # TODO @@ -1398,10 +1265,6 @@ class SetStreamPosition(Builtin): >> Read[stream, Word] = is - #> SetStreamPosition[stream, -5] - : Invalid I/O Seek. - = 10 - >> SetStreamPosition[stream, Infinity] = 16 """ @@ -1490,7 +1353,7 @@ class Skip(Read): >> Skip[stream, Word, 2] >> Read[stream, Word] = d - #> Skip[stream, Word] + >> Skip[stream, Word] = EndOfFile #> Close[stream]; """ @@ -1555,7 +1418,7 @@ class Find(Read): = in manuscript, leads me to expect that the element uranium may be turned into >> Find[stream, "uranium"] = become possible to set up a nuclear chain reaction in a large mass of uranium, - >> Close[stream] + #> Close[stream] = ... >> stream = OpenRead["ExampleData/EinsteinSzilLetter.txt", CharacterEncoding->"UTF8"]; @@ -1563,7 +1426,7 @@ class Find(Read): = a new and important source of energy in the immediate future. Certain aspects >> Find[stream, {"energy", "power"} ] = by which vast amounts of power and large quantities of new radium-like - >> Close[stream] + #> Close[stream] = ... """ @@ -1649,14 +1512,8 @@ class StringToStream(Builtin): >> strm = StringToStream["abc 123"] = InputStream[String, ...] - #> Read[strm, Word] - = abc - - #> Read[strm, Number] - = 123 - - #> Close[strm] - = String + The stream must be closed after using it, to release the resource: + >> Close[strm]; """ summary_text = "open an input stream for reading from a string" @@ -1685,14 +1542,6 @@ class Streams(Builtin): >> Streams["stdout"] = ... - - #> OpenWrite[] - = ... - #> Streams[%[[1]]] - = {OutputStream[...]} - - #> Streams["some_nonexistent_name"] - = {} """ summary_text = "list currently open streams" @@ -1764,11 +1613,12 @@ class Write(Builtin): = ... >> Write[stream, 10 x + 15 y ^ 2] >> Write[stream, 3 Sin[z]] + The stream must be closed in order to use the file again: >> Close[stream]; >> stream = OpenRead[%]; >> ReadList[stream] = {10 x + 15 y ^ 2, 3 Sin[z]} - #> DeleteFile[Close[stream]]; + >> DeleteFile[Close[stream]]; """ summary_text = "write a sequence of expressions to a stream, ending the output with a newline (line feed)" @@ -1817,7 +1667,7 @@ class WriteString(Builtin): >> FilePrint[%] | This is a test 1This is also a test 2 - #> DeleteFile[pathname]; + >> DeleteFile[pathname]; >> stream = OpenWrite[]; >> WriteString[stream, "This is a test 1", "This is also a test 2"] >> pathname = Close[stream] @@ -1825,29 +1675,7 @@ class WriteString(Builtin): >> FilePrint[%] | This is a test 1This is also a test 2 - #> DeleteFile[pathname]; - #> stream = OpenWrite[]; - #> WriteString[stream, 100, 1 + x + y, Sin[x + y]] - #> pathname = Close[stream] - = ... - #> FilePrint[%] - | 1001 + x + ySin[x + y] - - #> DeleteFile[pathname]; - #> stream = OpenWrite[]; - #> WriteString[stream] - #> pathame = Close[stream] - = ... - #> FilePrint[%] - - #> WriteString[%%, abc] - #> Streams[%%%][[1]] - = ... - #> pathname = Close[%]; - #> FilePrint[%] - | abc - #> DeleteFile[pathname]; - #> Clear[pathname]; + >> DeleteFile[pathname]; If stream is the string "stdout" or "stderr", writes to the system standard output/ standard error channel: diff --git a/mathics/builtin/files_io/filesystem.py b/mathics/builtin/files_io/filesystem.py index edb9fdb3e..f0faf505e 100644 --- a/mathics/builtin/files_io/filesystem.py +++ b/mathics/builtin/files_io/filesystem.py @@ -53,9 +53,6 @@ class AbsoluteFileName(Builtin): >> AbsoluteFileName["ExampleData/sunflowers.jpg"] = ... - #> AbsoluteFileName["Some/NonExistant/Path.ext"] - : File not found during AbsoluteFileName[Some/NonExistant/Path.ext]. - = $Failed """ messages = { @@ -363,23 +360,6 @@ class DirectoryName(Builtin): >> DirectoryName["a/b/c", 2] = a - - #> DirectoryName["a/b/c", 3] // InputForm - = "" - #> DirectoryName[""] // InputForm - = "" - - #> DirectoryName["a/b/c", x] - : Positive machine-sized integer expected at position 2 in DirectoryName[a/b/c, x]. - = DirectoryName[a/b/c, x] - - #> DirectoryName["a/b/c", -1] - : Positive machine-sized integer expected at position 2 in DirectoryName[a/b/c, -1]. - = DirectoryName[a/b/c, -1] - - #> DirectoryName[x] - : String expected at position 1 in DirectoryName[x]. - = DirectoryName[x] """ messages = { @@ -508,12 +488,6 @@ class FileBaseName(Builtin): >> FileBaseName["file.tar.gz"] = file.tar - - #> FileBaseName["file."] - = file - - #> FileBaseName["file"] - = file """ options = { @@ -627,11 +601,6 @@ class FileExtension(Builtin): >> FileExtension["file.tar.gz"] = gz - - #> FileExtension["file."] - = #<--# - #> FileExtension["file"] - = #<--# """ options = { @@ -660,9 +629,6 @@ class FileInformation(Builtin): >> FileInformation["ExampleData/sunflowers.jpg"] = {File -> ..., FileType -> File, ByteCount -> 142286, Date -> ...} - - #> FileInformation["ExampleData/missing_file.jpg"] - = {} """ rules = { @@ -688,9 +654,6 @@ class FindFile(Builtin): >> FindFile["VectorAnalysis`VectorAnalysis`"] = ... - - #> FindFile["SomeTypoPackage`"] - = $Failed """ messages = { @@ -938,97 +901,6 @@ class Needs(Builtin): >> Needs["VectorAnalysis`"] - #> Needs["VectorAnalysis`"] - - #> Needs["SomeFakePackageOrTypo`"] - : Cannot open SomeFakePackageOrTypo`. - : Context SomeFakePackageOrTypo` was not created when Needs was evaluated. - = $Failed - - #> Needs["VectorAnalysis"] - : Invalid context specified at position 1 in Needs[VectorAnalysis]. A context must consist of valid symbol names separated by and ending with `. - = Needs[VectorAnalysis] - - ## --- VectorAnalysis --- - - #> Needs["VectorAnalysis`"] - - #> DotProduct[{1,2,3}, {4,5,6}] - = 32 - #> DotProduct[{-1.4, 0.6, 0.2}, {0.1, 0.6, 1.7}] - = 0.56 - - #> CrossProduct[{1,2,3}, {4,5,6}] - = {-3, 6, -3} - #> CrossProduct[{-1.4, 0.6, 0.2}, {0.1, 0.6, 1.7}] - = {0.9, 2.4, -0.9} - - #> ScalarTripleProduct[{-2,3,1},{0,4,0},{-1,3,3}] - = -20 - #> ScalarTripleProduct[{-1.4,0.6,0.2}, {0.1,0.6,1.7}, {0.7,-1.5,-0.2}] - = -2.79 - - #> CoordinatesToCartesian[{2, Pi, 3}, Spherical] - = {0, 0, -2} - #> CoordinatesFromCartesian[%, Spherical] - = {2, Pi, 0} - #> CoordinatesToCartesian[{2, Pi, 3}, Cylindrical] - = {-2, 0, 3} - #> CoordinatesFromCartesian[%, Cylindrical] - = {2, Pi, 3} - ## Needs Sin/Cos exact value (PR #100) for these tests to pass - ## #> CoordinatesToCartesian[{2, Pi / 4, Pi / 3}, Spherical] - ## = {Sqrt[2] / 2, Sqrt[6] / 2, Sqrt[2]} - ## #> CoordinatesFromCartesian[%, Spherical] - ## = {2, Pi / 4, Pi / 3} - ## #> CoordinatesToCartesian[{2, Pi / 4, -1}, Cylindrical] - ## = {Sqrt[2], Sqrt[2], -1} - ## #> CoordinatesFromCartesian[%, Cylindrical] - ## = {2, Pi / 4, -1} - #> CoordinatesToCartesian[{0.27, 0.51, 0.92}, Cylindrical] - = {0.235641, 0.131808, 0.92} - #> CoordinatesToCartesian[{0.27, 0.51, 0.92}, Spherical] - = {0.0798519, 0.104867, 0.235641} - - #> Coordinates[] - = {Xx, Yy, Zz} - #> Coordinates[Spherical] - = {Rr, Ttheta, Pphi} - #> SetCoordinates[Cylindrical] - = Cylindrical[Rr, Ttheta, Zz] - #> Coordinates[] - = {Rr, Ttheta, Zz} - #> CoordinateSystem - = Cylindrical - #> Parameters[] - = {} - #> CoordinateRanges[] - ## = {0 <= Rr < Infinity, -Pi < Ttheta <= Pi, -Infinity < Zz < Infinity} - = {0 <= Rr && Rr < Infinity, -Pi < Ttheta && Ttheta <= Pi, -Infinity < Zz < Infinity} - #> CoordinateRanges[Cartesian] - = {-Infinity < Xx < Infinity, -Infinity < Yy < Infinity, -Infinity < Zz < Infinity} - #> ScaleFactors[Cartesian] - = {1, 1, 1} - #> ScaleFactors[Spherical] - = {1, Rr, Rr Sin[Ttheta]} - #> ScaleFactors[Cylindrical] - = {1, Rr, 1} - #> ScaleFactors[{2, 1, 3}, Cylindrical] - = {1, 2, 1} - #> JacobianDeterminant[Cartesian] - = 1 - #> JacobianDeterminant[Spherical] - = Rr ^ 2 Sin[Ttheta] - #> JacobianDeterminant[Cylindrical] - = Rr - #> JacobianDeterminant[{2, 1, 3}, Cylindrical] - = 2 - #> JacobianMatrix[Cartesian] - = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}} - #> JacobianMatrix[Spherical] - = {{Cos[Pphi] Sin[Ttheta], Rr Cos[Pphi] Cos[Ttheta], -Rr Sin[Pphi] Sin[Ttheta]}, {Sin[Pphi] Sin[Ttheta], Rr Cos[Ttheta] Sin[Pphi], Rr Cos[Pphi] Sin[Ttheta]}, {Cos[Ttheta], -Rr Sin[Ttheta], 0}} - #> JacobianMatrix[Cylindrical] - = {{Cos[Ttheta], -Rr Sin[Ttheta], 0}, {Sin[Ttheta], Rr Cos[Ttheta], 0}, {0, 0, 1}} """ messages = { @@ -1223,10 +1095,6 @@ class SetDirectory(Builtin): S> SetDirectory[] = ... - - #> SetDirectory["MathicsNonExample"] - : Cannot set current directory to MathicsNonExample. - = $Failed """ messages = { diff --git a/mathics/builtin/files_io/importexport.py b/mathics/builtin/files_io/importexport.py index 42a147eb9..01e2b8ac0 100644 --- a/mathics/builtin/files_io/importexport.py +++ b/mathics/builtin/files_io/importexport.py @@ -1197,7 +1197,7 @@ class RegisterExport(Builtin): >> FilePrint["sample.txt"] | Encode this string! - #> DeleteFile["sample.txt"] + >> DeleteFile["sample.txt"] Very basic encrypted text exporter: >> ExampleExporter2[filename_, data_, opts___] := Module[{strm = OpenWrite[filename], char}, (* TODO: Check data *) char = FromCharacterCode[Mod[ToCharacterCode[data] - 84, 26] + 97]; WriteString[strm, char]; Close[strm]] @@ -1209,7 +1209,7 @@ class RegisterExport(Builtin): >> FilePrint["sample.txt"] | rapbqrguvffgevat - #> DeleteFile["sample.txt"] + >> DeleteFile["sample.txt"] """ summary_text = "register an exporter for a file format" @@ -1247,13 +1247,6 @@ class URLFetch(Builtin):
    'URLFetch[$URL$]'
    Returns the content of $URL$ as a string. - - - #> Quiet[URLFetch["https:////", {}]] - = $Failed - - ##> Quiet[URLFetch["https://www.example.com", {}]] - # = ... """ summary_text = "fetch data from a URL" @@ -1340,38 +1333,16 @@ class Import(Builtin):
    imports from a URL. - #> Import["ExampleData/ExampleData.tx"] - : File not found during Import. - = $Failed - #> Import[x] - : First argument x is not a valid file, directory, or URL specification. - = $Failed - - ## CSV - #> Import["ExampleData/numberdata.csv", "Elements"] - = {Data, Grid} - #> Import["ExampleData/numberdata.csv", "Data"] - = {{0.88, 0.60, 0.94}, {0.76, 0.19, 0.51}, {0.97, 0.04, 0.26}, {0.33, 0.74, 0.79}, {0.42, 0.64, 0.56}} - #> Import["ExampleData/numberdata.csv"] - = {{0.88, 0.60, 0.94}, {0.76, 0.19, 0.51}, {0.97, 0.04, 0.26}, {0.33, 0.74, 0.79}, {0.42, 0.64, 0.56}} - #> Import["ExampleData/numberdata.csv", "FieldSeparators" -> "."] - = {{0, 88,0, 60,0, 94}, {0, 76,0, 19,0, 51}, {0, 97,0, 04,0, 26}, {0, 33,0, 74,0, 79}, {0, 42,0, 64,0, 56}} ## Text >> Import["ExampleData/ExampleData.txt", "Elements"] = {Data, Lines, Plaintext, String, Words} >> Import["ExampleData/ExampleData.txt", "Lines"] = ... - #> Import["ExampleData/Middlemarch.txt"]; - : An invalid unicode sequence was encountered and ignored. ## JSON >> Import["ExampleData/colors.json"] = {colorsArray -> {{colorName -> black, rgbValue -> (0, 0, 0), hexValue -> #000000}, {colorName -> red, rgbValue -> (255, 0, 0), hexValue -> #FF0000}, {colorName -> green, rgbValue -> (0, 255, 0), hexValue -> #00FF00}, {colorName -> blue, rgbValue -> (0, 0, 255), hexValue -> #0000FF}, {colorName -> yellow, rgbValue -> (255, 255, 0), hexValue -> #FFFF00}, {colorName -> cyan, rgbValue -> (0, 255, 255), hexValue -> #00FFFF}, {colorName -> magenta, rgbValue -> (255, 0, 255), hexValue -> #FF00FF}, {colorName -> white, rgbValue -> (255, 255, 255), hexValue -> #FFFFFF}}} - - ## XML - #> Import["ExampleData/InventionNo1.xml", "Tags"] - = {accidental, alter, arpeggiate, ..., words} """ messages = { @@ -1632,26 +1603,6 @@ class ImportString(Import):
    attempts to determine the format of the string from its content. - - #> ImportString[x] - : First argument x is not a string. - = $Failed - - ## CSV - #> datastring = "0.88, 0.60, 0.94\\n.076, 0.19, .51\\n0.97, 0.04, .26"; - #> ImportString[datastring, "Elements"] - = {Data, Lines, Plaintext, String, Words} - #> ImportString[datastring, {"CSV","Elements"}] - = {Data, Grid} - #> ImportString[datastring, {"CSV", "Data"}] - = {{0.88, 0.60, 0.94}, {.076, 0.19, .51}, {0.97, 0.04, .26}} - #> ImportString[datastring] - = 0.88, 0.60, 0.94 - . .076, 0.19, .51 - . 0.97, 0.04, .26 - #> ImportString[datastring, "CSV","FieldSeparators" -> "."] - = {{0, 88, 0, 60, 0, 94}, {076, 0, 19, , 51}, {0, 97, 0, 04, , 26}} - ## Text >> str = "Hello!\\n This is a testing text\\n"; >> ImportString[str, "Elements"] @@ -1736,49 +1687,6 @@ class Export(Builtin):
    'Export["$file$", $exprs$, $elems$]'
    exports $exprs$ to a file as elements specified by $elems$. - - ## Invalid Filename - #> Export["abc.", 1+2] - : Cannot infer format of file abc.. - = $Failed - #> Export[".ext", 1+2] - : Cannot infer format of file .ext. - = $Failed - #> Export[x, 1+2] - : First argument x is not a valid file specification. - = $Failed - - ## Explicit Format - #> Export["abc.txt", 1+x, "JPF"] - : {JPF} is not a valid set of export elements for the Text format. - = $Failed - #> Export["abc.txt", 1+x, {"JPF"}] - : {JPF} is not a valid set of export elements for the Text format. - = $Failed - - ## Empty elems - #> Export["123.txt", 1+x, {}] - = 123.txt - #> Export["123.jcp", 1+x, {}] - : Cannot infer format of file 123.jcp. - = $Failed - - ## Compression - ## #> Export["abc.txt", 1+x, "ZIP"] (* MMA Bug - Export::type *) - ## : {ZIP} is not a valid set of export elements for the Text format. - ## = $Failed - ## #> Export["abc.txt", 1+x, "BZIP"] (* MMA Bug - General::stop *) - ## : {BZIP} is not a valid set of export elements for the Text format. - ## = $Failed - ## #> Export["abc.txt", 1+x, {"BZIP", "ZIP", "Text"}] - ## = abc.txt - ## #> Export["abc.txt", 1+x, {"GZIP", "Text"}] - ## = abc.txt - ## #> Export["abc.txt", 1+x, {"BZIP2", "Text"}] - ## = abc.txt - - ## FORMATS - """ messages = { @@ -2146,43 +2054,6 @@ class FileFormat(Builtin): >> FileFormat["ExampleData/hedy.tif"] = TIFF - - ## ASCII text - #> FileFormat["ExampleData/BloodToilTearsSweat.txt"] - = Text - #> FileFormat["ExampleData/MadTeaParty.gif"] - = GIF - #> FileFormat["ExampleData/moon.tif"] - = TIFF - - #> FileFormat["ExampleData/numberdata.csv"] - = CSV - - #> FileFormat["ExampleData/EinsteinSzilLetter.txt"] - = Text - - #> FileFormat["ExampleData/BloodToilTearsSweat.txt"] - = Text - - ## Doesn't work on Microsoft Windows - ## S> FileFormat["ExampleData/benzene.xyz"] - ## = XYZ - - #> FileFormat["ExampleData/colors.json"] - = JSON - - #> FileFormat["ExampleData/some-typo.extension"] - : File not found during FileFormat[ExampleData/some-typo.extension]. - = $Failed - - #> FileFormat["ExampleData/Testosterone.svg"] - = SVG - - #> FileFormat["ExampleData/colors.json"] - = JSON - - #> FileFormat["ExampleData/InventionNo1.xml"] - = XML """ summary_text = "determine the file format of a file" diff --git a/mathics/builtin/intfns/combinatorial.py b/mathics/builtin/intfns/combinatorial.py index 681f9277d..22a77f486 100644 --- a/mathics/builtin/intfns/combinatorial.py +++ b/mathics/builtin/intfns/combinatorial.py @@ -113,10 +113,6 @@ class Binomial(MPMathFunction): = 0 >> Binomial[-10.5, -3.5] = 0. - - ## TODO should be ComplexInfinity but mpmath returns +inf - #> Binomial[-10, -3.5] - = Infinity """ attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED @@ -411,90 +407,10 @@ class Subsets(Builtin): 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}, {}} - - #> Subsets[{}] - = {{}} - - #> Subsets[] - = Subsets[] - - #> Subsets[{a, b, c}, 2.5] - : Position 2 of Subsets[{a, b, c}, 2.5] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer - = Subsets[{a, b, c}, 2.5] - - #> Subsets[{a, b, c}, -1] - : Position 2 of Subsets[{a, b, c}, -1] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer - = Subsets[{a, b, c}, -1] - - #> Subsets[{a, b, c}, {3, 4, 5, 6}] - : Position 2 of Subsets[{a, b, c}, {3, 4, 5, 6}] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer - = Subsets[{a, b, c}, {3, 4, 5, 6}] - - #> Subsets[{a, b, c}, {-1, 2}] - : Position 2 of Subsets[{a, b, c}, {-1, 2}] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer - = Subsets[{a, b, c}, {-1, 2}] - - #> Subsets[{a, b, c}, All] - = {{}, {a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, b, c}} - - #> Subsets[{a, b, c}, Infinity] - = {{}, {a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, b, c}} - - #> Subsets[{a, b, c}, ALL] - : Position 2 of Subsets[{a, b, c}, ALL] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer - = Subsets[{a, b, c}, ALL] - - #> Subsets[{a, b, c}, {a}] - : Position 2 of Subsets[{a, b, c}, {a}] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer - = Subsets[{a, b, c}, {a}] - - #> Subsets[{a, b, c}, {}] - : Position 2 of Subsets[{a, b, c}, {}] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer - = Subsets[{a, b, c}, {}] - - #> Subsets[{a, b}, 0] - = {{}} - - #> Subsets[{1, 2}, x] - : Position 2 of Subsets[{1, 2}, x] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer - = Subsets[{1, 2}, x] - - #> Subsets[x] - : Nonatomic expression expected at position 1 in Subsets[x]. - = Subsets[x] - - #> Subsets[x, {1, 2}] - : Nonatomic expression expected at position 1 in Subsets[x, {1, 2}]. - = Subsets[x, {1, 2}] - - #> Subsets[x, {1, 2, 3}, {1, 3}] - : Nonatomic expression expected at position 1 in Subsets[x, {1, 2, 3}, {1, 3}]. - = Subsets[x, {1, 2, 3}, {1, 3}] - - #> Subsets[a + b + c] - = {0, a, b, c, a + b, a + c, b + c, a + b + c} - - #> Subsets[f[a, b, c]] - = {f[], f[a], f[b], f[c], f[a, b], f[a, c], f[b, c], f[a, b, c]} - - #> Subsets[a + b + c, {1, 3, 2}] - = {a, b, c, a + b + c} - - #> Subsets[a* b * c, All, {6}] - = {a c} - - #> Subsets[{a, b, c}, {1, Infinity}] - = {{a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, b, c}} - - #> Subsets[{a, b, c}, {1, Infinity, 2}] - = {{a}, {b}, {c}, {a, b, c}} - - #> Subsets[{a, b, c}, {3, Infinity, -1}] - = {} """ messages = { - "nninfseq": "Position 2 of `1` must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer", + "nninfseq": "Position 2 of `1` must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer.", "normal": "Nonatomic expression expected at position 1 in `1`.", } diff --git a/mathics/builtin/intfns/divlike.py b/mathics/builtin/intfns/divlike.py index 864558707..b68dfd5ea 100644 --- a/mathics/builtin/intfns/divlike.py +++ b/mathics/builtin/intfns/divlike.py @@ -298,16 +298,6 @@ class Quotient(Builtin): >> Quotient[23, 7] = 3 - - #> Quotient[13, 0] - : Infinite expression Quotient[13, 0] encountered. - = ComplexInfinity - #> Quotient[-17, 7] - = -3 - #> Quotient[-17, -4] - = 4 - #> Quotient[19, -4] - = -5 """ attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED @@ -338,24 +328,6 @@ class QuotientRemainder(Builtin): >> QuotientRemainder[23, 7] = {3, 2} - - #> QuotientRemainder[13, 0] - : The argument 0 in QuotientRemainder[13, 0] should be nonzero. - = QuotientRemainder[13, 0] - #> QuotientRemainder[-17, 7] - = {-3, 4} - #> QuotientRemainder[-17, -4] - = {4, -1} - #> QuotientRemainder[19, -4] - = {-5, -1} - #> QuotientRemainder[a, 0] - = QuotientRemainder[a, 0] - #> QuotientRemainder[a, b] - = QuotientRemainder[a, b] - #> QuotientRemainder[5.2,2.5] - = {2, 0.2} - #> QuotientRemainder[5, 2.] - = {2, 1.} """ attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED diff --git a/mathics/builtin/intfns/recurrence.py b/mathics/builtin/intfns/recurrence.py index aaf544c36..c28637069 100644 --- a/mathics/builtin/intfns/recurrence.py +++ b/mathics/builtin/intfns/recurrence.py @@ -63,9 +63,6 @@ class HarmonicNumber(MPMathFunction): >> HarmonicNumber[3.8] = 2.03806 - - #> HarmonicNumber[-1.5] - = 0.613706 """ rules = { diff --git a/mathics/builtin/numbers/algebra.py b/mathics/builtin/numbers/algebra.py index 9c21f7782..178d424ab 100644 --- a/mathics/builtin/numbers/algebra.py +++ b/mathics/builtin/numbers/algebra.py @@ -373,12 +373,6 @@ class Apart(Builtin): But it does not touch other expressions: >> Sin[1 / (x ^ 2 - y ^ 2)] // Apart = Sin[1 / (x ^ 2 - y ^ 2)] - - #> Attributes[f] = {HoldAll}; Apart[f[x + x]] - = f[x + x] - - #> Attributes[f] = {}; Apart[f[x + x]] - = f[2 x] """ attributes = A_LISTABLE | A_PROTECTED @@ -504,25 +498,9 @@ class Coefficient(Builtin): >> Coefficient[a x^2 + b y^3 + c x + d y + 5, x, 0] = 5 + b y ^ 3 + d y - ## Errors: - #> Coefficient[x + y + 3] - : Coefficient called with 1 argument; 2 or 3 arguments are expected. - = Coefficient[3 + x + y] - #> Coefficient[x + y + 3, 5] - : 5 is not a valid variable. - = Coefficient[3 + x + y, 5] - - ## 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] - ## = x y - ## ## Sympy 1.0 retuns 0 - ## ## TODO: Support Modulus ## >> Coefficient[(x + 2)^3 + (x + 3)^2, x, 0, Modulus -> 3] ## = 2 - ## #> Coefficient[(x + 2)^3 + (x + 3)^2, x, 0, {Modulus -> 3, Modulus -> 2, Modulus -> 10}] - ## = {2, 1, 7} """ attributes = A_LISTABLE | A_PROTECTED @@ -910,21 +888,11 @@ class CoefficientList(Builtin): = {2 / (-3 + y), 1 / (-3 + y) + 1 / (-2 + y)} >> CoefficientList[(x + y)^3, z] = {(x + y) ^ 3} - #> CoefficientList[x + y, 5] - : 5 is not a valid variable. - = CoefficientList[x + y, 5] - ## Form 2 CoefficientList[poly, {var1, var2, ...}] >> CoefficientList[a x^2 + b y^3 + c x + d y + 5, {x, y}] = {{5, d, 0, b}, {c, 0, 0, 0}, {a, 0, 0, 0}} >> CoefficientList[(x - 2 y + 3 z)^3, {x, y, z}] = {{{0, 0, 0, 27}, {0, 0, -54, 0}, {0, 36, 0, 0}, {-8, 0, 0, 0}}, {{0, 0, 27, 0}, {0, -36, 0, 0}, {12, 0, 0, 0}, {0, 0, 0, 0}}, {{0, 9, 0, 0}, {-6, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, {{1, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}} - #> CoefficientList[(x - 2 y)^4, {x, 2}] - : 2 is not a valid variable. - = CoefficientList[(x - 2 y) ^ 4, {x, 2}] - #> CoefficientList[x / y, {x, y}] - : x / y is not a polynomial. - = CoefficientList[x / y, {x, y}] """ messages = { @@ -1182,22 +1150,6 @@ class Expand(_Expand): >> Expand[(1 + a)^12, Modulus -> 4] = 1 + 2 a ^ 2 + 3 a ^ 4 + 3 a ^ 8 + 2 a ^ 10 + a ^ 12 - - #> Expand[x, Modulus -> -1] (* copy odd MMA behaviour *) - = 0 - #> Expand[x, Modulus -> x] - : Value of option Modulus -> x should be an integer. - = Expand[x, Modulus -> x] - - #> a(b(c+d)+e) // Expand - = a b c + a b d + a e - - #> (y^2)^(1/2)/(2x+2y)//Expand - = Sqrt[y ^ 2] / (2 x + 2 y) - - - #> 2(3+2x)^2/(5+x^2+3x)^3 // Expand - = 24 x / (5 + 3 x + x ^ 2) ^ 3 + 8 x ^ 2 / (5 + 3 x + x ^ 2) ^ 3 + 18 / (5 + 3 x + x ^ 2) ^ 3 """ summary_text = "expand out products and powers" @@ -1303,15 +1255,6 @@ class ExpandDenominator(_Expand): >> ExpandDenominator[(a + b) ^ 2 / ((c + d)^2 (e + f))] = (a + b) ^ 2 / (c ^ 2 e + c ^ 2 f + 2 c d e + 2 c d f + d ^ 2 e + d ^ 2 f) - - ## Modulus option - #> ExpandDenominator[1 / (x + y)^3, Modulus -> 3] - = 1 / (x ^ 3 + y ^ 3) - #> ExpandDenominator[1 / (x + y)^6, Modulus -> 4] - = 1 / (x ^ 6 + 2 x ^ 5 y + 3 x ^ 4 y ^ 2 + 3 x ^ 2 y ^ 4 + 2 x y ^ 5 + y ^ 6) - - #> ExpandDenominator[2(3+2x)^2/(5+x^2+3x)^3] - = 2 (3 + 2 x) ^ 2 / (125 + 225 x + 210 x ^ 2 + 117 x ^ 3 + 42 x ^ 4 + 9 x ^ 5 + x ^ 6) """ summary_text = "expand just the denominator of a rational expression" @@ -1354,11 +1297,6 @@ class Exponent(Builtin): = -Infinity >> Exponent[1, x] = 0 - - ## errors: - #> Exponent[x^2] - : Exponent called with 1 argument; 2 or 3 arguments are expected. - = Exponent[x ^ 2] """ attributes = A_LISTABLE | A_PROTECTED @@ -1422,10 +1360,6 @@ class Factor(Builtin): You can use Factor to find when a polynomial is zero: >> x^2 - x == 0 // Factor = x (-1 + x) == 0 - - ## Issue659 - #> Factor[{x+x^2}] - = {x (1 + x)} """ attributes = A_LISTABLE | A_PROTECTED @@ -1467,9 +1401,6 @@ class FactorTermsList(Builtin): = {2, -1 + x ^ 2} >> FactorTermsList[x^2 - 2 x + 1] = {1, 1 - 2 x + x ^ 2} - #> FactorTermsList[2 x^2 - 2, x] - = {2, 1, -1 + x ^ 2} - >> f = 3 (-1 + 2 x) (-1 + y) (1 - a) = 3 (-1 + 2 x) (-1 + y) (1 - a) >> FactorTermsList[f] @@ -1775,17 +1706,6 @@ class MinimalPolynomial(Builtin): = -2 - 2 x ^ 2 + x ^ 4 >> MinimalPolynomial[Sqrt[I + Sqrt[6]], x] = 49 - 10 x ^ 4 + x ^ 8 - - #> MinimalPolynomial[7a, x] - : 7 a is not an explicit algebraic number. - = MinimalPolynomial[7 a, x] - #> MinimalPolynomial[3x^3 + 2x^2 + y^2 + ab, x] - : ab + 2 x ^ 2 + 3 x ^ 3 + y ^ 2 is not an explicit algebraic number. - = MinimalPolynomial[ab + 2 x ^ 2 + 3 x ^ 3 + y ^ 2, x] - - ## PurePoly - #> MinimalPolynomial[Sqrt[2 + Sqrt[3]]] - = 1 - 4 #1 ^ 2 + #1 ^ 4 """ attributes = A_LISTABLE | A_PROTECTED @@ -1874,37 +1794,6 @@ class PolynomialQ(Builtin): = True >> PolynomialQ[x^2 + axy^2 - bSin[c], {a, b, c}] = False - - #> PolynomialQ[x, x, y] - : PolynomialQ called with 3 arguments; 1 or 2 arguments are expected. - = PolynomialQ[x, x, y] - - ## Always return True if argument is Null - #> PolynomialQ[x^3 - 2 x/y + 3xz,] - : Warning: comma encountered with no adjacent expression. The expression will be treated as Null (line 1 of ""). - = True - #> PolynomialQ[, {x, y, z}] - : Warning: comma encountered with no adjacent expression. The expression will be treated as Null (line 1 of ""). - = True - #> PolynomialQ[, ] - : Warning: comma encountered with no adjacent expression. The expression will be treated as Null (line 1 of ""). - : Warning: comma encountered with no adjacent expression. The expression will be treated as Null (line 1 of ""). - = True - - ## TODO: MMA and Sympy handle these cases differently - ## #> PolynomialQ[x^(1/2) + 6xyz] - ## : No variable is not supported in PolynomialQ. - ## = True - ## #> PolynomialQ[x^(1/2) + 6xyz, {}] - ## : No variable is not supported in PolynomialQ. - ## = True - - ## #> PolynomialQ[x^3 - 2 x/y + 3xz] - ## : No variable is not supported in PolynomialQ. - ## = False - ## #> PolynomialQ[x^3 - 2 x/y + 3xz, {}] - ## : No variable is not supported in PolynomialQ. - ## = False """ messages = { @@ -1994,9 +1883,6 @@ class Together(Builtin): But it does not touch other functions: >> Together[f[a / c + b / c]] = f[a / c + b / c] - - #> f[x]/x+f[x]/x^2//Together - = f[x] (1 + x) / x ^ 2 """ attributes = A_LISTABLE | A_PROTECTED @@ -2030,9 +1916,6 @@ class Variables(Builtin): = {a, b, c, x, y} >> Variables[x + Sin[y]] = {x, Sin[y]} - ## failing test case from MMA docs - #> Variables[E^x] - = {} """ summary_text = "list of variables in a polynomial" diff --git a/mathics/builtin/numbers/calculus.py b/mathics/builtin/numbers/calculus.py index ad5c38a1d..f6f39fd47 100644 --- a/mathics/builtin/numbers/calculus.py +++ b/mathics/builtin/numbers/calculus.py @@ -172,24 +172,6 @@ class D(SympyFunction): Hesse matrix: >> D[Sin[x] * Cos[y], {{x,y}, 2}] = {{-Cos[y] Sin[x], -Cos[x] Sin[y]}, {-Cos[x] Sin[y], -Cos[y] Sin[x]}} - - #> D[2/3 Cos[x] - 1/3 x Cos[x] Sin[x] ^ 2,x]//Expand - = -2 x Cos[x] ^ 2 Sin[x] / 3 + x Sin[x] ^ 3 / 3 - 2 Sin[x] / 3 - Cos[x] Sin[x] ^ 2 / 3 - - #> D[f[#1], {#1,2}] - = f''[#1] - #> D[(#1&)[t],{t,4}] - = 0 - - #> Attributes[f] ={HoldAll}; Apart[f''[x + x]] - = f''[2 x] - - #> Attributes[f] = {}; Apart[f''[x + x]] - = f''[2 x] - - ## Issue #375 - #> D[{#^2}, #] - = {2 #1} """ # TODO @@ -416,16 +398,6 @@ class Derivative(PostfixOperator, SympyFunction): = Derivative[2, 1][h] >> Derivative[2, 0, 1, 0][h[g]] = Derivative[2, 0, 1, 0][h[g]] - - ## Parser Tests - #> Hold[f''] // FullForm - = Hold[Derivative[2][f]] - #> Hold[f ' '] // FullForm - = Hold[Derivative[2][f]] - #> Hold[f '' ''] // FullForm - = Hold[Derivative[4][f]] - #> Hold[Derivative[x][4] '] // FullForm - = Hold[Derivative[1][Derivative[x][4]]] """ attributes = A_N_HOLD_ALL @@ -866,12 +838,8 @@ class FindRoot(_BaseFinder): = FindRoot[Sin[x] - x, {x, 0}] - #> FindRoot[2.5==x,{x,0}] - = {x -> 2.5} - >> FindRoot[x^2 - 2, {x, 1,3}, Method->"Secant"] = {x -> 1.41421} - """ rules = { @@ -972,20 +940,6 @@ class Integrate(SympyFunction): >> Integrate[f[x], {x, a, b}] // TeXForm = \int_a^b f\left[x\right] \, dx - #> DownValues[Integrate] - = {} - #> Definition[Integrate] - = Attributes[Integrate] = {Protected, ReadProtected} - . - . Options[Integrate] = {Assumptions -> $Assumptions, GenerateConditions -> Automatic, PrincipalValue -> False} - #> Integrate[Hold[x + x], {x, a, b}] - = Integrate[Hold[x + x], {x, a, b}] - #> Integrate[sin[x], x] - = Integrate[sin[x], x] - - #> Integrate[x ^ 3.5 + x, x] - = x ^ 2 / 2 + 0.222222 x ^ 4.5 - Sometimes there is a loss of precision during integration. You can check the precision of your result with the following sequence of commands. @@ -994,20 +948,6 @@ class Integrate(SympyFunction): >> % // Precision = MachinePrecision - #> Integrate[1/(x^5+1), x] - = RootSum[1 + 5 #1 + 25 #1 ^ 2 + 125 #1 ^ 3 + 625 #1 ^ 4&, Log[x + 5 #1] #1&] + Log[1 + x] / 5 - - #> Integrate[ArcTan(x), x] - = x ^ 2 ArcTan / 2 - #> Integrate[E[x], x] - = Integrate[E[x], x] - - #> Integrate[Exp[-(x/2)^2],{x,-Infinity,+Infinity}] - = 2 Sqrt[Pi] - - #> Integrate[Exp[-1/(x^2)], x] - = x E ^ (-1 / x ^ 2) + Sqrt[Pi] Erf[1 / x] - >> Integrate[ArcSin[x / 3], x] = x ArcSin[x / 3] + Sqrt[9 - x ^ 2] diff --git a/mathics/builtin/numbers/diffeqns.py b/mathics/builtin/numbers/diffeqns.py index 383e5322a..9224d81d7 100644 --- a/mathics/builtin/numbers/diffeqns.py +++ b/mathics/builtin/numbers/diffeqns.py @@ -42,48 +42,6 @@ class DSolve(Builtin): >> DSolve[D[y[x, t], t] + 2 D[y[x, t], x] == 0, y[x, t], {x, t}] = {{y[x, t] -> C[1][x - 2 t]}} - - ## FIXME: sympy solves this as `Function[{x}, C[1] + Integrate[ArcSin[f[2 x]], x]]` - ## #> Attributes[f] = {HoldAll}; - ## #> DSolve[f[x + x] == Sin[f'[x]], f, x] - ## : To avoid possible ambiguity, the arguments of the dependent variable in f[x + x] == Sin[f'[x]] should literally match the independent variables. - ## = DSolve[f[x + x] == Sin[f'[x]], f, x] - - ## #> Attributes[f] = {}; - ## #> DSolve[f[x + x] == Sin[f'[x]], f, x] - ## : To avoid possible ambiguity, the arguments of the dependent variable in f[2 x] == Sin[f'[x]] should literally match the independent variables. - ## = DSolve[f[2 x] == Sin[f'[x]], f, x] - - #> DSolve[f'[x] == f[x], f, x] // FullForm - = {{Rule[f, Function[{x}, Times[C[1], Power[E, x]]]]}} - - #> DSolve[f'[x] == f[x], f, x] /. {C[1] -> 1} - = {{f -> (Function[{x}, 1 E ^ x])}} - - #> DSolve[f'[x] == f[x], f, x] /. {C -> D} - = {{f -> (Function[{x}, D[1] E ^ x])}} - - #> DSolve[f'[x] == f[x], f, x] /. {C[1] -> C[0]} - = {{f -> (Function[{x}, C[0] E ^ x])}} - - #> DSolve[f[x] == 0, f, {}] - : {} cannot be used as a variable. - = DSolve[f[x] == 0, f, {}] - - ## Order of arguments shoudn't matter - #> DSolve[D[f[x, y], x] == D[f[x, y], y], f, {x, y}] - = {{f -> (Function[{x, y}, C[1][-x - y]])}} - #> DSolve[D[f[x, y], x] == D[f[x, y], y], f[x, y], {x, y}] - = {{f[x, y] -> C[1][-x - y]}} - #> DSolve[D[f[x, y], x] == D[f[x, y], y], f[x, y], {y, x}] - = {{f[x, y] -> C[1][-x - y]}} - """ - - # XXX sympy #11669 test - """ - #> DSolve[\\[Gamma]'[x] == 0, \\[Gamma], x] - : Hit sympy bug #11669. - = ... """ # TODO: GeneratedParameters option diff --git a/mathics/builtin/numbers/exp.py b/mathics/builtin/numbers/exp.py index e4c626e65..7156ef212 100644 --- a/mathics/builtin/numbers/exp.py +++ b/mathics/builtin/numbers/exp.py @@ -176,9 +176,6 @@ class Exp(MPMathFunction): >> Plot[Exp[x], {x, 0, 3}] = -Graphics- - #> Exp[1.*^20] - : Overflow occurred in computation. - = Overflow[] """ rules = { @@ -206,21 +203,6 @@ class Log(MPMathFunction): = Indeterminate >> Plot[Log[x], {x, 0, 5}] = -Graphics- - - #> Log[1000] / Log[10] // Simplify - = 3 - - #> Log[1.4] - = 0.336472 - - #> Log[Exp[1.4]] - = 1.4 - - #> Log[-1.4] - = 0.336472 + 3.14159 I - - #> N[Log[10], 30] - = 2.30258509299404568401799145468 """ summary_text = "logarithm function" @@ -316,9 +298,6 @@ class LogisticSigmoid(Builtin): >> LogisticSigmoid[{-0.2, 0.1, 0.3}] = {0.450166, 0.524979, 0.574443} - - #> LogisticSigmoid[I Pi] - = LogisticSigmoid[I Pi] """ summary_text = "logistic function" diff --git a/mathics/builtin/numbers/hyperbolic.py b/mathics/builtin/numbers/hyperbolic.py index 8f999077e..9884e619c 100644 --- a/mathics/builtin/numbers/hyperbolic.py +++ b/mathics/builtin/numbers/hyperbolic.py @@ -52,8 +52,6 @@ class ArcCosh(MPMathFunction): = 0. + 1.5708 I >> ArcCosh[0.00000000000000000000000000000000000000] = 1.5707963267948966192313216916397514421 I - #> ArcCosh[1.4] - = 0.867015 """ mpmath_name = "acosh" @@ -94,9 +92,6 @@ class ArcCoth(MPMathFunction): = 0. + 1.5708 I >> ArcCoth[0.5] = 0.549306 - 1.5708 I - - #> ArcCoth[0.000000000000000000000000000000000000000] - = 1.57079632679489661923132169163975144210 I """ summary_text = "inverse hyperbolic cotangent function" diff --git a/mathics/builtin/numbers/integer.py b/mathics/builtin/numbers/integer.py index e2a4c0714..0d9ce034d 100644 --- a/mathics/builtin/numbers/integer.py +++ b/mathics/builtin/numbers/integer.py @@ -256,10 +256,6 @@ class FromDigits(Builtin): = 0 >> FromDigits[""] = 0 - - #> FromDigits[x] - : The input must be a string of digits or a list. - = FromDigits[x, 10] """ summary_text = "integer from a list of digits" diff --git a/mathics/builtin/numbers/linalg.py b/mathics/builtin/numbers/linalg.py index 1a9da9992..d670c4727 100644 --- a/mathics/builtin/numbers/linalg.py +++ b/mathics/builtin/numbers/linalg.py @@ -124,10 +124,6 @@ class Eigenvalues(Builtin): >> Eigenvalues[{{7, 1}, {-4, 3}}] = {5, 5} - - #> Eigenvalues[{{1, 0}, {0}}] - : Argument {{1, 0}, {0}} at position 1 is not a non-empty rectangular matrix. - = Eigenvalues[{{1, 0}, {0}}] """ messages = { @@ -221,9 +217,6 @@ class Eigenvectors(Builtin): >> Eigenvectors[{{0.1, 0.2}, {0.8, 0.5}}] = ... ### = {{-0.355518, -1.15048}, {-0.62896, 0.777438}} - - #> Eigenvectors[{{-2, 1, -1}, {-3, 2, 1}, {-1, 1, 0}}] - = {{1, 7, 3}, {1, 1, 0}, {0, 0, 0}} """ messages = { @@ -365,18 +358,6 @@ class LeastSquares(Builtin): >> LeastSquares[{{1, 1, 1}, {1, 1, 2}}, {1, 3}] : Solving for underdetermined system not implemented. = LeastSquares[{{1, 1, 1}, {1, 1, 2}}, {1, 3}] - - ## Inconsistent system - ideally we'd print a different message - #> LeastSquares[{{1, 1, 1}, {1, 1, 1}}, {1, 0}] - : Solving for underdetermined system not implemented. - = LeastSquares[{{1, 1, 1}, {1, 1, 1}}, {1, 0}] - - #> LeastSquares[{1, {2}}, {1, 2}] - : Argument {1, {2}} at position 1 is not a non-empty rectangular matrix. - = LeastSquares[{1, {2}}, {1, 2}] - #> LeastSquares[{{1, 2}, {3, 4}}, {1, {2}}] - : Argument {1, {2}} at position 2 is not a non-empty rectangular matrix. - = LeastSquares[{{1, 2}, {3, 4}}, {1, {2}}] """ messages = { @@ -510,13 +491,6 @@ class LinearSolve(Builtin): >> LinearSolve[{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, {1, -2, 3}] : Linear equation encountered that has no solution. = LinearSolve[{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, {1, -2, 3}] - - #> LinearSolve[{1, {2}}, {1, 2}] - : Argument {1, {2}} at position 1 is not a non-empty rectangular matrix. - = LinearSolve[{1, {2}}, {1, 2}] - #> LinearSolve[{{1, 2}, {3, 4}}, {1, {2}}] - : Argument {1, {2}} at position 2 is not a non-empty rectangular matrix. - = LinearSolve[{{1, 2}, {3, 4}}, {1, {2}}] """ messages = { @@ -582,13 +556,6 @@ class MatrixExp(Builtin): >> MatrixExp[{{1.5, 0.5}, {0.5, 2.0}}] = {{5.16266, 3.02952}, {3.02952, 8.19218}} - - #> MatrixExp[{{a, 0}, {0, b}}] - = {{E ^ a, 0}, {0, E ^ b}} - - #> MatrixExp[{{1, 0}, {0}}] - : Argument {{1, 0}, {0}} at position 1 is not a non-empty rectangular matrix. - = MatrixExp[{{1, 0}, {0}}] """ messages = { @@ -628,13 +595,6 @@ class MatrixPower(Builtin): >> MatrixPower[{{1, 2}, {2, 5}}, -3] = {{169, -70}, {-70, 29}} - - #> MatrixPower[{{0, x}, {0, 0}}, n] - = MatrixPower[{{0, x}, {0, 0}}, n] - - #> MatrixPower[{{1, 0}, {0}}, 2] - : Argument {{1, 0}, {0}} at position 1 is not a non-empty rectangular matrix. - = MatrixPower[{{1, 0}, {0}}, 2] """ messages = { @@ -681,10 +641,6 @@ class MatrixRank(Builtin): = 3 >> MatrixRank[{{a, b}, {3 a, 3 b}}] = 1 - - #> MatrixRank[{{1, 0}, {0}}] - : Argument {{1, 0}, {0}} at position 1 is not a non-empty rectangular matrix. - = MatrixRank[{{1, 0}, {0}}] """ messages = { @@ -721,10 +677,6 @@ class NullSpace(Builtin): = {} >> MatrixRank[A] = 3 - - #> NullSpace[{1, {2}}] - : Argument {1, {2}} at position 1 is not a non-empty rectangular matrix. - = NullSpace[{1, {2}}] """ messages = { @@ -764,10 +716,6 @@ class PseudoInverse(Builtin): >> PseudoInverse[{{1.0, 2.5}, {2.5, 1.0}}] = {{-0.190476, 0.47619}, {0.47619, -0.190476}} - - #> PseudoInverse[{1, {2}}] - : Argument {1, {2}} at position 1 is not a non-empty rectangular matrix. - = PseudoInverse[{1, {2}}] """ messages = { @@ -798,10 +746,6 @@ class QRDecomposition(Builtin): >> QRDecomposition[{{1, 2}, {3, 4}, {5, 6}}] = {{{Sqrt[35] / 35, 3 Sqrt[35] / 35, Sqrt[35] / 7}, {13 Sqrt[210] / 210, 2 Sqrt[210] / 105, -Sqrt[210] / 42}}, {{Sqrt[35], 44 Sqrt[35] / 35}, {0, 2 Sqrt[210] / 35}}} - - #> QRDecomposition[{1, {2}}] - : Argument {1, {2}} at position 1 is not a non-empty rectangular matrix. - = QRDecomposition[{1, {2}}] """ messages = { @@ -844,10 +788,6 @@ class RowReduce(Builtin): . 0 1 2 . . 0 0 0 - - #> RowReduce[{{1, 0}, {0}}] - : Argument {{1, 0}, {0}} at position 1 is not a non-empty rectangular matrix. - = RowReduce[{{1, 0}, {0}}] """ messages = { @@ -881,15 +821,6 @@ class SingularValueDecomposition(Builtin): >> SingularValueDecomposition[{{1.5, 2.0}, {2.5, 3.0}}] = {{{0.538954, 0.842335}, {0.842335, -0.538954}}, {{4.63555, 0.}, {0., 0.107862}}, {{0.628678, 0.777666}, {-0.777666, 0.628678}}} - - - #> SingularValueDecomposition[{{3/2, 2}, {5/2, 3}}] - : Symbolic SVD is not implemented, performing numerically. - = {{{0.538954, 0.842335}, {0.842335, -0.538954}}, {{4.63555, 0.}, {0., 0.107862}}, {{0.628678, 0.777666}, {-0.777666, 0.628678}}} - - #> SingularValueDecomposition[{1, {2}}] - : Argument {1, {2}} at position 1 is not a non-empty rectangular matrix. - = SingularValueDecomposition[{1, {2}}] """ # Sympy lacks symbolic SVD diff --git a/mathics/builtin/numbers/numbertheory.py b/mathics/builtin/numbers/numbertheory.py index 85687c3db..9e9972238 100644 --- a/mathics/builtin/numbers/numbertheory.py +++ b/mathics/builtin/numbers/numbertheory.py @@ -91,14 +91,6 @@ class Divisors(Builtin): = {1, 2, 4, 8, 11, 16, 22, 32, 44, 64, 88, 176, 352, 704} >> Divisors[{87, 106, 202, 305}] = {{1, 3, 29, 87}, {1, 2, 53, 106}, {1, 2, 101, 202}, {1, 5, 61, 305}} - #> Divisors[0] - = Divisors[0] - #> Divisors[{-206, -502, -1702, 9}] - = {{1, 2, 103, 206}, {1, 2, 251, 502}, {1, 2, 23, 37, 46, 74, 851, 1702}, {1, 3, 9}} - #> Length[Divisors[1000*369]] - = 96 - #> Length[Divisors[305*176*369*100]] - = 672 """ # TODO: support GaussianIntegers @@ -275,21 +267,6 @@ class FractionalPart(Builtin): >> FractionalPart[-5.25] = -0.25 - - #> FractionalPart[b] - = FractionalPart[b] - - #> FractionalPart[{-2.4, -2.5, -3.0}] - = {-0.4, -0.5, 0.} - - #> FractionalPart[14/32] - = 7 / 16 - - #> FractionalPart[4/(1 + 3 I)] - = 2 / 5 - I / 5 - - #> FractionalPart[Pi^20] - = -8769956796 + Pi ^ 20 """ attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_READ_PROTECTED | A_PROTECTED @@ -370,47 +347,6 @@ class MantissaExponent(Builtin): >> MantissaExponent[10, b] = MantissaExponent[10, b] - - #> MantissaExponent[E, Pi] - = {E / Pi, 1} - - #> MantissaExponent[Pi, Pi] - = {1 / Pi, 2} - - #> MantissaExponent[5/2 + 3, Pi] - = {11 / (2 Pi ^ 2), 2} - - #> MantissaExponent[b] - = MantissaExponent[b] - - #> MantissaExponent[17, E] - = {17 / E ^ 3, 3} - - #> MantissaExponent[17., E] - = {0.84638, 3} - - #> MantissaExponent[Exp[Pi], 2] - = {E ^ Pi / 32, 5} - - #> MantissaExponent[3 + 2 I, 2] - : The value 3 + 2 I is not a real number - = MantissaExponent[3 + 2 I, 2] - - #> MantissaExponent[25, 0.4] - : Base 0.4 is not a real number greater than 1. - = MantissaExponent[25, 0.4] - - #> MantissaExponent[0.0000124] - = {0.124, -4} - - #> MantissaExponent[0.0000124, 2] - = {0.812646, -16} - - #> MantissaExponent[0] - = {0, 0} - - #> MantissaExponent[0, 2] - = {0, 0} """ attributes = A_LISTABLE | A_PROTECTED @@ -674,9 +610,6 @@ class PrimePowerQ(Builtin): >> PrimePowerQ[371293] = True - - #> PrimePowerQ[1] - = False """ attributes = A_LISTABLE | A_PROTECTED | A_READ_PROTECTED @@ -687,19 +620,19 @@ class PrimePowerQ(Builtin): # TODO: GaussianIntegers option """ - #> PrimePowerQ[5, GaussianIntegers -> True] + ##> PrimePowerQ[5, GaussianIntegers -> True] = False """ # TODO: Complex args """ - #> PrimePowerQ[{3 + I, 3 - 2 I, 3 + 4 I, 9 + 7 I}] + ##> PrimePowerQ[{3 + I, 3 - 2 I, 3 + 4 I, 9 + 7 I}] = {False, True, True, False} """ # TODO: Gaussian rationals """ - #> PrimePowerQ[2/125 - 11 I/125] + ##> PrimePowerQ[2/125 - 11 I/125] = True """ @@ -740,12 +673,6 @@ class RandomPrime(Builtin): >> RandomPrime[{10,30}, {2,5}] = ... - - #> RandomPrime[{10,12}, {2,2}] - = {{11, 11}, {11, 11}} - - #> RandomPrime[2, {3,2}] - = {{2, 2}, {2, 2}, {2, 2}} """ messages = { diff --git a/mathics/builtin/numbers/randomnumbers.py b/mathics/builtin/numbers/randomnumbers.py index 580ce0c35..77910941e 100644 --- a/mathics/builtin/numbers/randomnumbers.py +++ b/mathics/builtin/numbers/randomnumbers.py @@ -334,25 +334,15 @@ class RandomComplex(Builtin): >> RandomComplex[] = ... - #> 0 <= Re[%] <= 1 && 0 <= Im[%] <= 1 - = True >> RandomComplex[{1+I, 5+5I}] = ... - #> 1 <= Re[%] <= 5 && 1 <= Im[%] <= 5 - = True >> RandomComplex[1+I, 5] = {..., ..., ..., ..., ...} >> RandomComplex[{1+I, 2+2I}, {2, 2}] = {{..., ...}, {..., ...}} - - #> RandomComplex[{6, 2 Pi + I}] - = 6... - - #> RandomComplex[{6.3, 2.5 I}] // FullForm - = Complex[..., ...] """ messages = { @@ -463,8 +453,6 @@ class RandomInteger(Builtin): >> RandomInteger[{1, 5}] = ... - #> 1 <= % <= 5 - = True >> RandomInteger[100, {2, 3}] // TableForm = ... ... ... @@ -542,21 +530,8 @@ class RandomReal(Builtin): >> RandomReal[] = ... - #> 0 <= % <= 1 - = True - >> RandomReal[{1, 5}] = ... - - ## needs too much horizontal space in TeX form - #> RandomReal[100, {2, 3}] // TableForm - = ... ... ... - . - . ... ... ... - - #> RandomReal[{0, 1}, {1, -1}] - : The array dimensions {1, -1} given in position 2 of RandomReal[{0, 1}, {1, -1}] should be a list of non-negative machine-sized integers giving the dimensions for the result. - = RandomReal[{0, 1}, {1, -1}] """ messages = { @@ -691,10 +666,6 @@ class SeedRandom(Builtin): >> SeedRandom[] >> RandomInteger[100] = ... - - #> SeedRandom[x] - : Argument x should be an integer or string. - = SeedRandom[x] """ messages = { diff --git a/mathics/builtin/numbers/trig.py b/mathics/builtin/numbers/trig.py index 1218ae2b7..8ea925163 100644 --- a/mathics/builtin/numbers/trig.py +++ b/mathics/builtin/numbers/trig.py @@ -550,21 +550,6 @@ class ArcTan(MPMathFunction): >> ArcTan[1, 1] = Pi / 4 - #> ArcTan[-1, 1] - = 3 Pi / 4 - #> ArcTan[1, -1] - = -Pi / 4 - #> ArcTan[-1, -1] - = -3 Pi / 4 - - #> ArcTan[1, 0] - = 0 - #> ArcTan[-1, 0] - = Pi - #> ArcTan[0, 1] - = Pi / 2 - #> ArcTan[0, -1] - = -Pi / 2 """ mpmath_name = "atan" @@ -603,9 +588,6 @@ class Cos(MPMathFunction): >> Cos[3 Pi] = -1 - - #> Cos[1.5 Pi] - = -1.83697×10^-16 """ mpmath_name = "cos" @@ -815,9 +797,6 @@ class Sin(MPMathFunction): >> Plot[Sin[x], {x, -Pi, Pi}] = -Graphics- - - #> N[Sin[1], 40] - = 0.8414709848078965066525023216302989996226 """ mpmath_name = "sin" @@ -855,9 +834,6 @@ class Tan(MPMathFunction): = 0 >> Tan[Pi / 2] = ComplexInfinity - - #> Tan[0.5 Pi] - = 1.63312×10^16 """ mpmath_name = "tan" diff --git a/mathics/builtin/numeric.py b/mathics/builtin/numeric.py index 44c8999ea..63bf5d88e 100644 --- a/mathics/builtin/numeric.py +++ b/mathics/builtin/numeric.py @@ -257,21 +257,6 @@ class N(Builtin): = F[3.14159265358979300000000000000] >> N[F[Pi], 30, Method->"sympy"] = F[3.14159265358979323846264338328] - #> p=N[Pi,100] - = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 - #> ToString[p] - = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 - - #> N[1.012345678901234567890123, 20] - = 1.0123456789012345679 - - #> N[I, 30] - = 1.00000000000000000000000000000 I - - #> N[1.012345678901234567890123, 50] - = 1.01234567890123456789012 - #> % // Precision - = 24. """ options = {"Method": "Automatic"} @@ -454,18 +439,6 @@ class Rationalize(Builtin): Find the exact rational representation of 'N[Pi]' >> Rationalize[N[Pi], 0] = 245850922 / 78256779 - - #> Rationalize[N[Pi] + 0.8 I, x] - : Tolerance specification x must be a non-negative number. - = Rationalize[3.14159 + 0.8 I, x] - - #> Rationalize[N[Pi] + 0.8 I, -1] - : Tolerance specification -1 must be a non-negative number. - = Rationalize[3.14159 + 0.8 I, -1] - - #> Rationalize[x, y] - : Tolerance specification y must be a non-negative number. - = Rationalize[x, y] """ messages = { @@ -769,17 +742,11 @@ class Sign(SympyFunction): = 0 >> Sign[{-5, -10, 15, 20, 0}] = {-1, -1, 1, 1, 0} - #> Sign[{1, 2.3, 4/5, {-6.7, 0}, {8/9, -10}}] - = {1, 1, 1, {-1, 0}, {1, -1}} + + For a complex number, 'Sign' returns the phase of the number: >> Sign[3 - 4*I] = 3 / 5 - 4 I / 5 - #> Sign[1 - 4*I] == (1/17 - 4 I/17) Sqrt[17] - = True - #> Sign[4, 5, 6] - : Sign called with 3 arguments; 1 argument is expected. - = Sign[4, 5, 6] - #> Sign["20"] - = Sign[20] + """ summary_text = "complex sign of a number" diff --git a/mathics/builtin/specialfns/bessel.py b/mathics/builtin/specialfns/bessel.py index e2e2455da..ebe20fea2 100644 --- a/mathics/builtin/specialfns/bessel.py +++ b/mathics/builtin/specialfns/bessel.py @@ -24,7 +24,6 @@ class _Bessel(MPMathFunction): - attributes = A_LISTABLE | A_NUMERIC_FUNCTION | A_PROTECTED | A_READ_PROTECTED nargs = {2} @@ -109,18 +108,6 @@ class AiryAiZero(Builtin): >> N[AiryAiZero[1]] = -2.33811 - - #> AiryAiZero[1] - = AiryAiZero[1] - - #> AiryAiZero[1.] - = AiryAiZero[1.] - - #> AiryAi[AiryAiZero[1]] - = 0 - - #> N[AiryAiZero[2], 100] - = -4.087949444130970616636988701457391060224764699108529754984160876025121946836047394331169160758270562 """ # TODO: 'AiryAiZero[$k$, $x0$]' - $k$th zero less than x0 @@ -235,18 +222,6 @@ class AiryBiZero(Builtin): >> N[AiryBiZero[1]] = -1.17371 - - #> AiryBiZero[1] - = AiryBiZero[1] - - #> AiryBiZero[1.] - = AiryBiZero[1.] - - #> AiryBi[AiryBiZero[1]] - = 0 - - #> N[AiryBiZero[2], 100] - = -3.271093302836352715680228240166413806300935969100284801485032396261130864238742879252000673830055014 """ # TODO: 'AiryBiZero[$k$, $x0$]' - $k$th zero less than x0 @@ -380,9 +355,6 @@ class BesselJ(_Bessel): >> BesselJ[0, 5.2] = -0.11029 - #> BesselJ[2.5, 1] - = 0.0494968 - >> D[BesselJ[n, z], z] = -BesselJ[1 + n, z] / 2 + BesselJ[-1 + n, z] / 2 diff --git a/mathics/builtin/specialfns/gamma.py b/mathics/builtin/specialfns/gamma.py index 33746fd11..7369e0ba6 100644 --- a/mathics/builtin/specialfns/gamma.py +++ b/mathics/builtin/specialfns/gamma.py @@ -155,8 +155,6 @@ class Factorial(PostfixOperator, MPMathFunction): >> !a! //FullForm = Not[Factorial[a]] - #> 0! - = 1 """ attributes = A_NUMERIC_FUNCTION | A_PROTECTED @@ -301,22 +299,6 @@ class Gamma(MPMathMultiFunction): Both 'Gamma' and 'Factorial' functions are continuous: >> Plot[{Gamma[x], x!}, {x, 0, 4}] = -Graphics- - - ## Issue 203 - #> N[Gamma[24/10], 100] - = 1.242169344504305404913070252268300492431517240992022966055507541481863694148882652446155342679460339 - #> N[N[Gamma[24/10],100]/N[Gamma[14/10],100],100] - = 1.400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - #> % // Precision - = 100. - - #> Gamma[1.*^20] - : Overflow occurred in computation. - = Overflow[] - - ## Needs mpmath support for lowergamma - #> Gamma[1., 2.] - = Gamma[1., 2.] """ mpmath_names = { diff --git a/mathics/builtin/specialfns/orthogonal.py b/mathics/builtin/specialfns/orthogonal.py index 464b148f9..bd2cb002e 100644 --- a/mathics/builtin/specialfns/orthogonal.py +++ b/mathics/builtin/specialfns/orthogonal.py @@ -269,9 +269,6 @@ class SphericalHarmonicY(MPMathFunction): ## Results depend on sympy version >> SphericalHarmonicY[3, 1, theta, phi] = ... - - #> SphericalHarmonicY[1,1,x,y] - = -Sqrt[6] E ^ (I y) Sin[x] / (4 Sqrt[Pi]) """ nargs = {4} diff --git a/mathics/builtin/tensors.py b/mathics/builtin/tensors.py index d58c86bff..bad1a83f4 100644 --- a/mathics/builtin/tensors.py +++ b/mathics/builtin/tensors.py @@ -19,65 +19,17 @@ """ -from mathics.core.atoms import Integer, String +from mathics.core.atoms import Integer from mathics.core.attributes import A_FLAT, A_ONE_IDENTITY, A_PROTECTED from mathics.core.builtin import BinaryOperator, Builtin from mathics.core.evaluation import Evaluation -from mathics.core.expression import Expression from mathics.core.list import ListExpression -from mathics.core.symbols import Atom, Symbol, SymbolFalse, SymbolTrue -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 +from mathics.eval.tensors import ( + eval_Inner, + eval_LeviCivitaTensor, + eval_Outer, + get_dimensions, +) class ArrayDepth(Builtin): @@ -215,46 +167,7 @@ class Inner(Builtin): def eval(self, f, list1, list2, g, evaluation: Evaluation): "Inner[f_, list1_, list2_, g_]" - m = get_dimensions(list1) - n = get_dimensions(list2) - - if not m or not n: - evaluation.message("Inner", "normal") - 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:]) + return eval_Inner(f, list1, list2, g, evaluation) class Outer(Builtin): @@ -273,10 +186,21 @@ class Outer(Builtin): Outer product of two matrices: >> Outer[Times, {{a, b}, {c, d}}, {{1, 2}, {3, 4}}] = {{{{a, 2 a}, {3 a, 4 a}}, {{b, 2 b}, {3 b, 4 b}}}, {{{c, 2 c}, {3 c, 4 c}}, {{d, 2 d}, {3 d, 4 d}}}} + + Outer product of two sparse arrays: + >> Outer[Times, SparseArray[{{1, 2} -> a, {2, 1} -> b}], SparseArray[{{1, 2} -> c, {2, 1} -> d}]] + = SparseArray[Automatic, {2, 2, 2, 2}, 0, {{1, 2, 1, 2} -> a c, {1, 2, 2, 1} -> a d, {2, 1, 1, 2} -> b c, {2, 1, 2, 1} -> b d}] 'Outer' of multiple lists: >> Outer[f, {a, b}, {x, y, z}, {1, 2}] = {{{f[a, x, 1], f[a, x, 2]}, {f[a, y, 1], f[a, y, 2]}, {f[a, z, 1], f[a, z, 2]}}, {{f[b, x, 1], f[b, x, 2]}, {f[b, y, 1], f[b, y, 2]}, {f[b, z, 1], f[b, z, 2]}}} + + 'Outer' converts input sparse arrays to lists if f=!=Times, or if the input is a mixture of sparse arrays and lists: + >> Outer[f, SparseArray[{{1, 2} -> a, {2, 1} -> b}], SparseArray[{{1, 2} -> c, {2, 1} -> d}]] + = {{{{f[0, 0], f[0, c]}, {f[0, d], f[0, 0]}}, {{f[a, 0], f[a, c]}, {f[a, d], f[a, 0]}}}, {{{f[b, 0], f[b, c]}, {f[b, d], f[b, 0]}}, {{f[0, 0], f[0, c]}, {f[0, d], f[0, 0]}}}} + + >> Outer[Times, SparseArray[{{1, 2} -> a, {2, 1} -> b}], {c, d}] + = {{{0, 0}, {a c, a d}}, {{b c, b d}, {0, 0}}} Arrays can be ragged: >> Outer[Times, {{1, 2}}, {{a, b}, {c, d, e}}] @@ -299,32 +223,7 @@ class Outer(Builtin): def eval(self, f, lists, evaluation: Evaluation): "Outer[f_, lists__]" - lists = lists.get_sequence() - head = None - for list in lists: - if isinstance(list, Atom): - evaluation.message("Outer", "normal") - return - if head is None: - head = list.head - elif not list.head.sameQ(head): - evaluation.message("Outer", "heads", head, list.head) - return - - def rec(item, rest_lists, current): - evaluation.check_stopped() - if isinstance(item, Atom) or not item.head.sameQ(head): - if rest_lists: - return rec(rest_lists[0], rest_lists[1:], current + [item]) - else: - return Expression(f, *(current + [item])) - else: - elements = [] - for element in item.elements: - elements.append(rec(element, rest_lists, current)) - return Expression(head, *elements) - - return rec(lists[0], lists[1:], []) + return eval_Outer(f, lists, evaluation) class RotationTransform(Builtin): @@ -450,7 +349,7 @@ class Transpose(Builtin): :WMA: https://reference.wolfram.com/language/ref/Transpose.html)
    -
    'Tranpose[$m$]' +
    'Transpose[$m$]'
    transposes rows and columns in the matrix $m$.
    @@ -490,3 +389,57 @@ def eval(self, m, evaluation: Evaluation): else: result[col_index].append(item) return ListExpression(*[ListExpression(*row) for row in result]) + + +class ConjugateTranspose(Builtin): + """ + + :Conjugate transpose: https://en.wikipedia.org/wiki/Conjugate_transpose ( + :WMA: https://reference.wolfram.com/language/ref/ConjugateTranspose.html) + +
    +
    'ConjugateTranspose[$m$]' +
    gives the conjugate transpose of $m$. +
    + + >> ConjugateTranspose[{{0, I}, {0, 0}}] + = {{0, 0}, {-I, 0}} + + >> ConjugateTranspose[{{1, 2 I, 3}, {3 + 4 I, 5, I}}] + = {{1, 3 - 4 I}, {-2 I, 5}, {3, -I}} + """ + + rules = { + "ConjugateTranspose[m_]": "Conjugate[Transpose[m]]", + } + summary_text = "give the conjugate transpose" + + +class LeviCivitaTensor(Builtin): + """ + :Levi-Civita tensor:https://en.wikipedia.org/wiki/Levi-Civita_symbol \ + (:WMA link:https://reference.wolfram.com/language/ref/LeviCivitaTensor.html) + +
    +
    'LeviCivitaTensor[$d$]' +
    gives the $d$-dimensional Levi-Civita totally antisymmetric tensor. +
    + + >> LeviCivitaTensor[3] + = SparseArray[Automatic, {3, 3, 3}, 0, {{1, 2, 3} -> 1, {1, 3, 2} -> -1, {2, 1, 3} -> -1, {2, 3, 1} -> 1, {3, 1, 2} -> 1, {3, 2, 1} -> -1}] + + >> LeviCivitaTensor[3, List] + = {{{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, {{0, 0, -1}, {0, 0, 0}, {1, 0, 0}}, {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0}}} + """ + + rules = { + "LeviCivitaTensor[d_Integer]/; Greater[d, 0]": "LeviCivitaTensor[d, SparseArray]", + "LeviCivitaTensor[d_Integer, List] /; Greater[d, 0]": "LeviCivitaTensor[d, SparseArray] // Normal", + } + + summary_text = "give the Levi-Civita tensor with a given dimension" + + def eval(self, d, type, evaluation: Evaluation): + "LeviCivitaTensor[d_Integer, type_]" + + return eval_LeviCivitaTensor(d, type) diff --git a/mathics/builtin/testing_expressions/list_oriented.py b/mathics/builtin/testing_expressions/list_oriented.py index b99fe2040..b2f819331 100644 --- a/mathics/builtin/testing_expressions/list_oriented.py +++ b/mathics/builtin/testing_expressions/list_oriented.py @@ -7,10 +7,10 @@ from mathics.core.evaluation import Evaluation from mathics.core.exceptions import InvalidLevelspecError from mathics.core.expression import Expression -from mathics.core.rules import Pattern from mathics.core.symbols import Atom, SymbolFalse, SymbolTrue -from mathics.core.systemsymbols import SymbolSubsetQ +from mathics.core.systemsymbols import SymbolSubsetQ # , SymbolSparseArray from mathics.eval.parts import python_levelspec +from mathics.eval.testing_expressions import check_ArrayQ # , check_SparseArrayQ class ArrayQ(Builtin): @@ -51,37 +51,10 @@ class ArrayQ(Builtin): def eval(self, expr, pattern, test, evaluation: Evaluation): "ArrayQ[expr_, pattern_, test_]" - pattern = Pattern.create(pattern) - - dims = [len(expr.get_elements())] # to ensure an atom is not an array - - def check(level, expr): - if not expr.has_form("List", None): - test_expr = Expression(test, expr) - if test_expr.evaluate(evaluation) != SymbolTrue: - return False - level_dim = None - else: - level_dim = len(expr.elements) - - if len(dims) > level: - if dims[level] != level_dim: - return False - else: - dims.append(level_dim) - if level_dim is not None: - for element in expr.elements: - if not check(level + 1, element): - return False - return True - - if not check(0, expr): - return SymbolFalse + # if not isinstance(expr, Atom) and expr.head.sameQ(SymbolSparseArray): + # return check_SparseArrayQ(expr, pattern, test, evaluation) - depth = len(dims) - 1 # None doesn't count - if not pattern.does_match(Integer(depth), evaluation): - return SymbolFalse - return SymbolTrue + return check_ArrayQ(expr, pattern, test, evaluation) class DisjointQ(Test): diff --git a/mathics/core/symbols.py b/mathics/core/symbols.py index adfe063e9..fca9cbd27 100644 --- a/mathics/core/symbols.py +++ b/mathics/core/symbols.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- import time -from typing import Any, FrozenSet, List, Optional, Tuple +from typing import Any, FrozenSet, List, Optional from mathics.core.element import ( BaseElement, @@ -17,6 +17,7 @@ sympy_symbol_prefix = "_Mathics_User_" sympy_slot_prefix = "_Mathics_Slot_" + # FIXME: This is repeated below class NumericOperators: """ @@ -199,7 +200,8 @@ class Atom(BaseElement): Atom is not a directly-mentioned WL entity, although conceptually it very much seems to exist. - The other kinds expression element is a Builtin, e.g. `ByteArray``, `CompiledCode`` or ``Image``. + The other kinds expression element is a Builtin, e.g. `ByteArray``, `CompiledCode`` + or ``Image``. """ _head_name = "" @@ -251,8 +253,8 @@ def get_atom_name(self) -> str: def get_atoms(self, include_heads=True) -> List["Atom"]: return [self] - # We seem to need this because the caller doesn't distinguish something with elements - # from a single atom. + # We seem to need this because the caller doesn't distinguish + # something with elements from a single atom. def get_elements(self): return [] @@ -262,14 +264,18 @@ def get_head(self) -> "Symbol": def get_head_name(self) -> "str": return self.class_head_name # System`" + self.__class__.__name__ - # def get_option_values(self, evaluation, allow_symbols=False, stop_on_error=True): + # def get_option_values(self, evaluation, allow_symbols=False, + # stop_on_error=True): # """ # Build a dictionary of options from an expression. - # For example Symbol("Integrate").get_option_values(evaluation, allow_symbols=True) - # will return a list of options associated to the definition of the symbol "Integrate". + # For example Symbol("Integrate").get_option_values(evaluation, + # allow_symbols=True) + # will return a list of options associated to the definition of the symbol + # "Integrate". # If self is not an expression, # """ - # print("get_option_values is trivial for ", (self, stop_on_error, allow_symbols )) + # print("get_option_values is trivial for ", (self, stop_on_error, + # allow_symbols )) # 1/0 # return None if stop_on_error else {} @@ -661,7 +667,6 @@ class SymbolConstant(Symbol): # We use __new__ here to unsure that two Integer's that have the same value # return the same object. def __new__(cls, name, value): - name = ensure_context(name) self = cls._symbol_constants.get(name) if self is None: diff --git a/mathics/eval/tensors.py b/mathics/eval/tensors.py new file mode 100644 index 000000000..596c792b0 --- /dev/null +++ b/mathics/eval/tensors.py @@ -0,0 +1,244 @@ +import itertools + +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 Expression +from mathics.core.list import ListExpression +from mathics.core.symbols import ( + Atom, + Symbol, + SymbolFalse, + SymbolList, + SymbolTimes, + SymbolTrue, +) +from mathics.core.systemsymbols import ( + SymbolAutomatic, + SymbolNormal, + 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 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") + 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 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 + 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 + if sparse_to_list: + new_lists = [] + for _list in lists: + if isinstance(_list, Atom): + evaluation.message("Outer", "normal") + 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 + + def rec(item, rest_lists, current): + evaluation.check_stopped() + if isinstance(item, Atom) or not item.head.sameQ(head): + if rest_lists: + return rec(rest_lists[0], rest_lists[1:], current + [item]) + else: + return Expression(f, *(current + [item])) + else: + elements = [] + for element in item.elements: + elements.append(rec(element, rest_lists, current)) + return Expression(head, *elements) + + def rec_sparse(item, rest_lists, current): + evaluation.check_stopped() + if isinstance(item, tuple): # (rules) + elements = [] + for element in item: + elements.extend(rec_sparse(element, rest_lists, current)) + return tuple(elements) + else: # rule + _pos, _val = item.elements + if rest_lists: + return rec_sparse( + rest_lists[0], + rest_lists[1:], + (current[0] + _pos.elements, current[1] * _val), + ) + else: + return ( + Expression( + SymbolRule, + ListExpression(*(current[0] + _pos.elements)), + current[1] * _val, + ), + ) + + # head != SparseArray + if not head.sameQ(SymbolSparseArray): + return rec(lists[0], lists[1:], []) + + # head == SparseArray + dims = [] + val = Integer1 + data = [] # data = [(rules), ...] + for _list in lists: + _dims, _val, _rules = _list.elements[1:] + dims.extend(_dims) + val *= _val + if _val == Integer0: # _val==0, append (_rules) + data.append(_rules.elements) + else: # _val!=0, append (_rules, other pos->_val) + other_pos = [] + for pos in itertools.product(*(range(1, d.value + 1) for d in _dims)): + other_pos.append(ListExpression(*(Integer(i) for i in pos))) + rules_pos = set(rule.elements[0] for rule in _rules.elements) + other_pos = set(other_pos) - rules_pos + other_rules = [] + for pos in other_pos: + other_rules.append(Expression(SymbolRule, pos, _val)) + data.append(_rules.elements + tuple(other_rules)) + dims = ListExpression(*dims) + return Expression( + SymbolSparseArray, + SymbolAutomatic, + dims, + val, + ListExpression(*rec_sparse(data[0], data[1:], ((), Integer1))), + ) + + +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)) diff --git a/mathics/eval/testing_expressions.py b/mathics/eval/testing_expressions.py index 4046d0c8c..2bd751944 100644 --- a/mathics/eval/testing_expressions.py +++ b/mathics/eval/testing_expressions.py @@ -2,13 +2,15 @@ import sympy -from mathics.core.atoms import Complex, Integer0, Integer1, IntegerM1 +from mathics.core.atoms import Complex, Integer, Integer0, Integer1, IntegerM1 +from mathics.core.evaluation import Evaluation from mathics.core.expression import Expression -from mathics.core.systemsymbols import SymbolDirectedInfinity +from mathics.core.rules import Pattern +from mathics.core.symbols import SymbolFalse, SymbolTimes, SymbolTrue +from mathics.core.systemsymbols import SymbolDirectedInfinity, SymbolSparseArray def do_cmp(x1, x2) -> Optional[int]: - # don't attempt to compare complex numbers for x in (x1, x2): # TODO: Send message General::nord @@ -99,3 +101,64 @@ def expr_min(elements): def is_number(sympy_value) -> bool: return hasattr(sympy_value, "is_number") or isinstance(sympy_value, sympy.Float) + + +def check_ArrayQ(expr, pattern, test, evaluation: Evaluation): + "Check if expr is an Array which test yields true for each of its elements." + + pattern = Pattern.create(pattern) + + dims = [len(expr.get_elements())] # to ensure an atom is not an array + + def check(level, expr): + if not expr.has_form("List", None): + test_expr = Expression(test, expr) + if test_expr.evaluate(evaluation) != SymbolTrue: + return False + level_dim = None + else: + level_dim = len(expr.elements) + + if len(dims) > level: + if dims[level] != level_dim: + return False + else: + dims.append(level_dim) + if level_dim is not None: + for element in expr.elements: + if not check(level + 1, element): + return False + return True + + if not check(0, expr): + return SymbolFalse + + depth = len(dims) - 1 # None doesn't count + if not pattern.does_match(Integer(depth), evaluation): + return SymbolFalse + + return SymbolTrue + + +def check_SparseArrayQ(expr, pattern, test, evaluation: Evaluation): + "Check if expr is a SparseArray which test yields true for each of its elements." + + if not expr.head.sameQ(SymbolSparseArray): + return SymbolFalse + + pattern = Pattern.create(pattern) + dims, default_value, rules = expr.elements[1:] + if not pattern.does_match(Integer(len(dims.elements)), evaluation): + return SymbolFalse + + array_size = Expression(SymbolTimes, *dims.elements).evaluate(evaluation) + if array_size.value > len(rules.elements): # expr is not full + test_expr = Expression(test, default_value) # test default value + if test_expr.evaluate(evaluation) != SymbolTrue: + return SymbolFalse + for rule in rules.elements: + test_expr = Expression(test, rule.elements[-1]) + if test_expr.evaluate(evaluation) != SymbolTrue: + return SymbolFalse + + return SymbolTrue diff --git a/setup.py b/setup.py index db43c728f..d78268723 100644 --- a/setup.py +++ b/setup.py @@ -240,18 +240,18 @@ def subdirs(root, file="*.*", depth=10): description="A general-purpose computer algebra system.", license="GPL", url="https://mathics.org/", - download_url="https://github.com/Mathics/mathics-core/releases", + download_url="https://github.com/Mathics3/mathics-core/releases", keywords=["Mathematica", "Wolfram", "Interpreter", "Shell", "Math", "CAS"], classifiers=[ "Intended Audience :: Developers", "Intended Audience :: Science/Research", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Programming Language :: Python", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Scientific/Engineering", diff --git a/test/builtin/arithmetic/test_basic.py b/test/builtin/arithmetic/test_basic.py index 1bec99de7..07e83f1be 100644 --- a/test/builtin/arithmetic/test_basic.py +++ b/test/builtin/arithmetic/test_basic.py @@ -449,3 +449,35 @@ def test_cuberoot(str_expr, str_expected, msgs, failmsg): check_evaluation( str_expr, str_expected, expected_messages=msgs, failure_message=failmsg ) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ## Issue #302 + ## The sum should not converge since the first term is 1/0. + ( + "Sum[i / Log[i], {i, 1, Infinity}]", + None, + "Sum[i / Log[i], {i, 1, Infinity}]", + None, + ), + ( + "Sum[Cos[Pi i], {i, 1, Infinity}]", + None, + "Sum[Cos[i Pi], {i, 1, Infinity}]", + None, + ), + ], +) +def test_private_doctests_arithmetic(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/files_io/test_files.py b/test/builtin/files_io/test_files.py index 3e0a2bf6c..adb0dcc52 100644 --- a/test/builtin/files_io/test_files.py +++ b/test/builtin/files_io/test_files.py @@ -80,6 +80,262 @@ def test_close(): ), f"temporary filename {temp_filename} should not appear" +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ('Close["abc"]', ("abc is not open.",), "Close[abc]", None), + ( + "exp = Sin[1]; FilePrint[exp]", + ("File specification Sin[1] is not a string of one or more characters.",), + "FilePrint[Sin[1]]", + None, + ), + ( + 'FilePrint["somenonexistentpath_h47sdmk^&h4"]', + ("Cannot open somenonexistentpath_h47sdmk^&h4.",), + "FilePrint[somenonexistentpath_h47sdmk^&h4]", + None, + ), + ( + 'FilePrint[""]', + ("File specification is not a string of one or more characters.",), + "FilePrint[]", + None, + ), + ( + 'Get["SomeTypoPackage`"]', + ("Cannot open SomeTypoPackage`.",), + "$Failed", + None, + ), + ## Parser Tests + ( + "Hold[<< ~/some_example/dir/] // FullForm", + None, + 'Hold[Get["~/some_example/dir/"]]', + None, + ), + ( + r"Hold[<<`/.\-_:$*~?] // FullForm", + None, + r'Hold[Get["`/.\\\\-_:$*~?"]]', + None, + ), + ( + "OpenRead[]", + ("OpenRead called with 0 arguments; 1 argument is expected.",), + "OpenRead[]", + None, + ), + ( + "OpenRead[y]", + ("File specification y is not a string of one or more characters.",), + "OpenRead[y]", + None, + ), + ( + 'OpenRead[""]', + ("File specification is not a string of one or more characters.",), + "OpenRead[]", + None, + ), + ( + 'OpenRead["MathicsNonExampleFile"]', + ("Cannot open MathicsNonExampleFile.",), + "OpenRead[MathicsNonExampleFile]", + None, + ), + ( + 'fd=OpenRead["ExampleData/EinsteinSzilLetter.txt", BinaryFormat -> True, CharacterEncoding->"UTF8"]//Head', + None, + "InputStream", + None, + ), + ( + "Close[fd]; fd=.;fd=OpenWrite[BinaryFormat -> True]//Head", + None, + "OutputStream", + None, + ), + ( + 'DeleteFile[Close[fd]];fd=.;appendFile = OpenAppend["MathicsNonExampleFile"]//{#1[[0]],#1[[1]]}&', + None, + "{OutputStream, MathicsNonExampleFile}", + None, + ), + ( + "Close[appendFile]", + None, + "Close[{OutputStream, MathicsNonExampleFile}]", + None, + ), + ('DeleteFile["MathicsNonExampleFile"]', None, "Null", None), + ## writing to dir + ("x >>> /var/", ("Cannot open /var/.",), "x >>> /var/", None), + ## writing to read only file + ( + "x >>> /proc/uptime", + ("Cannot open /proc/uptime.",), + "x >>> /proc/uptime", + None, + ), + ## Malformed InputString + ( + "Read[InputStream[String], {Word, Number}]", + None, + "Read[InputStream[String], {Word, Number}]", + None, + ), + ## Correctly formed InputString but not open + ( + "Read[InputStream[String, -1], {Word, Number}]", + ("InputStream[String, -1] is not open.",), + "Read[InputStream[String, -1], {Word, Number}]", + None, + ), + ('stream = StringToStream[""];Read[stream, Word]', None, "EndOfFile", None), + ("Read[stream, Word]", None, "EndOfFile", None), + ("Close[stream];", None, "Null", None), + ( + 'stream = StringToStream["123xyz 321"]; Read[stream, Number]', + None, + "123", + None, + ), + ("Quiet[Read[stream, Number]]", None, "$Failed", None), + ## Real + ('stream = StringToStream["123, 4abc"];Read[stream, Real]', None, "123.", None), + ("Read[stream, Real]", None, "4.", None), + ("Quiet[Read[stream, Number]]", None, "$Failed", None), + ("Close[stream];", None, "Null", None), + ( + 'stream = StringToStream["1.523E-19"]; Read[stream, Real]', + None, + "1.523×10^-19", + None, + ), + ("Close[stream];", None, "Null", None), + ( + 'stream = StringToStream["-1.523e19"]; Read[stream, Real]', + None, + "-1.523×10^19", + None, + ), + ("Close[stream];", None, "Null", None), + ( + 'stream = StringToStream["3*^10"]; Read[stream, Real]', + None, + "3.×10^10", + None, + ), + ("Close[stream];", None, "Null", None), + ( + 'stream = StringToStream["3.*^10"]; Read[stream, Real]', + None, + "3.×10^10", + None, + ), + ("Close[stream];", None, "Null", None), + ## Expression + ( + 'stream = StringToStream["x + y Sin[z]"]; Read[stream, Expression]', + None, + "x + y Sin[z]", + None, + ), + ("Close[stream];", None, "Null", None), + ## ('stream = Quiet[StringToStream["Sin[1 123"]; Read[stream, Expression]]', None,'$Failed', None), + ( + 'stream = StringToStream["123 abc"]; Quiet[Read[stream, {Word, Number}]]', + None, + "$Failed", + None, + ), + ("Close[stream];", None, "Null", None), + ( + 'stream = StringToStream["123 123"]; Read[stream, {Real, Number}]', + None, + "{123., 123}", + None, + ), + ("Close[stream];", None, "Null", None), + ( + "Quiet[Read[stream, {Real}]]//{#1[[0]],#1[[1]][[0]],#1[[1]][[1]],#1[[2]]}&", + None, + "{Read, InputStream, String, {Real}}", + None, + ), + ( + r'stream = StringToStream["\"abc123\""];ReadList[stream, "Invalid"]//{#1[[0]],#1[[2]]}&', + ("Invalid is not a valid format specification.",), + "{ReadList, Invalid}", + None, + ), + ("Close[stream];", None, "Null", None), + ( + 'ReadList[StringToStream["a 1 b 2"], {Word, Number}, 1]', + None, + "{{a, 1}}", + None, + ), + ('stream = StringToStream["Mathics is cool!"];', None, "Null", None), + ("SetStreamPosition[stream, -5]", ("Invalid I/O Seek.",), "0", None), + ( + '(strm = StringToStream["abc 123"])//{#1[[0]],#1[[1]]}&', + None, + "{InputStream, String}", + None, + ), + ("Read[strm, Word]", None, "abc", None), + ("Read[strm, Number]", None, "123", None), + ("Close[strm]", None, "String", None), + ("(low=OpenWrite[])//Head", None, "OutputStream", None), + ( + "Streams[low[[1]]]//{#1[[0]],#1[[1]][[0]]}&", + None, + "{List, OutputStream}", + None, + ), + ('Streams["some_nonexistent_name"]', None, "{}", None), + ( + "stream = OpenWrite[]; WriteString[stream, 100, 1 + x + y, Sin[x + y]]", + None, + "Null", + None, + ), + ("(pathname = Close[stream])//Head", None, "String", None), + ("FilePrint[pathname]", ("1001 + x + ySin[x + y]",), "Null", None), + ("DeleteFile[pathname];", None, "Null", None), + ( + "stream = OpenWrite[];WriteString[stream];(pathname = Close[stream])//Head", + None, + "String", + None, + ), + ("FilePrint[pathname]", None, "Null", None), + ( + "WriteString[pathname, abc];(laststrm=Streams[pathname][[1]])//Head", + None, + "OutputStream", + None, + ), + ("Close[laststrm];FilePrint[pathname]", ("abc",), "Null", None), + ("DeleteFile[pathname];Clear[pathname];", None, "Null", None), + ], +) +def test_private_doctests_files(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, + ) + + # I do not know what this is it supposed to test with this... # def test_Inputget_and_put(): # stream = Expression('Plus', Symbol('x'), Integer(2)) diff --git a/test/builtin/files_io/test_filesystem.py b/test/builtin/files_io/test_filesystem.py new file mode 100644 index 000000000..32e2c5b82 --- /dev/null +++ b/test/builtin/files_io/test_filesystem.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +""" +Unit tests from builtins/files_io/filesystem.py +""" +import os.path as osp +import sys +from test.helper import check_evaluation, evaluate + +import pytest + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ( + 'AbsoluteFileName["Some/NonExistant/Path.ext"]', + ("File not found during AbsoluteFileName[Some/NonExistant/Path.ext].",), + "$Failed", + None, + ), + ('DirectoryName["a/b/c", 3] // InputForm', None, '""', None), + ('DirectoryName[""] // InputForm', None, '""', None), + ( + 'DirectoryName["a/b/c", x]', + ( + "Positive machine-sized integer expected at position 2 in DirectoryName[a/b/c, x].", + ), + "DirectoryName[a/b/c, x]", + None, + ), + ( + 'DirectoryName["a/b/c", -1]', + ( + "Positive machine-sized integer expected at position 2 in DirectoryName[a/b/c, -1].", + ), + "DirectoryName[a/b/c, -1]", + None, + ), + ( + "DirectoryName[x]", + ("String expected at position 1 in DirectoryName[x].",), + "DirectoryName[x]", + None, + ), + ('FileBaseName["file."]', None, "file", None), + ('FileBaseName["file"]', None, "file", None), + ('FileExtension["file."]', None, "", None), + ('FileExtension["file"]', None, "", None), + ('FileInformation["ExampleData/missing_file.jpg"]', None, "{}", None), + ('FindFile["SomeTypoPackage`"]', None, "$Failed", None), + ( + 'SetDirectory["MathicsNonExample"]', + ("Cannot set current directory to MathicsNonExample.",), + "$Failed", + None, + ), + ( + 'Needs["SomeFakePackageOrTypo`"]', + ( + "Cannot open SomeFakePackageOrTypo`.", + "Context SomeFakePackageOrTypo` was not created when Needs was evaluated.", + ), + "$Failed", + None, + ), + ( + 'Needs["VectorAnalysis"]', + ( + "Invalid context specified at position 1 in Needs[VectorAnalysis]. A context must consist of valid symbol names separated by and ending with `.", + ), + "Needs[VectorAnalysis]", + None, + ), + ], +) +def test_private_doctests_filesystem(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/files_io/test_importexport.py b/test/builtin/files_io/test_importexport.py index c85d8f59c..f51c38dfe 100644 --- a/test/builtin/files_io/test_importexport.py +++ b/test/builtin/files_io/test_importexport.py @@ -3,13 +3,12 @@ import os.path as osp import sys import tempfile +from test.helper import check_evaluation, evaluate, session import pytest from mathics.builtin.atomic.strings import to_python_encoding -from ...helper import session - # def test_import(): # eaccent = "\xe9" # for str_expr, str_expected, message in ( @@ -82,6 +81,185 @@ def test_export(): assert data.endswith("") +""" + + ## Compression + ## #> Export["abc.txt", 1+x, "ZIP"] (* MMA Bug - Export::type *) + ## : {ZIP} is not a valid set of export elements for the Text format. + ## = $Failed + ## #> Export["abc.txt", 1+x, "BZIP"] (* MMA Bug - General::stop *) + ## : {BZIP} is not a valid set of export elements for the Text format. + ## = $Failed + ## #> Export["abc.txt", 1+x, {"BZIP", "ZIP", "Text"}] + ## = abc.txt + ## #> Export["abc.txt", 1+x, {"GZIP", "Text"}] + ## = abc.txt + ## #> Export["abc.txt", 1+x, {"BZIP2", "Text"}] + ## = abc.txt + + ## Doesn't work on Microsoft Windows + ## S> FileFormat["ExampleData/benzene.xyz"] + ## = XYZ + +""" + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + (r'Quiet[URLFetch["https://", {}]]', None, "$Failed", None), + # (r'Quiet[URLFetch["https://www.example.com", {}]]', None, + # "...", None), + ( + 'Import["ExampleData/ExampleData.tx"]', + ("File not found during Import.",), + "$Failed", + None, + ), + ( + "Import[x]", + ("First argument x is not a valid file, directory, or URL specification.",), + "$Failed", + None, + ), + ## CSV + ( + 'Import["ExampleData/numberdata.csv", "Elements"]', + None, + "{Data, Grid}", + None, + ), + ( + 'Import["ExampleData/numberdata.csv", "Data"]', + None, + "{{0.88, 0.60, 0.94}, {0.76, 0.19, 0.51}, {0.97, 0.04, 0.26}, {0.33, 0.74, 0.79}, {0.42, 0.64, 0.56}}", + None, + ), + ( + 'Import["ExampleData/numberdata.csv"]', + None, + "{{0.88, 0.60, 0.94}, {0.76, 0.19, 0.51}, {0.97, 0.04, 0.26}, {0.33, 0.74, 0.79}, {0.42, 0.64, 0.56}}", + None, + ), + ( + 'Import["ExampleData/numberdata.csv", "FieldSeparators" -> "."]', + None, + "{{0, 88,0, 60,0, 94}, {0, 76,0, 19,0, 51}, {0, 97,0, 04,0, 26}, {0, 33,0, 74,0, 79}, {0, 42,0, 64,0, 56}}", + None, + ), + ( + 'Import["ExampleData/Middlemarch.txt"];', + ("An invalid unicode sequence was encountered and ignored.",), + "Null", + None, + ), + ## XML + ( + 'MatchQ[Import["ExampleData/InventionNo1.xml", "Tags"],{__String}]', + None, + "True", + None, + ), + ("ImportString[x]", ("First argument x is not a string.",), "$Failed", None), + ## CSV + ( + 'datastring = "0.88, 0.60, 0.94\\n.076, 0.19, .51\\n0.97, 0.04, .26";ImportString[datastring, "Elements"]', + None, + "{Data, Lines, Plaintext, String, Words}", + None, + ), + ('ImportString[datastring, {"CSV","Elements"}]', None, "{Data, Grid}", None), + ( + 'ImportString[datastring, {"CSV", "Data"}]', + None, + "{{0.88, 0.60, 0.94}, {.076, 0.19, .51}, {0.97, 0.04, .26}}", + None, + ), + ( + "ImportString[datastring]", + None, + "0.88, 0.60, 0.94\n.076, 0.19, .51\n0.97, 0.04, .26", + None, + ), + ( + 'ImportString[datastring, "CSV","FieldSeparators" -> "."]', + None, + "{{0, 88, 0, 60, 0, 94}, {076, 0, 19, , 51}, {0, 97, 0, 04, , 26}}", + None, + ), + ## Invalid Filename + ( + 'Export["abc.", 1+2]', + ("Cannot infer format of file abc..",), + "$Failed", + None, + ), + ( + 'Export[".ext", 1+2]', + ("Cannot infer format of file .ext.",), + "$Failed", + None, + ), + ( + "Export[x, 1+2]", + ("First argument x is not a valid file specification.",), + "$Failed", + None, + ), + ## Explicit Format + ( + 'Export["abc.txt", 1+x, "JPF"]', + ("{JPF} is not a valid set of export elements for the Text format.",), + "$Failed", + None, + ), + ( + 'Export["abc.txt", 1+x, {"JPF"}]', + ("{JPF} is not a valid set of export elements for the Text format.",), + "$Failed", + None, + ), + ## Empty elems + ('Export["123.txt", 1+x, {}]', None, "123.txt", None), + ( + 'Export["123.jcp", 1+x, {}]', + ("Cannot infer format of file 123.jcp.",), + "$Failed", + None, + ), + ## FORMATS + ## ASCII text + ('FileFormat["ExampleData/BloodToilTearsSweat.txt"]', None, "Text", None), + ('FileFormat["ExampleData/MadTeaParty.gif"]', None, "GIF", None), + ('FileFormat["ExampleData/moon.tif"]', None, "TIFF", None), + ('FileFormat["ExampleData/numberdata.csv"]', None, "CSV", None), + ('FileFormat["ExampleData/EinsteinSzilLetter.txt"]', None, "Text", None), + ('FileFormat["ExampleData/BloodToilTearsSweat.txt"]', None, "Text", None), + ('FileFormat["ExampleData/colors.json"]', None, "JSON", None), + ( + 'FileFormat["ExampleData/some-typo.extension"]', + ("File not found during FileFormat[ExampleData/some-typo.extension].",), + "$Failed", + None, + ), + ('FileFormat["ExampleData/Testosterone.svg"]', None, "SVG", None), + ('FileFormat["ExampleData/colors.json"]', None, "JSON", None), + ('FileFormat["ExampleData/InventionNo1.xml"]', None, "XML", None), + ], +) +def test_private_doctests_importexport(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, + ) + + # TODO: # mmatera: please put in pytest conditionally # >> System`Convert`B64Dump`B64Encode["∫ f  x"] diff --git a/test/builtin/numbers/test_algebra.py b/test/builtin/numbers/test_algebra.py index 71f95cc4c..e1cbee3b3 100644 --- a/test/builtin/numbers/test_algebra.py +++ b/test/builtin/numbers/test_algebra.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """ -Unit tests for mathics.builtins.numbers.algebra +Unit tests for mathics.builtins.numbers.algebra and +mathics.builtins.numbers.integer """ from test.helper import check_evaluation @@ -329,3 +330,183 @@ def test_fullsimplify(): ), ): check_evaluation(str_expr, str_expected, failure_message) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ("Attributes[f] = {HoldAll}; Apart[f[x + x]]", None, "f[x + x]", None), + ("Attributes[f] = {}; Apart[f[x + x]]", None, "f[2 x]", None), + ## Errors: + ( + "Coefficient[x + y + 3]", + ("Coefficient called with 1 argument; 2 or 3 arguments are expected.",), + "Coefficient[3 + x + y]", + None, + ), + ( + "Coefficient[x + y + 3, 5]", + ("5 is not a valid variable.",), + "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 + # ("Coefficient[(x + 2)^3 + (x + 3)^2, x, 0, {Modulus -> 3, Modulus -> 2, Modulus -> 10}]", + # None,"{2, 1, 7}", None), + ( + "CoefficientList[x + y, 5]", + ("5 is not a valid variable.",), + "CoefficientList[x + y, 5]", + None, + ), + ( + "CoefficientList[(x - 2 y)^4, {x, 2}]", + ("2 is not a valid variable.",), + "CoefficientList[(x - 2 y) ^ 4, {x, 2}]", + None, + ), + ( + "CoefficientList[x / y, {x, y}]", + ("x / y is not a polynomial.",), + "CoefficientList[x / y, {x, y}]", + None, + ), + ("Expand[x, Modulus -> -1] (* copy odd MMA behaviour *)", None, "0", None), + ( + "Expand[x, Modulus -> x]", + ("Value of option Modulus -> x should be an integer.",), + "Expand[x, Modulus -> x]", + None, + ), + ("a(b(c+d)+e) // Expand", None, "a b c + a b d + a e", None), + ("(y^2)^(1/2)/(2x+2y)//Expand", None, "Sqrt[y ^ 2] / (2 x + 2 y)", None), + ( + "2(3+2x)^2/(5+x^2+3x)^3 // Expand", + None, + "24 x / (5 + 3 x + x ^ 2) ^ 3 + 8 x ^ 2 / (5 + 3 x + x ^ 2) ^ 3 + 18 / (5 + 3 x + x ^ 2) ^ 3", + None, + ), + ## Modulus option + ( + "ExpandDenominator[1 / (x + y)^3, Modulus -> 3]", + None, + "1 / (x ^ 3 + y ^ 3)", + None, + ), + ( + "ExpandDenominator[1 / (x + y)^6, Modulus -> 4]", + None, + "1 / (x ^ 6 + 2 x ^ 5 y + 3 x ^ 4 y ^ 2 + 3 x ^ 2 y ^ 4 + 2 x y ^ 5 + y ^ 6)", + None, + ), + ( + "ExpandDenominator[2(3+2x)^2/(5+x^2+3x)^3]", + None, + "2 (3 + 2 x) ^ 2 / (125 + 225 x + 210 x ^ 2 + 117 x ^ 3 + 42 x ^ 4 + 9 x ^ 5 + x ^ 6)", + None, + ), + ## errors: + ( + "Exponent[x^2]", + ("Exponent called with 1 argument; 2 or 3 arguments are expected.",), + "Exponent[x ^ 2]", + None, + ), + ## Issue659 + ("Factor[{x+x^2}]", None, "{x (1 + x)}", None), + ("FactorTermsList[2 x^2 - 2, x]", None, "{2, 1, -1 + x ^ 2}", None), + ( + "MinimalPolynomial[7a, x]", + ("7 a is not an explicit algebraic number.",), + "MinimalPolynomial[7 a, x]", + None, + ), + ( + "MinimalPolynomial[3x^3 + 2x^2 + y^2 + ab, x]", + ("ab + 2 x ^ 2 + 3 x ^ 3 + y ^ 2 is not an explicit algebraic number.",), + "MinimalPolynomial[ab + 2 x ^ 2 + 3 x ^ 3 + y ^ 2, x]", + None, + ), + ## PurePoly + ("MinimalPolynomial[Sqrt[2 + Sqrt[3]]]", None, "1 - 4 #1 ^ 2 + #1 ^ 4", None), + ( + "PolynomialQ[x, x, y]", + ("PolynomialQ called with 3 arguments; 1 or 2 arguments are expected.",), + "PolynomialQ[x, x, y]", + None, + ), + ## Always return True if argument is Null + ( + "PolynomialQ[x^3 - 2 x/y + 3xz, ]", + None, + "True", + "Always return True if argument is Null", + ), + ( + "PolynomialQ[, {x, y, z}]", + None, + "True", + "True if the expression is Null", + ), + ( + "PolynomialQ[, ]", + None, + "True", + None, + ), + ## TODO: MMA and Sympy handle these cases differently + ## #> PolynomialQ[x^(1/2) + 6xyz] + ## : No variable is not supported in PolynomialQ. + ## = True + ## #> PolynomialQ[x^(1/2) + 6xyz, {}] + ## : No variable is not supported in PolynomialQ. + ## = True + ## #> PolynomialQ[x^3 - 2 x/y + 3xz] + ## : No variable is not supported in PolynomialQ. + ## = False + ## #> PolynomialQ[x^3 - 2 x/y + 3xz, {}] + ## : No variable is not supported in PolynomialQ. + ## = False + ("f[x]/x+f[x]/x^2//Together", None, "f[x] (1 + x) / x ^ 2", None), + ## failing test case from MMA docs + ("Variables[E^x]", None, "{}", None), + ], +) +def test_private_doctests_algebra(str_expr, msgs, str_expected, fail_msg): + """doctests for algebra""" + check_evaluation( + str_expr, + str_expected, + to_string_expr=True, + to_string_expected=True, + hold_expected=True, + failure_message=fail_msg, + expected_messages=msgs, + ) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ( + "FromDigits[x]", + ("The input must be a string of digits or a list.",), + "FromDigits[x, 10]", + None, + ), + ], +) +def test_private_doctests_integer(str_expr, msgs, str_expected, fail_msg): + """doctests for integer""" + 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/numbers/test_calculus.py b/test/builtin/numbers/test_calculus.py index 7d4d3c60c..0230a8c7e 100644 --- a/test/builtin/numbers/test_calculus.py +++ b/test/builtin/numbers/test_calculus.py @@ -2,7 +2,7 @@ """ Unit tests for mathics.builtins.numbers.calculus -In parituclar: +In partiuclar: FindRoot[], FindMinimum[], NFindMaximum[] tests @@ -226,3 +226,68 @@ def test_private_doctests_optimization(str_expr, msgs, str_expected, fail_msg): failure_message=fail_msg, expected_messages=msgs, ) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ( + "D[2/3 Cos[x] - 1/3 x Cos[x] Sin[x] ^ 2,x]//Expand", + None, + "-2 x Cos[x] ^ 2 Sin[x] / 3 + x Sin[x] ^ 3 / 3 - 2 Sin[x] / 3 - Cos[x] Sin[x] ^ 2 / 3", + None, + ), + ("D[f[#1], {#1,2}]", None, "f''[#1]", None), + ("D[(#1&)[t],{t,4}]", None, "0", None), + ("Attributes[f] ={HoldAll}; Apart[f''[x + x]]", None, "f''[2 x]", None), + ("Attributes[f] = {}; Apart[f''[x + x]]", None, "f''[2 x]", None), + ## Issue #375 + ("D[{#^2}, #]", None, "{2 #1}", None), + ("FindRoot[2.5==x,{x,0}]", None, "{x -> 2.5}", None), + ("DownValues[Integrate]", None, "{}", None), + ( + "Definition[Integrate]", + None, + ( + "Attributes[Integrate] = {Protected, ReadProtected}\n" + "\n" + "Options[Integrate] = {Assumptions -> $Assumptions, GenerateConditions -> Automatic, PrincipalValue -> False}\n" + ), + None, + ), + ( + "Integrate[Hold[x + x], {x, a, b}]", + None, + "Integrate[Hold[x + x], {x, a, b}]", + None, + ), + ("Integrate[sin[x], x]", None, "Integrate[sin[x], x]", None), + ("Integrate[x ^ 3.5 + x, x]", None, "x ^ 2 / 2 + 0.222222 x ^ 4.5", None), + ( + "Integrate[1/(x^5+1), x]", + None, + "RootSum[1 + 5 #1 + 25 #1 ^ 2 + 125 #1 ^ 3 + 625 #1 ^ 4&, Log[x + 5 #1] #1&] + Log[1 + x] / 5", + None, + ), + ("Integrate[ArcTan(x), x]", None, "x ^ 2 ArcTan / 2", None), + ("Integrate[E[x], x]", None, "Integrate[E[x], x]", None), + ("Integrate[Exp[-(x/2)^2],{x,-Infinity,+Infinity}]", None, "2 Sqrt[Pi]", None), + ( + "Integrate[Exp[-1/(x^2)], x]", + None, + "x E ^ (-1 / x ^ 2) + Sqrt[Pi] Erf[1 / x]", + None, + ), + ], +) +def test_private_doctests_calculus(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/numbers/test_diffeqns.py b/test/builtin/numbers/test_diffeqns.py new file mode 100644 index 000000000..46a8579d7 --- /dev/null +++ b/test/builtin/numbers/test_diffeqns.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- +""" +Unit tests for mathics.builtins.numbers.diffeqns +""" +from test.helper import check_evaluation + +import pytest + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ## FIXME: sympy solves this as `Function[{x}, C[1] + Integrate[ArcSin[f[2 x]], x]]` + # ( + # "Attributes[f] = {HoldAll}; DSolve[f[x + x] == Sin[f'[x]], f, x]", + # ( + # ( + # "To avoid possible ambiguity, the arguments of the dependent " + # "variable in f[x + x] == Sin[f'[x]] should literally match " + # "the independent variables." + # ), + # ), + # "DSolve[f[x + x] == Sin[f'[x]], f, x]", + # "sympy solves this as `Function[{x}, C[1] + Integrate[ArcSin[f[2 x]], x]]`", + # ), + # """ + # ( + # "Attributes[f] = {}; DSolve[f[x + x] == Sin[f'[x]], f, x]", + # ( + # ( + # "To avoid possible ambiguity, the arguments of the dependent " + # "variable in f[2 x] == Sin[f'[x]] should literally match " + # "the independent variables." + # ), + # ), + # "DSolve[f[2 x] == Sin[f'[x]], f, x]", + # None, + # ), + ( + "DSolve[f'[x] == f[x], f, x] // FullForm", + None, + "{{Rule[f, Function[{x}, Times[C[1], Power[E, x]]]]}}", + None, + ), + ( + "DSolve[f'[x] == f[x], f, x] /. {C[1] -> 1}", + None, + "{{f -> (Function[{x}, 1 E ^ x])}}", + None, + ), + ( + "DSolve[f'[x] == f[x], f, x] /. {C -> D}", + None, + "{{f -> (Function[{x}, D[1] E ^ x])}}", + None, + ), + ( + "DSolve[f'[x] == f[x], f, x] /. {C[1] -> C[0]}", + None, + "{{f -> (Function[{x}, C[0] E ^ x])}}", + None, + ), + ( + "DSolve[f[x] == 0, f, {}]", + ("{} cannot be used as a variable.",), + "DSolve[f[x] == 0, f, {}]", + None, + ), + ## Order of arguments shoudn't matter + ( + "DSolve[D[f[x, y], x] == D[f[x, y], y], f, {x, y}]", + None, + "{{f -> (Function[{x, y}, C[1][-x - y]])}}", + None, + ), + ( + "DSolve[D[f[x, y], x] == D[f[x, y], y], f[x, y], {x, y}]", + None, + "{{f[x, y] -> C[1][-x - y]}}", + None, + ), + ( + "DSolve[D[f[x, y], x] == D[f[x, y], y], f[x, y], {y, x}]", + None, + "{{f[x, y] -> C[1][-x - y]}}", + None, + ), + ( + "DSolve[\\[Gamma]'[x] == 0, \\[Gamma], x]", + None, + "{{γ -> (Function[{x}, C[1]])}}", + "sympy #11669 test", + ), + ], +) +def test_private_doctests_diffeqns(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/numbers/test_hyperbolic.py b/test/builtin/numbers/test_hyperbolic.py index 762cab81f..5b7a4cc31 100644 --- a/test/builtin/numbers/test_hyperbolic.py +++ b/test/builtin/numbers/test_hyperbolic.py @@ -1,12 +1,15 @@ -# -*- coding: utf-8 -*- +## -*- coding: utf-8 -*- """ -Unit tests for mathics.builtins.numbers.hyperbolic +Unit tests for mathics.builtins.numbers.hyperbolic and +mathics.builtins.numbers.exp These simple verify various rules from from symja_android_library/symja_android_library/rules/Gudermannian.m """ from test.helper import check_evaluation +import pytest + def test_gudermannian(): for str_expr, str_expected in ( @@ -34,3 +37,53 @@ def test_complexexpand(): ), ): check_evaluation(str_expr, str_expected) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ("ArcCosh[1.4]", None, "0.867015", None), + ( + "ArcCoth[0.000000000000000000000000000000000000000]", + None, + "1.57079632679489661923132169163975144210 I", + None, + ), + ], +) +def test_private_doctests_hyperbolic(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, + ) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ("Exp[1.*^20]", ("Overflow occurred in computation.",), "Overflow[]", None), + ("Log[1000] / Log[10] // Simplify", None, "3", None), + ("Log[1.4]", None, "0.336472", None), + ("Log[Exp[1.4]]", None, "1.4", None), + ("Log[-1.4]", None, "0.336472 + 3.14159 I", None), + ("N[Log[10], 30]", None, "2.30258509299404568401799145468", None), + ("LogisticSigmoid[I Pi]", None, "LogisticSigmoid[I Pi]", None), + ], +) +def test_private_doctests_exp(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/numbers/test_linalg.py b/test/builtin/numbers/test_linalg.py index 73a914082..3494e65e2 100644 --- a/test/builtin/numbers/test_linalg.py +++ b/test/builtin/numbers/test_linalg.py @@ -88,3 +88,139 @@ def test_inverse(str_expr, str_expected, fail_msg, warnings): check_evaluation( str_expr, str_expected, failure_message="", expected_messages=warnings ) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ( + "Eigenvalues[{{1, 0}, {0}}]", + ( + "Argument {{1, 0}, {0}} at position 1 is not a non-empty rectangular matrix.", + ), + "Eigenvalues[{{1, 0}, {0}}]", + None, + ), + ( + "Eigenvectors[{{-2, 1, -1}, {-3, 2, 1}, {-1, 1, 0}}]", + None, + "{{1, 7, 3}, {1, 1, 0}, {0, 0, 0}}", + None, + ), + ## Inconsistent system - ideally we'd print a different message + ( + "LeastSquares[{{1, 1, 1}, {1, 1, 1}}, {1, 0}]", + ("Solving for underdetermined system not implemented.",), + "LeastSquares[{{1, 1, 1}, {1, 1, 1}}, {1, 0}]", + None, + ), + ( + "LeastSquares[{1, {2}}, {1, 2}]", + ("Argument {1, {2}} at position 1 is not a non-empty rectangular matrix.",), + "LeastSquares[{1, {2}}, {1, 2}]", + None, + ), + ( + "LeastSquares[{{1, 2}, {3, 4}}, {1, {2}}]", + ("Argument {1, {2}} at position 2 is not a non-empty rectangular matrix.",), + "LeastSquares[{{1, 2}, {3, 4}}, {1, {2}}]", + None, + ), + ( + "LinearSolve[{1, {2}}, {1, 2}]", + ("Argument {1, {2}} at position 1 is not a non-empty rectangular matrix.",), + "LinearSolve[{1, {2}}, {1, 2}]", + None, + ), + ( + "LinearSolve[{{1, 2}, {3, 4}}, {1, {2}}]", + ("Argument {1, {2}} at position 2 is not a non-empty rectangular matrix.",), + "LinearSolve[{{1, 2}, {3, 4}}, {1, {2}}]", + None, + ), + ("MatrixExp[{{a, 0}, {0, b}}]", None, "{{E ^ a, 0}, {0, E ^ b}}", None), + ( + "MatrixExp[{{1, 0}, {0}}]", + ( + "Argument {{1, 0}, {0}} at position 1 is not a non-empty rectangular matrix.", + ), + "MatrixExp[{{1, 0}, {0}}]", + None, + ), + ( + "MatrixPower[{{0, x}, {0, 0}}, n]", + None, + "MatrixPower[{{0, x}, {0, 0}}, n]", + None, + ), + ( + "MatrixPower[{{1, 0}, {0}}, 2]", + ( + "Argument {{1, 0}, {0}} at position 1 is not a non-empty rectangular matrix.", + ), + "MatrixPower[{{1, 0}, {0}}, 2]", + None, + ), + ( + "MatrixRank[{{1, 0}, {0}}]", + ( + "Argument {{1, 0}, {0}} at position 1 is not a non-empty rectangular matrix.", + ), + "MatrixRank[{{1, 0}, {0}}]", + None, + ), + ( + "NullSpace[{1, {2}}]", + ("Argument {1, {2}} at position 1 is not a non-empty rectangular matrix.",), + "NullSpace[{1, {2}}]", + None, + ), + ( + "PseudoInverse[{1, {2}}]", + ("Argument {1, {2}} at position 1 is not a non-empty rectangular matrix.",), + "PseudoInverse[{1, {2}}]", + None, + ), + ( + "QRDecomposition[{1, {2}}]", + ("Argument {1, {2}} at position 1 is not a non-empty rectangular matrix.",), + "QRDecomposition[{1, {2}}]", + None, + ), + ( + "RowReduce[{{1, 0}, {0}}]", + ( + "Argument {{1, 0}, {0}} at position 1 is not a non-empty rectangular matrix.", + ), + "RowReduce[{{1, 0}, {0}}]", + None, + ), + ( + "SingularValueDecomposition[{{3/2, 2}, {5/2, 3}}]", + ("Symbolic SVD is not implemented, performing numerically.",), + ( + "{{{0.538954, 0.842335}, {0.842335, -0.538954}}, " + "{{4.63555, 0.}, {0., 0.107862}}, " + "{{0.628678, 0.777666}, {-0.777666, 0.628678}}}" + ), + None, + ), + ( + "SingularValueDecomposition[{1, {2}}]", + ("Argument {1, {2}} at position 1 is not a non-empty rectangular matrix.",), + "SingularValueDecomposition[{1, {2}}]", + None, + ), + ], +) +def test_private_doctests_linalg(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/numbers/test_numbertheory.py b/test/builtin/numbers/test_numbertheory.py new file mode 100644 index 000000000..8e5e149b4 --- /dev/null +++ b/test/builtin/numbers/test_numbertheory.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +""" +Unit tests for mathics.builtins.numbers.numbertheory +""" +from test.helper import check_evaluation + +import pytest + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ("Divisors[0]", None, "Divisors[0]", None), + ( + "Divisors[{-206, -502, -1702, 9}]", + None, + ( + "{{1, 2, 103, 206}, " + "{1, 2, 251, 502}, " + "{1, 2, 23, 37, 46, 74, 851, 1702}, " + "{1, 3, 9}}" + ), + None, + ), + ("Length[Divisors[1000*369]]", None, "96", None), + ("Length[Divisors[305*176*369*100]]", None, "672", None), + ("FractionalPart[b]", None, "FractionalPart[b]", None), + ("FractionalPart[{-2.4, -2.5, -3.0}]", None, "{-0.4, -0.5, 0.}", None), + ("FractionalPart[14/32]", None, "7 / 16", None), + ("FractionalPart[4/(1 + 3 I)]", None, "2 / 5 - I / 5", None), + ("FractionalPart[Pi^20]", None, "-8769956796 + Pi ^ 20", None), + ("MantissaExponent[E, Pi]", None, "{E / Pi, 1}", None), + ("MantissaExponent[Pi, Pi]", None, "{1 / Pi, 2}", None), + ("MantissaExponent[5/2 + 3, Pi]", None, "{11 / (2 Pi ^ 2), 2}", None), + ("MantissaExponent[b]", None, "MantissaExponent[b]", None), + ("MantissaExponent[17, E]", None, "{17 / E ^ 3, 3}", None), + ("MantissaExponent[17., E]", None, "{0.84638, 3}", None), + ("MantissaExponent[Exp[Pi], 2]", None, "{E ^ Pi / 32, 5}", None), + ( + "MantissaExponent[3 + 2 I, 2]", + ("The value 3 + 2 I is not a real number",), + "MantissaExponent[3 + 2 I, 2]", + None, + ), + ( + "MantissaExponent[25, 0.4]", + ("Base 0.4 is not a real number greater than 1.",), + "MantissaExponent[25, 0.4]", + None, + ), + ("MantissaExponent[0.0000124]", None, "{0.124, -4}", None), + ("MantissaExponent[0.0000124, 2]", None, "{0.812646, -16}", None), + ("MantissaExponent[0]", None, "{0, 0}", None), + ("MantissaExponent[0, 2]", None, "{0, 0}", None), + ("PrimePowerQ[1]", None, "False", None), + ("RandomPrime[{10,12}, {2,2}]", None, "{{11, 11}, {11, 11}}", None), + ("RandomPrime[2, {3,2}]", None, "{{2, 2}, {2, 2}, {2, 2}}", None), + ], +) +def test_private_doctests_numbertheory(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/numbers/test_randomnumbers.py b/test/builtin/numbers/test_randomnumbers.py index d2bf37277..9e0e7bccd 100644 --- a/test/builtin/numbers/test_randomnumbers.py +++ b/test/builtin/numbers/test_randomnumbers.py @@ -39,3 +39,70 @@ def test_random_sample(str_expr, str_expected): to_string_expr=True, to_string_expected=True, ) + + +# -*- coding: utf-8 -*- +""" +Unit tests for mathics.builtins.specialfns.gamma +""" +from test.helper import check_evaluation + +import pytest + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ( + "RandomComplex[] //(0 <= Re[#1] <= 1 && 0 <= Im[#1] <= 1)&", + None, + "True", + None, + ), + ( + "z=RandomComplex[{1+I, 5+5I}];1 <= Re[z] <= 5 && 1 <= Im[z] <= 5", + None, + "True", + None, + ), + ( + "z=.;RandomComplex[{6.3, 2.5 I}] // Head", + None, + "Complex", + None, + ), + ("RandomInteger[{1, 5}]// (1<= #1 <= 5)&", None, "True", None), + ("RandomReal[]// (0<= #1 <= 1)&", None, "True", None), + ( + "Length /@ RandomReal[100, {2, 3}]", + None, + "{3, 3}", + None, + ), + ( + "RandomReal[{0, 1}, {1, -1}]", + ( + "The array dimensions {1, -1} given in position 2 of RandomReal[{0, 1}, {1, -1}] should be a list of non-negative machine-sized integers giving the dimensions for the result.", + ), + "RandomReal[{0, 1}, {1, -1}]", + None, + ), + ( + "SeedRandom[x]", + ("Argument x should be an integer or string.",), + "SeedRandom[x]", + None, + ), + ], +) +def test_private_doctests_randomnumbers(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/numbers/test_trig.py b/test/builtin/numbers/test_trig.py index 5aee15cb7..dbe01c2d4 100644 --- a/test/builtin/numbers/test_trig.py +++ b/test/builtin/numbers/test_trig.py @@ -7,6 +7,8 @@ """ from test.helper import check_evaluation +import pytest + def test_ArcCos(): for str_expr, str_expected in ( @@ -22,3 +24,31 @@ def test_ArcCos(): ("ArcCos[(1 + Sqrt[3]) / (2*Sqrt[2])]", "1/12 Pi"), ): check_evaluation(str_expr, str_expected) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ("ArcTan[-1, 1]", None, "3 Pi / 4", None), + ("ArcTan[1, -1]", None, "-Pi / 4", None), + ("ArcTan[-1, -1]", None, "-3 Pi / 4", None), + ("ArcTan[1, 0]", None, "0", None), + ("ArcTan[-1, 0]", None, "Pi", None), + ("ArcTan[0, 1]", None, "Pi / 2", None), + ("ArcTan[0, -1]", None, "-Pi / 2", None), + ("Cos[1.5 Pi]", None, "-1.83697×10^-16", None), + ("N[Sin[1], 40]", None, "0.8414709848078965066525023216302989996226", None), + ("Tan[0.5 Pi]", None, "1.63312×10^16", None), + ], +) +def test_private_doctests_trig(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/specialfns/test_bessel.py b/test/builtin/specialfns/test_bessel.py index b6201d76e..77a73ee98 100644 --- a/test/builtin/specialfns/test_bessel.py +++ b/test/builtin/specialfns/test_bessel.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """ -Unit tests for mathics.builtins.arithmetic.bessel +Unit tests for mathics.builtins.specialfns.bessel and +mathics.builtins.specialfns.orthogonal """ from test.helper import check_evaluation @@ -13,7 +14,7 @@ # by SymPy. [ ( - "BesselI[1/2,z]", + "z=.;BesselI[1/2,z]", "Sqrt[2] Sinh[z] / (Sqrt[z] Sqrt[Pi])", "BesselI 1/2 rule", ), @@ -30,3 +31,64 @@ def test_add(str_expr, str_expected, assert_failure_msg): check_evaluation( str_expr, str_expected, hold_expected=True, failure_message=assert_failure_msg ) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ("AiryAiZero[1]", None, "AiryAiZero[1]", None), + ("AiryAiZero[1.]", None, "AiryAiZero[1.]", None), + ("AiryAi[AiryAiZero[1]]", None, "0", None), + ( + "N[AiryAiZero[2], 100]", + None, + "-4.087949444130970616636988701457391060224764699108529754984160876025121946836047394331169160758270562", + None, + ), + ("AiryBiZero[1]", None, "AiryBiZero[1]", None), + ("AiryBiZero[1.]", None, "AiryBiZero[1.]", None), + ("AiryBi[AiryBiZero[1]]", None, "0", None), + ( + "N[AiryBiZero[2], 100]", + None, + "-3.271093302836352715680228240166413806300935969100284801485032396261130864238742879252000673830055014", + None, + ), + ("BesselJ[2.5, 1]", None, "0.0494968", None), + ], +) +def test_private_doctests_bessel(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, + ) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ( + "SphericalHarmonicY[1,1,x,y]", + None, + "-Sqrt[6] E ^ (I y) Sin[x] / (4 Sqrt[Pi])", + None, + ), + ], +) +def test_private_doctests_orthogonal(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/specialfns/test_gamma.py b/test/builtin/specialfns/test_gamma.py new file mode 100644 index 000000000..b5d1d4148 --- /dev/null +++ b/test/builtin/specialfns/test_gamma.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +""" +Unit tests for mathics.builtins.specialfns.gamma +""" +from test.helper import check_evaluation + +import pytest + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ("0!", None, "1", None), + ( + "N[Gamma[24/10], 100]", + None, + "1.242169344504305404913070252268300492431517240992022966055507541481863694148882652446155342679460339", + "Issue 203", + ), + ( + "res=N[N[Gamma[24/10],100]/N[Gamma[14/10],100],100]", + None, + "1.400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Issue 203", + ), + ("res // Precision", None, "100.", None), + ( + "Gamma[1.*^20]", + ("Overflow occurred in computation.",), + "Overflow[]", + "Overflow", + ), + ("Gamma[1., 2.]", None, "Gamma[1., 2.]", "needs mpmath for lowergamma"), + ], +) +def test_private_doctests_gamma(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_intfns.py b/test/builtin/test_intfns.py new file mode 100644 index 000000000..c7c790728 --- /dev/null +++ b/test/builtin/test_intfns.py @@ -0,0 +1,213 @@ +# -*- coding: utf-8 -*- +""" +Unit tests from mathics.builtin.intfns +""" + +from test.helper import check_evaluation, session + +import pytest + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ("HarmonicNumber[-1.5]", None, "0.613706", None), + ], +) +def test_private_doctests_recurrence(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, + ) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ## TODO should be ComplexInfinity but mpmath returns +inf + ("Binomial[-10, -3.5]", None, "Infinity", None), + ("Subsets[{}]", None, "{{}}", None), + ("Subsets[]", None, "Subsets[]", None), + ( + "Subsets[{a, b, c}, 2.5]", + ( + "Position 2 of Subsets[{a, b, c}, 2.5] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer.", + ), + "Subsets[{a, b, c}, 2.5]", + None, + ), + ( + "Subsets[{a, b, c}, -1]", + ( + "Position 2 of Subsets[{a, b, c}, -1] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer.", + ), + "Subsets[{a, b, c}, -1]", + None, + ), + ( + "Subsets[{a, b, c}, {3, 4, 5, 6}]", + ( + "Position 2 of Subsets[{a, b, c}, {3, 4, 5, 6}] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer.", + ), + "Subsets[{a, b, c}, {3, 4, 5, 6}]", + None, + ), + ( + "Subsets[{a, b, c}, {-1, 2}]", + ( + "Position 2 of Subsets[{a, b, c}, {-1, 2}] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer.", + ), + "Subsets[{a, b, c}, {-1, 2}]", + None, + ), + ( + "Subsets[{a, b, c}, All]", + None, + "{{}, {a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, b, c}}", + None, + ), + ( + "Subsets[{a, b, c}, Infinity]", + None, + "{{}, {a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, b, c}}", + None, + ), + ( + "Subsets[{a, b, c}, ALL]", + ( + "Position 2 of Subsets[{a, b, c}, ALL] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer.", + ), + "Subsets[{a, b, c}, ALL]", + None, + ), + ( + "Subsets[{a, b, c}, {a}]", + ( + "Position 2 of Subsets[{a, b, c}, {a}] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer.", + ), + "Subsets[{a, b, c}, {a}]", + None, + ), + ( + "Subsets[{a, b, c}, {}]", + ( + "Position 2 of Subsets[{a, b, c}, {}] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer.", + ), + "Subsets[{a, b, c}, {}]", + None, + ), + ("Subsets[{a, b}, 0]", None, "{{}}", None), + ( + "Subsets[{1, 2}, x]", + ( + "Position 2 of Subsets[{1, 2}, x] must be All, Infinity, a non-negative integer, or a List whose first element (required) is a non-negative integer, second element (optional) is a non-negative integer or Infinity, and third element (optional) is a nonzero integer.", + ), + "Subsets[{1, 2}, x]", + None, + ), + ( + "Subsets[x]", + ("Nonatomic expression expected at position 1 in Subsets[x].",), + "Subsets[x]", + None, + ), + ( + "Subsets[x, {1, 2}]", + ("Nonatomic expression expected at position 1 in Subsets[x, {1, 2}].",), + "Subsets[x, {1, 2}]", + None, + ), + ( + "Subsets[x, {1, 2, 3}, {1, 3}]", + ( + "Nonatomic expression expected at position 1 in Subsets[x, {1, 2, 3}, {1, 3}].", + ), + "Subsets[x, {1, 2, 3}, {1, 3}]", + None, + ), + ( + "Subsets[a + b + c]", + None, + "{0, a, b, c, a + b, a + c, b + c, a + b + c}", + None, + ), + ( + "Subsets[f[a, b, c]]", + None, + "{f[], f[a], f[b], f[c], f[a, b], f[a, c], f[b, c], f[a, b, c]}", + None, + ), + ("Subsets[a + b + c, {1, 3, 2}]", None, "{a, b, c, a + b + c}", None), + ("Subsets[a* b * c, All, {6}]", None, "{a c}", None), + ( + "Subsets[{a, b, c}, {1, Infinity}]", + None, + "{{a}, {b}, {c}, {a, b}, {a, c}, {b, c}, {a, b, c}}", + None, + ), + ( + "Subsets[{a, b, c}, {1, Infinity, 2}]", + None, + "{{a}, {b}, {c}, {a, b, c}}", + None, + ), + ("Subsets[{a, b, c}, {3, Infinity, -1}]", None, "{}", None), + ], +) +def test_private_doctests_combinatorial(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, + ) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ( + "Quotient[13, 0]", + ("Infinite expression Quotient[13, 0] encountered.",), + "ComplexInfinity", + None, + ), + ("Quotient[-17, 7]", None, "-3", None), + ("Quotient[-17, -4]", None, "4", None), + ("Quotient[19, -4]", None, "-5", None), + ( + "QuotientRemainder[13, 0]", + ("The argument 0 in QuotientRemainder[13, 0] should be nonzero.",), + "QuotientRemainder[13, 0]", + None, + ), + ("QuotientRemainder[-17, 7]", None, "{-3, 4}", None), + ("QuotientRemainder[-17, -4]", None, "{4, -1}", None), + ("QuotientRemainder[19, -4]", None, "{-5, -1}", None), + ("QuotientRemainder[a, 0]", None, "QuotientRemainder[a, 0]", None), + ("QuotientRemainder[a, b]", None, "QuotientRemainder[a, b]", None), + ("QuotientRemainder[5.2,2.5]", None, "{2, 0.2}", None), + ("QuotientRemainder[5, 2.]", None, "{2, 1.}", None), + ], +) +def test_private_doctests_divlike(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_numeric.py b/test/builtin/test_numeric.py index dff0d72b9..ae5e6c603 100644 --- a/test/builtin/test_numeric.py +++ b/test/builtin/test_numeric.py @@ -4,9 +4,10 @@ In particular, Rationalize and RealValuNumberQ """ - from test.helper import check_evaluation +import pytest + def test_rationalize(): # Some of the Rationalize tests were taken from Symja's tests and docs @@ -67,3 +68,73 @@ def test_realvalued(): ), ): check_evaluation(str_expr, str_expected) + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + ( + "p=N[Pi,100]", + None, + "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068", + None, + ), + ( + "ToString[p]", + None, + "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068", + None, + ), + ("N[1.012345678901234567890123, 20]", None, "1.0123456789012345679", None), + ("N[I, 30]", None, "1.00000000000000000000000000000 I", None), + ( + "N[1.012345678901234567890123, 50] //{#1, #1//Precision}&", + None, + "{1.01234567890123456789012, 24.}", + None, + ), + ( + "p=.;x=.;y=.;Rationalize[N[Pi] + 0.8 I, x]", + ("Tolerance specification x must be a non-negative number.",), + "Rationalize[3.14159 + 0.8 I, x]", + None, + ), + ( + "Rationalize[N[Pi] + 0.8 I, -1]", + ("Tolerance specification -1 must be a non-negative number.",), + "Rationalize[3.14159 + 0.8 I, -1]", + None, + ), + ( + "Rationalize[x, y]", + ("Tolerance specification y must be a non-negative number.",), + "Rationalize[x, y]", + None, + ), + ( + "Sign[{1, 2.3, 4/5, {-6.7, 0}, {8/9, -10}}]", + None, + "{1, 1, 1, {-1, 0}, {1, -1}}", + None, + ), + ("Sign[1 - 4*I] == (1/17 - 4 I/17) Sqrt[17]", None, "True", None), + ( + "Sign[4, 5, 6]", + ("Sign called with 3 arguments; 1 argument is expected.",), + "Sign[4, 5, 6]", + None, + ), + ('Sign["20"]', None, "Sign[20]", None), + ], +) +def test_private_doctests_numeric(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/core/parser/test_parser.py b/test/core/parser/test_parser.py index 2b9c33e60..026599044 100644 --- a/test/core/parser/test_parser.py +++ b/test/core/parser/test_parser.py @@ -291,6 +291,8 @@ def testDerivative(self): self.check("f'", "Derivative[1][f]") self.check("f''", "Derivative[2][f]") self.check("f' '", "Derivative[2][f]") + self.check("f '' ''", "Derivative[4][f]") + self.check("Derivative[x][4] '", "Derivative[1][Derivative[x][4]]") def testPlus(self): self.check("+1", Node("Plus", Number("1"))) diff --git a/test/package/test_vectoranalysis.py b/test/package/test_vectoranalysis.py new file mode 100644 index 000000000..c4648b481 --- /dev/null +++ b/test/package/test_vectoranalysis.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- +""" +Unit tests from packages/VectorAnalysis +""" +import os.path as osp +import sys +from test.helper import check_evaluation, evaluate + +import pytest + + +@pytest.mark.parametrize( + ("str_expr", "msgs", "str_expected", "fail_msg"), + [ + (None, None, None, None), + ('Needs["VectorAnalysis`"];', None, "Null", None), + ("DotProduct[{1,2,3}, {4,5,6}]", None, "32", None), + ("DotProduct[{-1.4, 0.6, 0.2}, {0.1, 0.6, 1.7}]", None, "0.56", None), + ("CrossProduct[{1,2,3}, {4,5,6}]", None, "{-3, 6, -3}", None), + ( + "CrossProduct[{-1.4, 0.6, 0.2}, {0.1, 0.6, 1.7}]", + None, + "{0.9, 2.4, -0.9}", + None, + ), + ("ScalarTripleProduct[{-2,3,1},{0,4,0},{-1,3,3}]", None, "-20", None), + ( + "ScalarTripleProduct[{-1.4,0.6,0.2}, {0.1,0.6,1.7}, {0.7,-1.5,-0.2}]", + None, + "-2.79", + None, + ), + ( + "last=CoordinatesToCartesian[{2, Pi, 3}, Spherical]", + None, + "{0, 0, -2}", + None, + ), + ("CoordinatesFromCartesian[last, Spherical]", None, "{2, Pi, 0}", None), + ( + "last=CoordinatesToCartesian[{2, Pi, 3}, Cylindrical]", + None, + "{-2, 0, 3}", + None, + ), + ("CoordinatesFromCartesian[last, Cylindrical]", None, "{2, Pi, 3}", None), + ## Needs Sin/Cos exact value (PR #100) for these tests to pass + # ('last=CoordinatesToCartesian[{2, Pi / 4, Pi / 3}, Spherical]', None, + # '{Sqrt[2] / 2, Sqrt[2] Sqrt[3] / 2, Sqrt[2]}', None), + # ('CoordinatesFromCartesian[last, Spherical]', None, + # '{2, Pi / 4, Pi / 3}', None,), + # ('last=CoordinatesToCartesian[{2, Pi / 4, -1}, Cylindrical]', None, + # '{Sqrt[2], Sqrt[2], -1}', None), + # ('last=CoordinatesFromCartesian[last, Cylindrical]', None, + # '{2, Pi / 4, -1}', None), + ## Continue... + ( + "CoordinatesToCartesian[{0.27, 0.51, 0.92}, Cylindrical]", + None, + "{0.235641, 0.131808, 0.92}", + None, + ), + ( + "CoordinatesToCartesian[{0.27, 0.51, 0.92}, Spherical]", + None, + "{0.0798519, 0.104867, 0.235641}", + None, + ), + ("Coordinates[]", None, "{Xx, Yy, Zz}", None), + ("Coordinates[Spherical]", None, "{Rr, Ttheta, Pphi}", None), + ("SetCoordinates[Cylindrical]", None, "Cylindrical[Rr, Ttheta, Zz]", None), + ("Coordinates[]", None, "{Rr, Ttheta, Zz}", None), + ("CoordinateSystem", None, "Cylindrical", None), + ("Parameters[]", None, "{}", None), + ( + "CoordinateRanges[]", + None, + ## And[a