AI Newsletter Digest improvements: fixed QP soft line break decoding, URL extraction, and content cleaning
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+313
@@ -0,0 +1,313 @@
|
||||
import sympy
|
||||
import tempfile
|
||||
import os
|
||||
from pathlib import Path
|
||||
from sympy.core.mod import Mod
|
||||
from sympy.core.relational import Eq
|
||||
from sympy.core.symbol import symbols
|
||||
from sympy.external import import_module
|
||||
from sympy.tensor import IndexedBase, Idx
|
||||
from sympy.utilities.autowrap import autowrap, ufuncify, CodeWrapError
|
||||
from sympy.testing.pytest import skip
|
||||
|
||||
numpy = import_module('numpy', min_module_version='1.6.1')
|
||||
Cython = import_module('Cython', min_module_version='0.15.1')
|
||||
f2py = import_module('numpy.f2py', import_kwargs={'fromlist': ['f2py']})
|
||||
|
||||
f2pyworks = False
|
||||
if f2py:
|
||||
try:
|
||||
autowrap(symbols('x'), 'f95', 'f2py')
|
||||
except (CodeWrapError, ImportError, OSError):
|
||||
f2pyworks = False
|
||||
else:
|
||||
f2pyworks = True
|
||||
|
||||
a, b, c = symbols('a b c')
|
||||
n, m, d = symbols('n m d', integer=True)
|
||||
A, B, C = symbols('A B C', cls=IndexedBase)
|
||||
i = Idx('i', m)
|
||||
j = Idx('j', n)
|
||||
k = Idx('k', d)
|
||||
|
||||
|
||||
def has_module(module):
|
||||
"""
|
||||
Return True if module exists, otherwise run skip().
|
||||
|
||||
module should be a string.
|
||||
"""
|
||||
# To give a string of the module name to skip(), this function takes a
|
||||
# string. So we don't waste time running import_module() more than once,
|
||||
# just map the three modules tested here in this dict.
|
||||
modnames = {'numpy': numpy, 'Cython': Cython, 'f2py': f2py}
|
||||
|
||||
if modnames[module]:
|
||||
if module == 'f2py' and not f2pyworks:
|
||||
skip("Couldn't run f2py.")
|
||||
return True
|
||||
skip("Couldn't import %s." % module)
|
||||
|
||||
#
|
||||
# test runners used by several language-backend combinations
|
||||
#
|
||||
|
||||
def runtest_autowrap_twice(language, backend):
|
||||
f = autowrap((((a + b)/c)**5).expand(), language, backend)
|
||||
g = autowrap((((a + b)/c)**4).expand(), language, backend)
|
||||
|
||||
# check that autowrap updates the module name. Else, g gives the same as f
|
||||
assert f(1, -2, 1) == -1.0
|
||||
assert g(1, -2, 1) == 1.0
|
||||
|
||||
|
||||
def runtest_autowrap_trace(language, backend):
|
||||
has_module('numpy')
|
||||
trace = autowrap(A[i, i], language, backend)
|
||||
assert trace(numpy.eye(100)) == 100
|
||||
|
||||
|
||||
def runtest_autowrap_matrix_vector(language, backend):
|
||||
has_module('numpy')
|
||||
x, y = symbols('x y', cls=IndexedBase)
|
||||
expr = Eq(y[i], A[i, j]*x[j])
|
||||
mv = autowrap(expr, language, backend)
|
||||
|
||||
# compare with numpy's dot product
|
||||
M = numpy.random.rand(10, 20)
|
||||
x = numpy.random.rand(20)
|
||||
y = numpy.dot(M, x)
|
||||
assert numpy.sum(numpy.abs(y - mv(M, x))) < 1e-13
|
||||
|
||||
|
||||
def runtest_autowrap_matrix_matrix(language, backend):
|
||||
has_module('numpy')
|
||||
expr = Eq(C[i, j], A[i, k]*B[k, j])
|
||||
matmat = autowrap(expr, language, backend)
|
||||
|
||||
# compare with numpy's dot product
|
||||
M1 = numpy.random.rand(10, 20)
|
||||
M2 = numpy.random.rand(20, 15)
|
||||
M3 = numpy.dot(M1, M2)
|
||||
assert numpy.sum(numpy.abs(M3 - matmat(M1, M2))) < 1e-13
|
||||
|
||||
|
||||
def runtest_ufuncify(language, backend):
|
||||
has_module('numpy')
|
||||
a, b, c = symbols('a b c')
|
||||
fabc = ufuncify([a, b, c], a*b + c, backend=backend)
|
||||
facb = ufuncify([a, c, b], a*b + c, backend=backend)
|
||||
grid = numpy.linspace(-2, 2, 50)
|
||||
b = numpy.linspace(-5, 4, 50)
|
||||
c = numpy.linspace(-1, 1, 50)
|
||||
expected = grid*b + c
|
||||
numpy.testing.assert_allclose(fabc(grid, b, c), expected)
|
||||
numpy.testing.assert_allclose(facb(grid, c, b), expected)
|
||||
|
||||
|
||||
def runtest_issue_10274(language, backend):
|
||||
expr = (a - b + c)**(13)
|
||||
tmp = tempfile.mkdtemp()
|
||||
f = autowrap(expr, language, backend, tempdir=tmp,
|
||||
helpers=('helper', a - b + c, (a, b, c)))
|
||||
assert f(1, 1, 1) == 1
|
||||
|
||||
for file in os.listdir(tmp):
|
||||
if not (file.startswith("wrapped_code_") and file.endswith(".c")):
|
||||
continue
|
||||
|
||||
with open(tmp + '/' + file) as fil:
|
||||
lines = fil.readlines()
|
||||
assert lines[0] == "/******************************************************************************\n"
|
||||
assert "Code generated with SymPy " + sympy.__version__ in lines[1]
|
||||
assert lines[2:] == [
|
||||
" * *\n",
|
||||
" * See http://www.sympy.org/ for more information. *\n",
|
||||
" * *\n",
|
||||
" * This file is part of 'autowrap' *\n",
|
||||
" ******************************************************************************/\n",
|
||||
"#include " + '"' + file[:-1]+ 'h"' + "\n",
|
||||
"#include <math.h>\n",
|
||||
"\n",
|
||||
"double helper(double a, double b, double c) {\n",
|
||||
"\n",
|
||||
" double helper_result;\n",
|
||||
" helper_result = a - b + c;\n",
|
||||
" return helper_result;\n",
|
||||
"\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"double autofunc(double a, double b, double c) {\n",
|
||||
"\n",
|
||||
" double autofunc_result;\n",
|
||||
" autofunc_result = pow(helper(a, b, c), 13);\n",
|
||||
" return autofunc_result;\n",
|
||||
"\n",
|
||||
"}\n",
|
||||
]
|
||||
|
||||
|
||||
def runtest_issue_15337(language, backend):
|
||||
has_module('numpy')
|
||||
# NOTE : autowrap was originally designed to only accept an iterable for
|
||||
# the kwarg "helpers", but in issue 10274 the user mistakenly thought that
|
||||
# if there was only a single helper it did not need to be passed via an
|
||||
# iterable that wrapped the helper tuple. There were no tests for this
|
||||
# behavior so when the code was changed to accept a single tuple it broke
|
||||
# the original behavior. These tests below ensure that both now work.
|
||||
a, b, c, d, e = symbols('a, b, c, d, e')
|
||||
expr = (a - b + c - d + e)**13
|
||||
exp_res = (1. - 2. + 3. - 4. + 5.)**13
|
||||
|
||||
f = autowrap(expr, language, backend, args=(a, b, c, d, e),
|
||||
helpers=('f1', a - b + c, (a, b, c)))
|
||||
numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res)
|
||||
|
||||
f = autowrap(expr, language, backend, args=(a, b, c, d, e),
|
||||
helpers=(('f1', a - b, (a, b)), ('f2', c - d, (c, d))))
|
||||
numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res)
|
||||
|
||||
|
||||
def test_issue_15230():
|
||||
has_module('f2py')
|
||||
|
||||
x, y = symbols('x, y')
|
||||
expr = Mod(x, 3.0) - Mod(y, -2.0)
|
||||
f = autowrap(expr, args=[x, y], language='F95')
|
||||
exp_res = float(expr.xreplace({x: 3.5, y: 2.7}).evalf())
|
||||
assert abs(f(3.5, 2.7) - exp_res) < 1e-14
|
||||
|
||||
x, y = symbols('x, y', integer=True)
|
||||
expr = Mod(x, 3) - Mod(y, -2)
|
||||
f = autowrap(expr, args=[x, y], language='F95')
|
||||
assert f(3, 2) == expr.xreplace({x: 3, y: 2})
|
||||
|
||||
#
|
||||
# tests of language-backend combinations
|
||||
#
|
||||
|
||||
# f2py
|
||||
|
||||
|
||||
def test_wrap_twice_f95_f2py():
|
||||
has_module('f2py')
|
||||
runtest_autowrap_twice('f95', 'f2py')
|
||||
|
||||
|
||||
def test_autowrap_trace_f95_f2py():
|
||||
has_module('f2py')
|
||||
runtest_autowrap_trace('f95', 'f2py')
|
||||
|
||||
|
||||
def test_autowrap_matrix_vector_f95_f2py():
|
||||
has_module('f2py')
|
||||
runtest_autowrap_matrix_vector('f95', 'f2py')
|
||||
|
||||
|
||||
def test_autowrap_matrix_matrix_f95_f2py():
|
||||
has_module('f2py')
|
||||
runtest_autowrap_matrix_matrix('f95', 'f2py')
|
||||
|
||||
|
||||
def test_ufuncify_f95_f2py():
|
||||
has_module('f2py')
|
||||
runtest_ufuncify('f95', 'f2py')
|
||||
|
||||
|
||||
def test_issue_15337_f95_f2py():
|
||||
has_module('f2py')
|
||||
runtest_issue_15337('f95', 'f2py')
|
||||
|
||||
# Cython
|
||||
|
||||
|
||||
def test_wrap_twice_c_cython():
|
||||
has_module('Cython')
|
||||
runtest_autowrap_twice('C', 'cython')
|
||||
|
||||
|
||||
def test_autowrap_trace_C_Cython():
|
||||
has_module('Cython')
|
||||
runtest_autowrap_trace('C99', 'cython')
|
||||
|
||||
|
||||
def test_autowrap_matrix_vector_C_cython():
|
||||
has_module('Cython')
|
||||
runtest_autowrap_matrix_vector('C99', 'cython')
|
||||
|
||||
|
||||
def test_autowrap_matrix_matrix_C_cython():
|
||||
has_module('Cython')
|
||||
runtest_autowrap_matrix_matrix('C99', 'cython')
|
||||
|
||||
|
||||
def test_ufuncify_C_Cython():
|
||||
has_module('Cython')
|
||||
runtest_ufuncify('C99', 'cython')
|
||||
|
||||
|
||||
def test_issue_10274_C_cython():
|
||||
has_module('Cython')
|
||||
runtest_issue_10274('C89', 'cython')
|
||||
|
||||
|
||||
def test_issue_15337_C_cython():
|
||||
has_module('Cython')
|
||||
runtest_issue_15337('C89', 'cython')
|
||||
|
||||
|
||||
def test_autowrap_custom_printer():
|
||||
has_module('Cython')
|
||||
|
||||
from sympy.core.numbers import pi
|
||||
from sympy.utilities.codegen import C99CodeGen
|
||||
from sympy.printing.c import C99CodePrinter
|
||||
|
||||
class PiPrinter(C99CodePrinter):
|
||||
def _print_Pi(self, expr):
|
||||
return "S_PI"
|
||||
|
||||
printer = PiPrinter()
|
||||
gen = C99CodeGen(printer=printer)
|
||||
gen.preprocessor_statements.append('#include "shortpi.h"')
|
||||
|
||||
expr = pi * a
|
||||
|
||||
expected = (
|
||||
'#include "%s"\n'
|
||||
'#include <math.h>\n'
|
||||
'#include "shortpi.h"\n'
|
||||
'\n'
|
||||
'double autofunc(double a) {\n'
|
||||
'\n'
|
||||
' double autofunc_result;\n'
|
||||
' autofunc_result = S_PI*a;\n'
|
||||
' return autofunc_result;\n'
|
||||
'\n'
|
||||
'}\n'
|
||||
)
|
||||
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
# write a trivial header file to use in the generated code
|
||||
Path(os.path.join(tmpdir, 'shortpi.h')).write_text('#define S_PI 3.14')
|
||||
|
||||
func = autowrap(expr, backend='cython', tempdir=tmpdir, code_gen=gen)
|
||||
|
||||
assert func(4.2) == 3.14 * 4.2
|
||||
|
||||
# check that the generated code is correct
|
||||
for filename in os.listdir(tmpdir):
|
||||
if filename.startswith('wrapped_code') and filename.endswith('.c'):
|
||||
with open(os.path.join(tmpdir, filename)) as f:
|
||||
lines = f.readlines()
|
||||
expected = expected % filename.replace('.c', '.h')
|
||||
assert ''.join(lines[7:]) == expected
|
||||
|
||||
|
||||
# Numpy
|
||||
|
||||
def test_ufuncify_numpy():
|
||||
# This test doesn't use Cython, but if Cython works, then there is a valid
|
||||
# C compiler, which is needed.
|
||||
has_module('Cython')
|
||||
runtest_ufuncify('C99', 'numpy')
|
||||
+375
@@ -0,0 +1,375 @@
|
||||
# This tests the compilation and execution of the source code generated with
|
||||
# utilities.codegen. The compilation takes place in a temporary directory that
|
||||
# is removed after the test. By default the test directory is always removed,
|
||||
# but this behavior can be changed by setting the environment variable
|
||||
# SYMPY_TEST_CLEAN_TEMP to:
|
||||
# export SYMPY_TEST_CLEAN_TEMP=always : the default behavior.
|
||||
# export SYMPY_TEST_CLEAN_TEMP=success : only remove the directories of working tests.
|
||||
# export SYMPY_TEST_CLEAN_TEMP=never : never remove the directories with the test code.
|
||||
# When a directory is not removed, the necessary information is printed on
|
||||
# screen to find the files that belong to the (failed) tests. If a test does
|
||||
# not fail, py.test captures all the output and you will not see the directories
|
||||
# corresponding to the successful tests. Use the --nocapture option to see all
|
||||
# the output.
|
||||
|
||||
# All tests below have a counterpart in utilities/test/test_codegen.py. In the
|
||||
# latter file, the resulting code is compared with predefined strings, without
|
||||
# compilation or execution.
|
||||
|
||||
# All the generated Fortran code should conform with the Fortran 95 standard,
|
||||
# and all the generated C code should be ANSI C, which facilitates the
|
||||
# incorporation in various projects. The tests below assume that the binary cc
|
||||
# is somewhere in the path and that it can compile ANSI C code.
|
||||
|
||||
from sympy.abc import x, y, z
|
||||
from sympy.testing.pytest import IS_WASM, skip
|
||||
from sympy.utilities.codegen import codegen, make_routine, get_code_generator
|
||||
import sys
|
||||
import os
|
||||
import tempfile
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
# templates for the main program that will test the generated code.
|
||||
|
||||
main_template = {}
|
||||
main_template['F95'] = """
|
||||
program main
|
||||
include "codegen.h"
|
||||
integer :: result;
|
||||
result = 0
|
||||
|
||||
%(statements)s
|
||||
|
||||
call exit(result)
|
||||
end program
|
||||
"""
|
||||
|
||||
main_template['C89'] = """
|
||||
#include "codegen.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
int main() {
|
||||
int result = 0;
|
||||
|
||||
%(statements)s
|
||||
|
||||
return result;
|
||||
}
|
||||
"""
|
||||
main_template['C99'] = main_template['C89']
|
||||
# templates for the numerical tests
|
||||
|
||||
numerical_test_template = {}
|
||||
numerical_test_template['C89'] = """
|
||||
if (fabs(%(call)s)>%(threshold)s) {
|
||||
printf("Numerical validation failed: %(call)s=%%e threshold=%(threshold)s\\n", %(call)s);
|
||||
result = -1;
|
||||
}
|
||||
"""
|
||||
numerical_test_template['C99'] = numerical_test_template['C89']
|
||||
|
||||
numerical_test_template['F95'] = """
|
||||
if (abs(%(call)s)>%(threshold)s) then
|
||||
write(6,"('Numerical validation failed:')")
|
||||
write(6,"('%(call)s=',e15.5,'threshold=',e15.5)") %(call)s, %(threshold)s
|
||||
result = -1;
|
||||
end if
|
||||
"""
|
||||
# command sequences for supported compilers
|
||||
|
||||
compile_commands = {}
|
||||
compile_commands['cc'] = [
|
||||
"cc -c codegen.c -o codegen.o",
|
||||
"cc -c main.c -o main.o",
|
||||
"cc main.o codegen.o -lm -o test.exe"
|
||||
]
|
||||
|
||||
compile_commands['gfortran'] = [
|
||||
"gfortran -c codegen.f90 -o codegen.o",
|
||||
"gfortran -ffree-line-length-none -c main.f90 -o main.o",
|
||||
"gfortran main.o codegen.o -o test.exe"
|
||||
]
|
||||
|
||||
compile_commands['g95'] = [
|
||||
"g95 -c codegen.f90 -o codegen.o",
|
||||
"g95 -ffree-line-length-huge -c main.f90 -o main.o",
|
||||
"g95 main.o codegen.o -o test.exe"
|
||||
]
|
||||
|
||||
compile_commands['ifort'] = [
|
||||
"ifort -c codegen.f90 -o codegen.o",
|
||||
"ifort -c main.f90 -o main.o",
|
||||
"ifort main.o codegen.o -o test.exe"
|
||||
]
|
||||
|
||||
combinations_lang_compiler = [
|
||||
('C89', 'cc'),
|
||||
('C99', 'cc'),
|
||||
('F95', 'ifort'),
|
||||
('F95', 'gfortran'),
|
||||
('F95', 'g95')
|
||||
]
|
||||
|
||||
def try_run(commands):
|
||||
"""Run a series of commands and only return True if all ran fine."""
|
||||
if IS_WASM:
|
||||
return False
|
||||
with open(os.devnull, 'w') as null:
|
||||
for command in commands:
|
||||
retcode = subprocess.call(command, stdout=null, shell=True,
|
||||
stderr=subprocess.STDOUT)
|
||||
if retcode != 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def run_test(label, routines, numerical_tests, language, commands, friendly=True):
|
||||
"""A driver for the codegen tests.
|
||||
|
||||
This driver assumes that a compiler ifort is present in the PATH and that
|
||||
ifort is (at least) a Fortran 90 compiler. The generated code is written in
|
||||
a temporary directory, together with a main program that validates the
|
||||
generated code. The test passes when the compilation and the validation
|
||||
run correctly.
|
||||
"""
|
||||
|
||||
# Check input arguments before touching the file system
|
||||
language = language.upper()
|
||||
assert language in main_template
|
||||
assert language in numerical_test_template
|
||||
|
||||
# Check that environment variable makes sense
|
||||
clean = os.getenv('SYMPY_TEST_CLEAN_TEMP', 'always').lower()
|
||||
if clean not in ('always', 'success', 'never'):
|
||||
raise ValueError("SYMPY_TEST_CLEAN_TEMP must be one of the following: 'always', 'success' or 'never'.")
|
||||
|
||||
# Do all the magic to compile, run and validate the test code
|
||||
# 1) prepare the temporary working directory, switch to that dir
|
||||
work = tempfile.mkdtemp("_sympy_%s_test" % language, "%s_" % label)
|
||||
oldwork = os.getcwd()
|
||||
os.chdir(work)
|
||||
|
||||
# 2) write the generated code
|
||||
if friendly:
|
||||
# interpret the routines as a name_expr list and call the friendly
|
||||
# function codegen
|
||||
codegen(routines, language, "codegen", to_files=True)
|
||||
else:
|
||||
code_gen = get_code_generator(language, "codegen")
|
||||
code_gen.write(routines, "codegen", to_files=True)
|
||||
|
||||
# 3) write a simple main program that links to the generated code, and that
|
||||
# includes the numerical tests
|
||||
test_strings = []
|
||||
for fn_name, args, expected, threshold in numerical_tests:
|
||||
call_string = "%s(%s)-(%s)" % (
|
||||
fn_name, ",".join(str(arg) for arg in args), expected)
|
||||
if language == "F95":
|
||||
call_string = fortranize_double_constants(call_string)
|
||||
threshold = fortranize_double_constants(str(threshold))
|
||||
test_strings.append(numerical_test_template[language] % {
|
||||
"call": call_string,
|
||||
"threshold": threshold,
|
||||
})
|
||||
|
||||
if language == "F95":
|
||||
f_name = "main.f90"
|
||||
elif language.startswith("C"):
|
||||
f_name = "main.c"
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
"FIXME: filename extension unknown for language: %s" % language)
|
||||
|
||||
Path(f_name).write_text(
|
||||
main_template[language] % {'statements': "".join(test_strings)})
|
||||
|
||||
# 4) Compile and link
|
||||
compiled = try_run(commands)
|
||||
|
||||
# 5) Run if compiled
|
||||
if compiled:
|
||||
executed = try_run(["./test.exe"])
|
||||
else:
|
||||
executed = False
|
||||
|
||||
# 6) Clean up stuff
|
||||
if clean == 'always' or (clean == 'success' and compiled and executed):
|
||||
def safe_remove(filename):
|
||||
if os.path.isfile(filename):
|
||||
os.remove(filename)
|
||||
safe_remove("codegen.f90")
|
||||
safe_remove("codegen.c")
|
||||
safe_remove("codegen.h")
|
||||
safe_remove("codegen.o")
|
||||
safe_remove("main.f90")
|
||||
safe_remove("main.c")
|
||||
safe_remove("main.o")
|
||||
safe_remove("test.exe")
|
||||
os.chdir(oldwork)
|
||||
os.rmdir(work)
|
||||
else:
|
||||
print("TEST NOT REMOVED: %s" % work, file=sys.stderr)
|
||||
os.chdir(oldwork)
|
||||
|
||||
# 7) Do the assertions in the end
|
||||
assert compiled, "failed to compile %s code with:\n%s" % (
|
||||
language, "\n".join(commands))
|
||||
assert executed, "failed to execute %s code from:\n%s" % (
|
||||
language, "\n".join(commands))
|
||||
|
||||
|
||||
def fortranize_double_constants(code_string):
|
||||
"""
|
||||
Replaces every literal float with literal doubles
|
||||
"""
|
||||
import re
|
||||
pattern_exp = re.compile(r'\d+(\.)?\d*[eE]-?\d+')
|
||||
pattern_float = re.compile(r'\d+\.\d*(?!\d*d)')
|
||||
|
||||
def subs_exp(matchobj):
|
||||
return re.sub('[eE]', 'd', matchobj.group(0))
|
||||
|
||||
def subs_float(matchobj):
|
||||
return "%sd0" % matchobj.group(0)
|
||||
|
||||
code_string = pattern_exp.sub(subs_exp, code_string)
|
||||
code_string = pattern_float.sub(subs_float, code_string)
|
||||
|
||||
return code_string
|
||||
|
||||
|
||||
def is_feasible(language, commands):
|
||||
# This test should always work, otherwise the compiler is not present.
|
||||
routine = make_routine("test", x)
|
||||
numerical_tests = [
|
||||
("test", ( 1.0,), 1.0, 1e-15),
|
||||
("test", (-1.0,), -1.0, 1e-15),
|
||||
]
|
||||
try:
|
||||
run_test("is_feasible", [routine], numerical_tests, language, commands,
|
||||
friendly=False)
|
||||
return True
|
||||
except AssertionError:
|
||||
return False
|
||||
|
||||
valid_lang_commands = []
|
||||
invalid_lang_compilers = []
|
||||
for lang, compiler in combinations_lang_compiler:
|
||||
commands = compile_commands[compiler]
|
||||
if is_feasible(lang, commands):
|
||||
valid_lang_commands.append((lang, commands))
|
||||
else:
|
||||
invalid_lang_compilers.append((lang, compiler))
|
||||
|
||||
# We test all language-compiler combinations, just to report what is skipped
|
||||
|
||||
def test_C89_cc():
|
||||
if ("C89", 'cc') in invalid_lang_compilers:
|
||||
skip("`cc' command didn't work as expected (C89)")
|
||||
|
||||
|
||||
def test_C99_cc():
|
||||
if ("C99", 'cc') in invalid_lang_compilers:
|
||||
skip("`cc' command didn't work as expected (C99)")
|
||||
|
||||
|
||||
def test_F95_ifort():
|
||||
if ("F95", 'ifort') in invalid_lang_compilers:
|
||||
skip("`ifort' command didn't work as expected")
|
||||
|
||||
|
||||
def test_F95_gfortran():
|
||||
if ("F95", 'gfortran') in invalid_lang_compilers:
|
||||
skip("`gfortran' command didn't work as expected")
|
||||
|
||||
|
||||
def test_F95_g95():
|
||||
if ("F95", 'g95') in invalid_lang_compilers:
|
||||
skip("`g95' command didn't work as expected")
|
||||
|
||||
# Here comes the actual tests
|
||||
|
||||
|
||||
def test_basic_codegen():
|
||||
numerical_tests = [
|
||||
("test", (1.0, 6.0, 3.0), 21.0, 1e-15),
|
||||
("test", (-1.0, 2.0, -2.5), -2.5, 1e-15),
|
||||
]
|
||||
name_expr = [("test", (x + y)*z)]
|
||||
for lang, commands in valid_lang_commands:
|
||||
run_test("basic_codegen", name_expr, numerical_tests, lang, commands)
|
||||
|
||||
|
||||
def test_intrinsic_math1_codegen():
|
||||
# not included: log10
|
||||
from sympy.core.evalf import N
|
||||
from sympy.functions import ln
|
||||
from sympy.functions.elementary.exponential import log
|
||||
from sympy.functions.elementary.hyperbolic import (cosh, sinh, tanh)
|
||||
from sympy.functions.elementary.integers import (ceiling, floor)
|
||||
from sympy.functions.elementary.miscellaneous import sqrt
|
||||
from sympy.functions.elementary.trigonometric import (acos, asin, atan, cos, sin, tan)
|
||||
name_expr = [
|
||||
("test_fabs", abs(x)),
|
||||
("test_acos", acos(x)),
|
||||
("test_asin", asin(x)),
|
||||
("test_atan", atan(x)),
|
||||
("test_cos", cos(x)),
|
||||
("test_cosh", cosh(x)),
|
||||
("test_log", log(x)),
|
||||
("test_ln", ln(x)),
|
||||
("test_sin", sin(x)),
|
||||
("test_sinh", sinh(x)),
|
||||
("test_sqrt", sqrt(x)),
|
||||
("test_tan", tan(x)),
|
||||
("test_tanh", tanh(x)),
|
||||
]
|
||||
numerical_tests = []
|
||||
for name, expr in name_expr:
|
||||
for xval in 0.2, 0.5, 0.8:
|
||||
expected = N(expr.subs(x, xval))
|
||||
numerical_tests.append((name, (xval,), expected, 1e-14))
|
||||
for lang, commands in valid_lang_commands:
|
||||
if lang.startswith("C"):
|
||||
name_expr_C = [("test_floor", floor(x)), ("test_ceil", ceiling(x))]
|
||||
else:
|
||||
name_expr_C = []
|
||||
run_test("intrinsic_math1", name_expr + name_expr_C,
|
||||
numerical_tests, lang, commands)
|
||||
|
||||
|
||||
def test_instrinsic_math2_codegen():
|
||||
# not included: frexp, ldexp, modf, fmod
|
||||
from sympy.core.evalf import N
|
||||
from sympy.functions.elementary.trigonometric import atan2
|
||||
name_expr = [
|
||||
("test_atan2", atan2(x, y)),
|
||||
("test_pow", x**y),
|
||||
]
|
||||
numerical_tests = []
|
||||
for name, expr in name_expr:
|
||||
for xval, yval in (0.2, 1.3), (0.5, -0.2), (0.8, 0.8):
|
||||
expected = N(expr.subs(x, xval).subs(y, yval))
|
||||
numerical_tests.append((name, (xval, yval), expected, 1e-14))
|
||||
for lang, commands in valid_lang_commands:
|
||||
run_test("intrinsic_math2", name_expr, numerical_tests, lang, commands)
|
||||
|
||||
|
||||
def test_complicated_codegen():
|
||||
from sympy.core.evalf import N
|
||||
from sympy.functions.elementary.trigonometric import (cos, sin, tan)
|
||||
name_expr = [
|
||||
("test1", ((sin(x) + cos(y) + tan(z))**7).expand()),
|
||||
("test2", cos(cos(cos(cos(cos(cos(cos(cos(x + y + z))))))))),
|
||||
]
|
||||
numerical_tests = []
|
||||
for name, expr in name_expr:
|
||||
for xval, yval, zval in (0.2, 1.3, -0.3), (0.5, -0.2, 0.0), (0.8, 2.1, 0.8):
|
||||
expected = N(expr.subs(x, xval).subs(y, yval).subs(z, zval))
|
||||
numerical_tests.append((name, (xval, yval, zval), expected, 1e-12))
|
||||
for lang, commands in valid_lang_commands:
|
||||
run_test(
|
||||
"complicated_codegen", name_expr, numerical_tests, lang, commands)
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
from sympy.external.gmpy import LONG_MAX, iroot
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_iroot():
|
||||
assert iroot(2, LONG_MAX) == (1, False)
|
||||
assert iroot(2, LONG_MAX + 1) == (1, False)
|
||||
for x in range(3):
|
||||
assert iroot(x, 1) == (x, True)
|
||||
raises(ValueError, lambda: iroot(-1, 1))
|
||||
raises(ValueError, lambda: iroot(0, 0))
|
||||
raises(ValueError, lambda: iroot(0, -1))
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
from sympy.external import import_module
|
||||
from sympy.testing.pytest import warns
|
||||
|
||||
# fixes issue that arose in addressing issue 6533
|
||||
def test_no_stdlib_collections():
|
||||
'''
|
||||
make sure we get the right collections when it is not part of a
|
||||
larger list
|
||||
'''
|
||||
import collections
|
||||
matplotlib = import_module('matplotlib',
|
||||
import_kwargs={'fromlist': ['cm', 'collections']},
|
||||
min_module_version='1.1.0', catch=(RuntimeError,))
|
||||
if matplotlib:
|
||||
assert collections != matplotlib.collections
|
||||
|
||||
def test_no_stdlib_collections2():
|
||||
'''
|
||||
make sure we get the right collections when it is not part of a
|
||||
larger list
|
||||
'''
|
||||
import collections
|
||||
matplotlib = import_module('matplotlib',
|
||||
import_kwargs={'fromlist': ['collections']},
|
||||
min_module_version='1.1.0', catch=(RuntimeError,))
|
||||
if matplotlib:
|
||||
assert collections != matplotlib.collections
|
||||
|
||||
def test_no_stdlib_collections3():
|
||||
'''make sure we get the right collections with no catch'''
|
||||
import collections
|
||||
matplotlib = import_module('matplotlib',
|
||||
import_kwargs={'fromlist': ['cm', 'collections']},
|
||||
min_module_version='1.1.0')
|
||||
if matplotlib:
|
||||
assert collections != matplotlib.collections
|
||||
|
||||
def test_min_module_version_python3_basestring_error():
|
||||
with warns(UserWarning):
|
||||
import_module('mpmath', min_module_version='1000.0.1')
|
||||
+307
@@ -0,0 +1,307 @@
|
||||
from itertools import permutations
|
||||
|
||||
from sympy.external.ntheory import (bit_scan1, remove, bit_scan0, is_fermat_prp,
|
||||
is_euler_prp, is_strong_prp, gcdext, _lucas_sequence,
|
||||
is_fibonacci_prp, is_lucas_prp, is_selfridge_prp,
|
||||
is_strong_lucas_prp, is_strong_selfridge_prp,
|
||||
is_bpsw_prp, is_strong_bpsw_prp)
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
def test_bit_scan1():
|
||||
assert bit_scan1(0) is None
|
||||
assert bit_scan1(1) == 0
|
||||
assert bit_scan1(-1) == 0
|
||||
assert bit_scan1(2) == 1
|
||||
assert bit_scan1(7) == 0
|
||||
assert bit_scan1(-7) == 0
|
||||
for i in range(100):
|
||||
assert bit_scan1(1 << i) == i
|
||||
assert bit_scan1((1 << i) * 31337) == i
|
||||
for i in range(500):
|
||||
n = (1 << 500) + (1 << i)
|
||||
assert bit_scan1(n) == i
|
||||
assert bit_scan1(1 << 1000001) == 1000001
|
||||
assert bit_scan1((1 << 273956)*7**37) == 273956
|
||||
# issue 12709
|
||||
for i in range(1, 10):
|
||||
big = 1 << i
|
||||
assert bit_scan1(-big) == bit_scan1(big)
|
||||
|
||||
|
||||
def test_bit_scan0():
|
||||
assert bit_scan0(-1) is None
|
||||
assert bit_scan0(0) == 0
|
||||
assert bit_scan0(1) == 1
|
||||
assert bit_scan0(-2) == 0
|
||||
|
||||
|
||||
def test_remove():
|
||||
raises(ValueError, lambda: remove(1, 1))
|
||||
assert remove(0, 3) == (0, 0)
|
||||
for f in range(2, 10):
|
||||
for y in range(2, 1000):
|
||||
for z in [1, 17, 101, 1009]:
|
||||
assert remove(z*f**y, f) == (z, y)
|
||||
|
||||
|
||||
def test_gcdext():
|
||||
assert gcdext(0, 0) == (0, 0, 0)
|
||||
assert gcdext(3, 0) == (3, 1, 0)
|
||||
assert gcdext(0, 4) == (4, 0, 1)
|
||||
|
||||
for n in range(1, 10):
|
||||
assert gcdext(n, 1) == gcdext(-n, 1) == (1, 0, 1)
|
||||
assert gcdext(n, -1) == gcdext(-n, -1) == (1, 0, -1)
|
||||
assert gcdext(n, n) == gcdext(-n, n) == (n, 0, 1)
|
||||
assert gcdext(n, -n) == gcdext(-n, -n) == (n, 0, -1)
|
||||
|
||||
for n in range(2, 10):
|
||||
assert gcdext(1, n) == gcdext(1, -n) == (1, 1, 0)
|
||||
assert gcdext(-1, n) == gcdext(-1, -n) == (1, -1, 0)
|
||||
|
||||
for a, b in permutations([2**5, 3, 5, 7**2, 11], 2):
|
||||
g, x, y = gcdext(a, b)
|
||||
assert g == a*x + b*y == 1
|
||||
|
||||
|
||||
def test_is_fermat_prp():
|
||||
# invalid input
|
||||
raises(ValueError, lambda: is_fermat_prp(0, 10))
|
||||
raises(ValueError, lambda: is_fermat_prp(5, 1))
|
||||
|
||||
# n = 1
|
||||
assert not is_fermat_prp(1, 3)
|
||||
|
||||
# n is prime
|
||||
assert is_fermat_prp(2, 4)
|
||||
assert is_fermat_prp(3, 2)
|
||||
assert is_fermat_prp(11, 3)
|
||||
assert is_fermat_prp(2**31-1, 5)
|
||||
|
||||
# A001567
|
||||
pseudorpime = [341, 561, 645, 1105, 1387, 1729, 1905, 2047,
|
||||
2465, 2701, 2821, 3277, 4033, 4369, 4371, 4681]
|
||||
for n in pseudorpime:
|
||||
assert is_fermat_prp(n, 2)
|
||||
|
||||
# A020136
|
||||
pseudorpime = [15, 85, 91, 341, 435, 451, 561, 645, 703, 1105,
|
||||
1247, 1271, 1387, 1581, 1695, 1729, 1891, 1905]
|
||||
for n in pseudorpime:
|
||||
assert is_fermat_prp(n, 4)
|
||||
|
||||
|
||||
def test_is_euler_prp():
|
||||
# invalid input
|
||||
raises(ValueError, lambda: is_euler_prp(0, 10))
|
||||
raises(ValueError, lambda: is_euler_prp(5, 1))
|
||||
|
||||
# n = 1
|
||||
assert not is_euler_prp(1, 3)
|
||||
|
||||
# n is prime
|
||||
assert is_euler_prp(2, 4)
|
||||
assert is_euler_prp(3, 2)
|
||||
assert is_euler_prp(11, 3)
|
||||
assert is_euler_prp(2**31-1, 5)
|
||||
|
||||
# A047713
|
||||
pseudorpime = [561, 1105, 1729, 1905, 2047, 2465, 3277, 4033,
|
||||
4681, 6601, 8321, 8481, 10585, 12801, 15841]
|
||||
for n in pseudorpime:
|
||||
assert is_euler_prp(n, 2)
|
||||
|
||||
# A048950
|
||||
pseudorpime = [121, 703, 1729, 1891, 2821, 3281, 7381, 8401,
|
||||
8911, 10585, 12403, 15457, 15841, 16531, 18721]
|
||||
for n in pseudorpime:
|
||||
assert is_euler_prp(n, 3)
|
||||
|
||||
|
||||
def test_is_strong_prp():
|
||||
# invalid input
|
||||
raises(ValueError, lambda: is_strong_prp(0, 10))
|
||||
raises(ValueError, lambda: is_strong_prp(5, 1))
|
||||
|
||||
# n = 1
|
||||
assert not is_strong_prp(1, 3)
|
||||
|
||||
# n is prime
|
||||
assert is_strong_prp(2, 4)
|
||||
assert is_strong_prp(3, 2)
|
||||
assert is_strong_prp(11, 3)
|
||||
assert is_strong_prp(2**31-1, 5)
|
||||
|
||||
# A001262
|
||||
pseudorpime = [2047, 3277, 4033, 4681, 8321, 15841, 29341,
|
||||
42799, 49141, 52633, 65281, 74665, 80581]
|
||||
for n in pseudorpime:
|
||||
assert is_strong_prp(n, 2)
|
||||
|
||||
# A020229
|
||||
pseudorpime = [121, 703, 1891, 3281, 8401, 8911, 10585, 12403,
|
||||
16531, 18721, 19345, 23521, 31621, 44287, 47197]
|
||||
for n in pseudorpime:
|
||||
assert is_strong_prp(n, 3)
|
||||
|
||||
|
||||
def test_lucas_sequence():
|
||||
def lucas_u(P, Q, length):
|
||||
array = [0] * length
|
||||
array[1] = 1
|
||||
for k in range(2, length):
|
||||
array[k] = P * array[k - 1] - Q * array[k - 2]
|
||||
return array
|
||||
|
||||
def lucas_v(P, Q, length):
|
||||
array = [0] * length
|
||||
array[0] = 2
|
||||
array[1] = P
|
||||
for k in range(2, length):
|
||||
array[k] = P * array[k - 1] - Q * array[k - 2]
|
||||
return array
|
||||
|
||||
length = 20
|
||||
for P in range(-10, 10):
|
||||
for Q in range(-10, 10):
|
||||
D = P**2 - 4*Q
|
||||
if D == 0:
|
||||
continue
|
||||
us = lucas_u(P, Q, length)
|
||||
vs = lucas_v(P, Q, length)
|
||||
for n in range(3, 100, 2):
|
||||
for k in range(length):
|
||||
U, V, Qk = _lucas_sequence(n, P, Q, k)
|
||||
assert U == us[k] % n
|
||||
assert V == vs[k] % n
|
||||
assert pow(Q, k, n) == Qk
|
||||
|
||||
|
||||
def test_is_fibonacci_prp():
|
||||
# invalid input
|
||||
raises(ValueError, lambda: is_fibonacci_prp(3, 2, 1))
|
||||
raises(ValueError, lambda: is_fibonacci_prp(3, -5, 1))
|
||||
raises(ValueError, lambda: is_fibonacci_prp(3, 5, 2))
|
||||
raises(ValueError, lambda: is_fibonacci_prp(0, 5, -1))
|
||||
|
||||
# n = 1
|
||||
assert not is_fibonacci_prp(1, 3, 1)
|
||||
|
||||
# n is prime
|
||||
assert is_fibonacci_prp(2, 5, 1)
|
||||
assert is_fibonacci_prp(3, 6, -1)
|
||||
assert is_fibonacci_prp(11, 7, 1)
|
||||
assert is_fibonacci_prp(2**31-1, 8, -1)
|
||||
|
||||
# A005845
|
||||
pseudorpime = [705, 2465, 2737, 3745, 4181, 5777, 6721,
|
||||
10877, 13201, 15251, 24465, 29281, 34561]
|
||||
for n in pseudorpime:
|
||||
assert is_fibonacci_prp(n, 1, -1)
|
||||
|
||||
|
||||
def test_is_lucas_prp():
|
||||
# invalid input
|
||||
raises(ValueError, lambda: is_lucas_prp(3, 2, 1))
|
||||
raises(ValueError, lambda: is_lucas_prp(0, 5, -1))
|
||||
raises(ValueError, lambda: is_lucas_prp(15, 3, 1))
|
||||
|
||||
# n = 1
|
||||
assert not is_lucas_prp(1, 3, 1)
|
||||
|
||||
# n is prime
|
||||
assert is_lucas_prp(2, 5, 2)
|
||||
assert is_lucas_prp(3, 6, -1)
|
||||
assert is_lucas_prp(11, 7, 5)
|
||||
assert is_lucas_prp(2**31-1, 8, -3)
|
||||
|
||||
# A081264
|
||||
pseudorpime = [323, 377, 1891, 3827, 4181, 5777, 6601, 6721,
|
||||
8149, 10877, 11663, 13201, 13981, 15251, 17119]
|
||||
for n in pseudorpime:
|
||||
assert is_lucas_prp(n, 1, -1)
|
||||
|
||||
|
||||
def test_is_selfridge_prp():
|
||||
# invalid input
|
||||
raises(ValueError, lambda: is_selfridge_prp(0))
|
||||
|
||||
# n = 1
|
||||
assert not is_selfridge_prp(1)
|
||||
|
||||
# n is prime
|
||||
assert is_selfridge_prp(2)
|
||||
assert is_selfridge_prp(3)
|
||||
assert is_selfridge_prp(11)
|
||||
assert is_selfridge_prp(2**31-1)
|
||||
|
||||
# A217120
|
||||
pseudorpime = [323, 377, 1159, 1829, 3827, 5459, 5777, 9071,
|
||||
9179, 10877, 11419, 11663, 13919, 14839, 16109]
|
||||
for n in pseudorpime:
|
||||
assert is_selfridge_prp(n)
|
||||
|
||||
|
||||
def test_is_strong_lucas_prp():
|
||||
# invalid input
|
||||
raises(ValueError, lambda: is_strong_lucas_prp(3, 2, 1))
|
||||
raises(ValueError, lambda: is_strong_lucas_prp(0, 5, -1))
|
||||
raises(ValueError, lambda: is_strong_lucas_prp(15, 3, 1))
|
||||
|
||||
# n = 1
|
||||
assert not is_strong_lucas_prp(1, 3, 1)
|
||||
|
||||
# n is prime
|
||||
assert is_strong_lucas_prp(2, 5, 2)
|
||||
assert is_strong_lucas_prp(3, 6, -1)
|
||||
assert is_strong_lucas_prp(11, 7, 5)
|
||||
assert is_strong_lucas_prp(2**31-1, 8, -3)
|
||||
|
||||
|
||||
def test_is_strong_selfridge_prp():
|
||||
# invalid input
|
||||
raises(ValueError, lambda: is_strong_selfridge_prp(0))
|
||||
|
||||
# n = 1
|
||||
assert not is_strong_selfridge_prp(1)
|
||||
|
||||
# n is prime
|
||||
assert is_strong_selfridge_prp(2)
|
||||
assert is_strong_selfridge_prp(3)
|
||||
assert is_strong_selfridge_prp(11)
|
||||
assert is_strong_selfridge_prp(2**31-1)
|
||||
|
||||
# A217255
|
||||
pseudorpime = [5459, 5777, 10877, 16109, 18971, 22499, 24569,
|
||||
25199, 40309, 58519, 75077, 97439, 100127, 113573]
|
||||
for n in pseudorpime:
|
||||
assert is_strong_selfridge_prp(n)
|
||||
|
||||
|
||||
def test_is_bpsw_prp():
|
||||
# invalid input
|
||||
raises(ValueError, lambda: is_bpsw_prp(0))
|
||||
|
||||
# n = 1
|
||||
assert not is_bpsw_prp(1)
|
||||
|
||||
# n is prime
|
||||
assert is_bpsw_prp(2)
|
||||
assert is_bpsw_prp(3)
|
||||
assert is_bpsw_prp(11)
|
||||
assert is_bpsw_prp(2**31-1)
|
||||
|
||||
|
||||
def test_is_strong_bpsw_prp():
|
||||
# invalid input
|
||||
raises(ValueError, lambda: is_strong_bpsw_prp(0))
|
||||
|
||||
# n = 1
|
||||
assert not is_strong_bpsw_prp(1)
|
||||
|
||||
# n is prime
|
||||
assert is_strong_bpsw_prp(2)
|
||||
assert is_strong_bpsw_prp(3)
|
||||
assert is_strong_bpsw_prp(11)
|
||||
assert is_strong_bpsw_prp(2**31-1)
|
||||
+335
@@ -0,0 +1,335 @@
|
||||
# This testfile tests SymPy <-> NumPy compatibility
|
||||
|
||||
# Don't test any SymPy features here. Just pure interaction with NumPy.
|
||||
# Always write regular SymPy tests for anything, that can be tested in pure
|
||||
# Python (without numpy). Here we test everything, that a user may need when
|
||||
# using SymPy with NumPy
|
||||
from sympy.external.importtools import version_tuple
|
||||
from sympy.external import import_module
|
||||
|
||||
numpy = import_module('numpy')
|
||||
if numpy:
|
||||
array, matrix, ndarray = numpy.array, numpy.matrix, numpy.ndarray
|
||||
else:
|
||||
#bin/test will not execute any tests now
|
||||
disabled = True
|
||||
|
||||
|
||||
from sympy.core.numbers import (Float, Integer, Rational)
|
||||
from sympy.core.symbol import (Symbol, symbols)
|
||||
from sympy.functions.elementary.trigonometric import sin
|
||||
from sympy.matrices.dense import (Matrix, list2numpy, matrix2numpy, symarray)
|
||||
from sympy.utilities.lambdify import lambdify
|
||||
import sympy
|
||||
|
||||
import mpmath
|
||||
from sympy.abc import x, y, z
|
||||
from sympy.utilities.decorator import conserve_mpmath_dps
|
||||
from sympy.utilities.exceptions import ignore_warnings
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
|
||||
# first, systematically check, that all operations are implemented and don't
|
||||
# raise an exception
|
||||
|
||||
|
||||
def test_systematic_basic():
|
||||
def s(sympy_object, numpy_array):
|
||||
_ = [sympy_object + numpy_array,
|
||||
numpy_array + sympy_object,
|
||||
sympy_object - numpy_array,
|
||||
numpy_array - sympy_object,
|
||||
sympy_object * numpy_array,
|
||||
numpy_array * sympy_object,
|
||||
sympy_object / numpy_array,
|
||||
numpy_array / sympy_object,
|
||||
sympy_object ** numpy_array,
|
||||
numpy_array ** sympy_object]
|
||||
x = Symbol("x")
|
||||
y = Symbol("y")
|
||||
sympy_objs = [
|
||||
Rational(2, 3),
|
||||
Float("1.3"),
|
||||
x,
|
||||
y,
|
||||
pow(x, y)*y,
|
||||
Integer(5),
|
||||
Float(5.5),
|
||||
]
|
||||
numpy_objs = [
|
||||
array([1]),
|
||||
array([3, 8, -1]),
|
||||
array([x, x**2, Rational(5)]),
|
||||
array([x/y*sin(y), 5, Rational(5)]),
|
||||
]
|
||||
for x in sympy_objs:
|
||||
for y in numpy_objs:
|
||||
s(x, y)
|
||||
|
||||
|
||||
# now some random tests, that test particular problems and that also
|
||||
# check that the results of the operations are correct
|
||||
|
||||
def test_basics():
|
||||
one = Rational(1)
|
||||
zero = Rational(0)
|
||||
assert array(1) == array(one)
|
||||
assert array([one]) == array([one])
|
||||
assert array([x]) == array([x])
|
||||
assert array(x) == array(Symbol("x"))
|
||||
assert array(one + x) == array(1 + x)
|
||||
|
||||
X = array([one, zero, zero])
|
||||
assert (X == array([one, zero, zero])).all()
|
||||
assert (X == array([one, 0, 0])).all()
|
||||
|
||||
|
||||
def test_arrays():
|
||||
one = Rational(1)
|
||||
zero = Rational(0)
|
||||
X = array([one, zero, zero])
|
||||
Y = one*X
|
||||
X = array([Symbol("a") + Rational(1, 2)])
|
||||
Y = X + X
|
||||
assert Y == array([1 + 2*Symbol("a")])
|
||||
Y = Y + 1
|
||||
assert Y == array([2 + 2*Symbol("a")])
|
||||
Y = X - X
|
||||
assert Y == array([0])
|
||||
|
||||
|
||||
def test_conversion1():
|
||||
a = list2numpy([x**2, x])
|
||||
#looks like an array?
|
||||
assert isinstance(a, ndarray)
|
||||
assert a[0] == x**2
|
||||
assert a[1] == x
|
||||
assert len(a) == 2
|
||||
#yes, it's the array
|
||||
|
||||
|
||||
def test_conversion2():
|
||||
a = 2*list2numpy([x**2, x])
|
||||
b = list2numpy([2*x**2, 2*x])
|
||||
assert (a == b).all()
|
||||
|
||||
one = Rational(1)
|
||||
zero = Rational(0)
|
||||
X = list2numpy([one, zero, zero])
|
||||
Y = one*X
|
||||
X = list2numpy([Symbol("a") + Rational(1, 2)])
|
||||
Y = X + X
|
||||
assert Y == array([1 + 2*Symbol("a")])
|
||||
Y = Y + 1
|
||||
assert Y == array([2 + 2*Symbol("a")])
|
||||
Y = X - X
|
||||
assert Y == array([0])
|
||||
|
||||
|
||||
def test_list2numpy():
|
||||
assert (array([x**2, x]) == list2numpy([x**2, x])).all()
|
||||
|
||||
|
||||
def test_Matrix1():
|
||||
m = Matrix([[x, x**2], [5, 2/x]])
|
||||
assert (array(m.subs(x, 2)) == array([[2, 4], [5, 1]])).all()
|
||||
m = Matrix([[sin(x), x**2], [5, 2/x]])
|
||||
assert (array(m.subs(x, 2)) == array([[sin(2), 4], [5, 1]])).all()
|
||||
|
||||
|
||||
def test_Matrix2():
|
||||
m = Matrix([[x, x**2], [5, 2/x]])
|
||||
with ignore_warnings(PendingDeprecationWarning):
|
||||
assert (matrix(m.subs(x, 2)) == matrix([[2, 4], [5, 1]])).all()
|
||||
m = Matrix([[sin(x), x**2], [5, 2/x]])
|
||||
with ignore_warnings(PendingDeprecationWarning):
|
||||
assert (matrix(m.subs(x, 2)) == matrix([[sin(2), 4], [5, 1]])).all()
|
||||
|
||||
|
||||
def test_Matrix3():
|
||||
a = array([[2, 4], [5, 1]])
|
||||
assert Matrix(a) == Matrix([[2, 4], [5, 1]])
|
||||
assert Matrix(a) != Matrix([[2, 4], [5, 2]])
|
||||
a = array([[sin(2), 4], [5, 1]])
|
||||
assert Matrix(a) == Matrix([[sin(2), 4], [5, 1]])
|
||||
assert Matrix(a) != Matrix([[sin(0), 4], [5, 1]])
|
||||
|
||||
|
||||
def test_Matrix4():
|
||||
with ignore_warnings(PendingDeprecationWarning):
|
||||
a = matrix([[2, 4], [5, 1]])
|
||||
assert Matrix(a) == Matrix([[2, 4], [5, 1]])
|
||||
assert Matrix(a) != Matrix([[2, 4], [5, 2]])
|
||||
with ignore_warnings(PendingDeprecationWarning):
|
||||
a = matrix([[sin(2), 4], [5, 1]])
|
||||
assert Matrix(a) == Matrix([[sin(2), 4], [5, 1]])
|
||||
assert Matrix(a) != Matrix([[sin(0), 4], [5, 1]])
|
||||
|
||||
|
||||
def test_Matrix_sum():
|
||||
M = Matrix([[1, 2, 3], [x, y, x], [2*y, -50, z*x]])
|
||||
with ignore_warnings(PendingDeprecationWarning):
|
||||
m = matrix([[2, 3, 4], [x, 5, 6], [x, y, z**2]])
|
||||
assert M + m == Matrix([[3, 5, 7], [2*x, y + 5, x + 6], [2*y + x, y - 50, z*x + z**2]])
|
||||
assert m + M == Matrix([[3, 5, 7], [2*x, y + 5, x + 6], [2*y + x, y - 50, z*x + z**2]])
|
||||
assert M + m == M.add(m)
|
||||
|
||||
|
||||
def test_Matrix_mul():
|
||||
M = Matrix([[1, 2, 3], [x, y, x]])
|
||||
with ignore_warnings(PendingDeprecationWarning):
|
||||
m = matrix([[2, 4], [x, 6], [x, z**2]])
|
||||
assert M*m == Matrix([
|
||||
[ 2 + 5*x, 16 + 3*z**2],
|
||||
[2*x + x*y + x**2, 4*x + 6*y + x*z**2],
|
||||
])
|
||||
|
||||
assert m*M == Matrix([
|
||||
[ 2 + 4*x, 4 + 4*y, 6 + 4*x],
|
||||
[ 7*x, 2*x + 6*y, 9*x],
|
||||
[x + x*z**2, 2*x + y*z**2, 3*x + x*z**2],
|
||||
])
|
||||
a = array([2])
|
||||
assert a[0] * M == 2 * M
|
||||
assert M * a[0] == 2 * M
|
||||
|
||||
|
||||
def test_Matrix_array():
|
||||
class matarray:
|
||||
def __array__(self, dtype=object, copy=None):
|
||||
if copy is not None and not copy:
|
||||
raise TypeError("Cannot implement copy=False when converting Matrix to ndarray")
|
||||
from numpy import array
|
||||
return array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
||||
matarr = matarray()
|
||||
assert Matrix(matarr) == Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
||||
|
||||
|
||||
def test_matrix2numpy():
|
||||
a = matrix2numpy(Matrix([[1, x**2], [3*sin(x), 0]]))
|
||||
assert isinstance(a, ndarray)
|
||||
assert a.shape == (2, 2)
|
||||
assert a[0, 0] == 1
|
||||
assert a[0, 1] == x**2
|
||||
assert a[1, 0] == 3*sin(x)
|
||||
assert a[1, 1] == 0
|
||||
|
||||
|
||||
def test_matrix2numpy_conversion():
|
||||
a = Matrix([[1, 2, sin(x)], [x**2, x, Rational(1, 2)]])
|
||||
b = array([[1, 2, sin(x)], [x**2, x, Rational(1, 2)]])
|
||||
assert (matrix2numpy(a) == b).all()
|
||||
assert matrix2numpy(a).dtype == numpy.dtype('object')
|
||||
|
||||
c = matrix2numpy(Matrix([[1, 2], [10, 20]]), dtype='int8')
|
||||
d = matrix2numpy(Matrix([[1, 2], [10, 20]]), dtype='float64')
|
||||
assert c.dtype == numpy.dtype('int8')
|
||||
assert d.dtype == numpy.dtype('float64')
|
||||
|
||||
|
||||
def test_issue_3728():
|
||||
assert (Rational(1, 2)*array([2*x, 0]) == array([x, 0])).all()
|
||||
assert (Rational(1, 2) + array(
|
||||
[2*x, 0]) == array([2*x + Rational(1, 2), Rational(1, 2)])).all()
|
||||
assert (Float("0.5")*array([2*x, 0]) == array([Float("1.0")*x, 0])).all()
|
||||
assert (Float("0.5") + array(
|
||||
[2*x, 0]) == array([2*x + Float("0.5"), Float("0.5")])).all()
|
||||
|
||||
|
||||
@conserve_mpmath_dps
|
||||
def test_lambdify():
|
||||
mpmath.mp.dps = 16
|
||||
sin02 = mpmath.mpf("0.198669330795061215459412627")
|
||||
f = lambdify(x, sin(x), "numpy")
|
||||
prec = 1e-15
|
||||
assert -prec < f(0.2) - sin02 < prec
|
||||
|
||||
# if this succeeds, it can't be a numpy function
|
||||
|
||||
if version_tuple(numpy.__version__) >= version_tuple('1.17'):
|
||||
with raises(TypeError):
|
||||
f(x)
|
||||
else:
|
||||
with raises(AttributeError):
|
||||
f(x)
|
||||
|
||||
|
||||
def test_lambdify_matrix():
|
||||
f = lambdify(x, Matrix([[x, 2*x], [1, 2]]), [{'ImmutableMatrix': numpy.array}, "numpy"])
|
||||
assert (f(1) == array([[1, 2], [1, 2]])).all()
|
||||
|
||||
|
||||
def test_lambdify_matrix_multi_input():
|
||||
M = sympy.Matrix([[x**2, x*y, x*z],
|
||||
[y*x, y**2, y*z],
|
||||
[z*x, z*y, z**2]])
|
||||
f = lambdify((x, y, z), M, [{'ImmutableMatrix': numpy.array}, "numpy"])
|
||||
|
||||
xh, yh, zh = 1.0, 2.0, 3.0
|
||||
expected = array([[xh**2, xh*yh, xh*zh],
|
||||
[yh*xh, yh**2, yh*zh],
|
||||
[zh*xh, zh*yh, zh**2]])
|
||||
actual = f(xh, yh, zh)
|
||||
assert numpy.allclose(actual, expected)
|
||||
|
||||
|
||||
def test_lambdify_matrix_vec_input():
|
||||
X = sympy.DeferredVector('X')
|
||||
M = Matrix([
|
||||
[X[0]**2, X[0]*X[1], X[0]*X[2]],
|
||||
[X[1]*X[0], X[1]**2, X[1]*X[2]],
|
||||
[X[2]*X[0], X[2]*X[1], X[2]**2]])
|
||||
f = lambdify(X, M, [{'ImmutableMatrix': numpy.array}, "numpy"])
|
||||
|
||||
Xh = array([1.0, 2.0, 3.0])
|
||||
expected = array([[Xh[0]**2, Xh[0]*Xh[1], Xh[0]*Xh[2]],
|
||||
[Xh[1]*Xh[0], Xh[1]**2, Xh[1]*Xh[2]],
|
||||
[Xh[2]*Xh[0], Xh[2]*Xh[1], Xh[2]**2]])
|
||||
actual = f(Xh)
|
||||
assert numpy.allclose(actual, expected)
|
||||
|
||||
|
||||
def test_lambdify_transl():
|
||||
from sympy.utilities.lambdify import NUMPY_TRANSLATIONS
|
||||
for sym, mat in NUMPY_TRANSLATIONS.items():
|
||||
assert sym in sympy.__dict__
|
||||
assert mat in numpy.__dict__
|
||||
|
||||
|
||||
def test_symarray():
|
||||
"""Test creation of numpy arrays of SymPy symbols."""
|
||||
|
||||
import numpy as np
|
||||
import numpy.testing as npt
|
||||
|
||||
syms = symbols('_0,_1,_2')
|
||||
s1 = symarray("", 3)
|
||||
s2 = symarray("", 3)
|
||||
npt.assert_array_equal(s1, np.array(syms, dtype=object))
|
||||
assert s1[0] == s2[0]
|
||||
|
||||
a = symarray('a', 3)
|
||||
b = symarray('b', 3)
|
||||
assert not(a[0] == b[0])
|
||||
|
||||
asyms = symbols('a_0,a_1,a_2')
|
||||
npt.assert_array_equal(a, np.array(asyms, dtype=object))
|
||||
|
||||
# Multidimensional checks
|
||||
a2d = symarray('a', (2, 3))
|
||||
assert a2d.shape == (2, 3)
|
||||
a00, a12 = symbols('a_0_0,a_1_2')
|
||||
assert a2d[0, 0] == a00
|
||||
assert a2d[1, 2] == a12
|
||||
|
||||
a3d = symarray('a', (2, 3, 2))
|
||||
assert a3d.shape == (2, 3, 2)
|
||||
a000, a120, a121 = symbols('a_0_0_0,a_1_2_0,a_1_2_1')
|
||||
assert a3d[0, 0, 0] == a000
|
||||
assert a3d[1, 2, 0] == a120
|
||||
assert a3d[1, 2, 1] == a121
|
||||
|
||||
|
||||
def test_vectorize():
|
||||
assert (numpy.vectorize(
|
||||
sin)([1, 2, 3]) == numpy.array([sin(1), sin(2), sin(3)])).all()
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
"""
|
||||
test_pythonmpq.py
|
||||
|
||||
Test the PythonMPQ class for consistency with gmpy2's mpq type. If gmpy2 is
|
||||
installed run the same tests for both.
|
||||
"""
|
||||
from fractions import Fraction
|
||||
from decimal import Decimal
|
||||
import pickle
|
||||
from typing import Callable, List, Tuple, Type
|
||||
|
||||
from sympy.testing.pytest import raises
|
||||
|
||||
from sympy.external.pythonmpq import PythonMPQ
|
||||
|
||||
#
|
||||
# If gmpy2 is installed then run the tests for both mpq and PythonMPQ.
|
||||
# That should ensure consistency between the implementation here and mpq.
|
||||
#
|
||||
rational_types: List[Tuple[Callable, Type, Callable, Type]]
|
||||
rational_types = [(PythonMPQ, PythonMPQ, int, int)]
|
||||
try:
|
||||
from gmpy2 import mpq, mpz
|
||||
rational_types.append((mpq, type(mpq(1)), mpz, type(mpz(1))))
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
def test_PythonMPQ():
|
||||
#
|
||||
# Test PythonMPQ and also mpq if gmpy/gmpy2 is installed.
|
||||
#
|
||||
for Q, TQ, Z, TZ in rational_types:
|
||||
|
||||
def check_Q(q):
|
||||
assert isinstance(q, TQ)
|
||||
assert isinstance(q.numerator, TZ)
|
||||
assert isinstance(q.denominator, TZ)
|
||||
return q.numerator, q.denominator
|
||||
|
||||
# Check construction from different types
|
||||
assert check_Q(Q(3)) == (3, 1)
|
||||
assert check_Q(Q(3, 5)) == (3, 5)
|
||||
assert check_Q(Q(Q(3, 5))) == (3, 5)
|
||||
assert check_Q(Q(0.5)) == (1, 2)
|
||||
assert check_Q(Q('0.5')) == (1, 2)
|
||||
assert check_Q(Q(Fraction(3, 5))) == (3, 5)
|
||||
|
||||
# https://github.com/aleaxit/gmpy/issues/327
|
||||
if Q is PythonMPQ:
|
||||
assert check_Q(Q(Decimal('0.6'))) == (3, 5)
|
||||
|
||||
# Invalid types
|
||||
raises(TypeError, lambda: Q([]))
|
||||
raises(TypeError, lambda: Q([], []))
|
||||
|
||||
# Check normalisation of signs
|
||||
assert check_Q(Q(2, 3)) == (2, 3)
|
||||
assert check_Q(Q(-2, 3)) == (-2, 3)
|
||||
assert check_Q(Q(2, -3)) == (-2, 3)
|
||||
assert check_Q(Q(-2, -3)) == (2, 3)
|
||||
|
||||
# Check gcd calculation
|
||||
assert check_Q(Q(12, 8)) == (3, 2)
|
||||
|
||||
# __int__/__float__
|
||||
assert int(Q(5, 3)) == 1
|
||||
assert int(Q(-5, 3)) == -1
|
||||
assert float(Q(5, 2)) == 2.5
|
||||
assert float(Q(-5, 2)) == -2.5
|
||||
|
||||
# __str__/__repr__
|
||||
assert str(Q(2, 1)) == "2"
|
||||
assert str(Q(1, 2)) == "1/2"
|
||||
if Q is PythonMPQ:
|
||||
assert repr(Q(2, 1)) == "MPQ(2,1)"
|
||||
assert repr(Q(1, 2)) == "MPQ(1,2)"
|
||||
else:
|
||||
assert repr(Q(2, 1)) == "mpq(2,1)"
|
||||
assert repr(Q(1, 2)) == "mpq(1,2)"
|
||||
|
||||
# __bool__
|
||||
assert bool(Q(1, 2)) is True
|
||||
assert bool(Q(0)) is False
|
||||
|
||||
# __eq__/__ne__
|
||||
assert (Q(2, 3) == Q(2, 3)) is True
|
||||
assert (Q(2, 3) == Q(2, 5)) is False
|
||||
assert (Q(2, 3) != Q(2, 3)) is False
|
||||
assert (Q(2, 3) != Q(2, 5)) is True
|
||||
|
||||
# __hash__
|
||||
assert hash(Q(3, 5)) == hash(Fraction(3, 5))
|
||||
|
||||
# __reduce__
|
||||
q = Q(2, 3)
|
||||
assert pickle.loads(pickle.dumps(q)) == q
|
||||
|
||||
# __ge__/__gt__/__le__/__lt__
|
||||
assert (Q(1, 3) < Q(2, 3)) is True
|
||||
assert (Q(2, 3) < Q(2, 3)) is False
|
||||
assert (Q(2, 3) < Q(1, 3)) is False
|
||||
assert (Q(-2, 3) < Q(1, 3)) is True
|
||||
assert (Q(1, 3) < Q(-2, 3)) is False
|
||||
|
||||
assert (Q(1, 3) <= Q(2, 3)) is True
|
||||
assert (Q(2, 3) <= Q(2, 3)) is True
|
||||
assert (Q(2, 3) <= Q(1, 3)) is False
|
||||
assert (Q(-2, 3) <= Q(1, 3)) is True
|
||||
assert (Q(1, 3) <= Q(-2, 3)) is False
|
||||
|
||||
assert (Q(1, 3) > Q(2, 3)) is False
|
||||
assert (Q(2, 3) > Q(2, 3)) is False
|
||||
assert (Q(2, 3) > Q(1, 3)) is True
|
||||
assert (Q(-2, 3) > Q(1, 3)) is False
|
||||
assert (Q(1, 3) > Q(-2, 3)) is True
|
||||
|
||||
assert (Q(1, 3) >= Q(2, 3)) is False
|
||||
assert (Q(2, 3) >= Q(2, 3)) is True
|
||||
assert (Q(2, 3) >= Q(1, 3)) is True
|
||||
assert (Q(-2, 3) >= Q(1, 3)) is False
|
||||
assert (Q(1, 3) >= Q(-2, 3)) is True
|
||||
|
||||
# __abs__/__pos__/__neg__
|
||||
assert abs(Q(2, 3)) == abs(Q(-2, 3)) == Q(2, 3)
|
||||
assert +Q(2, 3) == Q(2, 3)
|
||||
assert -Q(2, 3) == Q(-2, 3)
|
||||
|
||||
# __add__/__radd__
|
||||
assert Q(2, 3) + Q(5, 7) == Q(29, 21)
|
||||
assert Q(2, 3) + 1 == Q(5, 3)
|
||||
assert 1 + Q(2, 3) == Q(5, 3)
|
||||
raises(TypeError, lambda: [] + Q(1))
|
||||
raises(TypeError, lambda: Q(1) + [])
|
||||
|
||||
# __sub__/__rsub__
|
||||
assert Q(2, 3) - Q(5, 7) == Q(-1, 21)
|
||||
assert Q(2, 3) - 1 == Q(-1, 3)
|
||||
assert 1 - Q(2, 3) == Q(1, 3)
|
||||
raises(TypeError, lambda: [] - Q(1))
|
||||
raises(TypeError, lambda: Q(1) - [])
|
||||
|
||||
# __mul__/__rmul__
|
||||
assert Q(2, 3) * Q(5, 7) == Q(10, 21)
|
||||
assert Q(2, 3) * 1 == Q(2, 3)
|
||||
assert 1 * Q(2, 3) == Q(2, 3)
|
||||
raises(TypeError, lambda: [] * Q(1))
|
||||
raises(TypeError, lambda: Q(1) * [])
|
||||
|
||||
# __pow__/__rpow__
|
||||
assert Q(2, 3) ** 2 == Q(4, 9)
|
||||
assert Q(2, 3) ** 1 == Q(2, 3)
|
||||
assert Q(-2, 3) ** 2 == Q(4, 9)
|
||||
assert Q(-2, 3) ** -1 == Q(-3, 2)
|
||||
if Q is PythonMPQ:
|
||||
raises(TypeError, lambda: 1 ** Q(2, 3))
|
||||
raises(TypeError, lambda: Q(1, 4) ** Q(1, 2))
|
||||
raises(TypeError, lambda: [] ** Q(1))
|
||||
raises(TypeError, lambda: Q(1) ** [])
|
||||
|
||||
# __div__/__rdiv__
|
||||
assert Q(2, 3) / Q(5, 7) == Q(14, 15)
|
||||
assert Q(2, 3) / 1 == Q(2, 3)
|
||||
assert 1 / Q(2, 3) == Q(3, 2)
|
||||
raises(TypeError, lambda: [] / Q(1))
|
||||
raises(TypeError, lambda: Q(1) / [])
|
||||
raises(ZeroDivisionError, lambda: Q(1, 2) / Q(0))
|
||||
|
||||
# __divmod__
|
||||
if Q is PythonMPQ:
|
||||
raises(TypeError, lambda: Q(2, 3) // Q(1, 3))
|
||||
raises(TypeError, lambda: Q(2, 3) % Q(1, 3))
|
||||
raises(TypeError, lambda: 1 // Q(1, 3))
|
||||
raises(TypeError, lambda: 1 % Q(1, 3))
|
||||
raises(TypeError, lambda: Q(2, 3) // 1)
|
||||
raises(TypeError, lambda: Q(2, 3) % 1)
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
# This testfile tests SymPy <-> SciPy compatibility
|
||||
|
||||
# Don't test any SymPy features here. Just pure interaction with SciPy.
|
||||
# Always write regular SymPy tests for anything, that can be tested in pure
|
||||
# Python (without scipy). Here we test everything, that a user may need when
|
||||
# using SymPy with SciPy
|
||||
|
||||
from sympy.external import import_module
|
||||
|
||||
scipy = import_module('scipy')
|
||||
if not scipy:
|
||||
#bin/test will not execute any tests now
|
||||
disabled = True
|
||||
|
||||
from sympy.functions.special.bessel import jn_zeros
|
||||
|
||||
|
||||
def eq(a, b, tol=1e-6):
|
||||
for x, y in zip(a, b):
|
||||
if not (abs(x - y) < tol):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def test_jn_zeros():
|
||||
assert eq(jn_zeros(0, 4, method="scipy"),
|
||||
[3.141592, 6.283185, 9.424777, 12.566370])
|
||||
assert eq(jn_zeros(1, 4, method="scipy"),
|
||||
[4.493409, 7.725251, 10.904121, 14.066193])
|
||||
assert eq(jn_zeros(2, 4, method="scipy"),
|
||||
[5.763459, 9.095011, 12.322940, 15.514603])
|
||||
assert eq(jn_zeros(3, 4, method="scipy"),
|
||||
[6.987932, 10.417118, 13.698023, 16.923621])
|
||||
assert eq(jn_zeros(4, 4, method="scipy"),
|
||||
[8.182561, 11.704907, 15.039664, 18.301255])
|
||||
Reference in New Issue
Block a user