From 0e3ee07512cadb52627842af17de9847d87930f0 Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 21 Jan 2019 17:58:08 -0600 Subject: [PATCH 01/11] Add Pymbolic CI job --- .gitlab-ci.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ef10883..71bf42d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -67,6 +67,17 @@ Python 3.5 Apple: reports: junit: test/pytest.xml +Pylint: + script: + - EXTRA_INSTALL="numpy sympy pexpect" + - py_version=3.6 + - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/prepare-and-run-pylint.sh + - ". ./prepare-and-run-pylint.sh pymbolic test/test_*.py" + tags: + - python3.6 + except: + - tags + Documentation: script: - EXTRA_INSTALL="numpy" -- GitLab From e8adef04b654cdb912a12d5b699a24960fd959dc Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 21 Jan 2019 18:50:34 -0600 Subject: [PATCH 02/11] Round 1 of changes --- pymbolic/geometric_algebra/mapper.py | 9 ++++++- pymbolic/imperative/transform.py | 2 +- pymbolic/interop/ast.py | 6 ++++- pymbolic/interop/common.py | 7 +++++ pymbolic/interop/sympy.py | 2 +- pymbolic/mapper/__init__.py | 21 +++++++++++++++ pymbolic/mapper/constant_folder.py | 2 +- pymbolic/mapper/differentiator.py | 2 +- pymbolic/mapper/unifier.py | 3 +++ pymbolic/parser.py | 2 +- pymbolic/polynomial.py | 40 +++++++++++----------------- pymbolic/primitives.py | 16 +++++++++-- 12 files changed, 78 insertions(+), 34 deletions(-) diff --git a/pymbolic/geometric_algebra/mapper.py b/pymbolic/geometric_algebra/mapper.py index 448d408..5ee9326 100644 --- a/pymbolic/geometric_algebra/mapper.py +++ b/pymbolic/geometric_algebra/mapper.py @@ -145,11 +145,15 @@ class Dimensionalizer(EvaluationMapper): Dimension of ambient space. Must be provided by subclass. """ + @property + def ambient_dim(self): + raise NotImplementedError + def map_multivector_variable(self, expr): from pymbolic.primitives import make_sym_vector return MultiVector( make_sym_vector(expr.name, self.ambient_dim, - var_class=type(expr))) + var_factory=type(expr))) def map_nabla(self, expr): from pytools.obj_array import make_obj_array @@ -232,6 +236,9 @@ class DerivativeBinder(IdentityMapper): self.derivative_source_and_nabla_component_collector() self.restrict_to_id = restrict_to_id + def take_derivative(self, ambient_axis, expr): + raise NotImplementedError + def map_product(self, expr): # {{{ gather NablaComponents and DerivativeSources diff --git a/pymbolic/imperative/transform.py b/pymbolic/imperative/transform.py index b324bab..6f4c08d 100644 --- a/pymbolic/imperative/transform.py +++ b/pymbolic/imperative/transform.py @@ -67,7 +67,7 @@ def fuse_instruction_streams_with_unique_ids(insns_a, insns_b): def disambiguate_identifiers(statements_a, statements_b, should_disambiguate_name=None): if should_disambiguate_name is None: - def should_disambiguate_name(name): + def should_disambiguate_name(name): # pylint:disable=function-redefined return True from pymbolic.imperative.analysis import get_all_used_identifiers diff --git a/pymbolic/interop/ast.py b/pymbolic/interop/ast.py index 6a826f1..d7787b8 100644 --- a/pymbolic/interop/ast.py +++ b/pymbolic/interop/ast.py @@ -91,12 +91,15 @@ class ASTMapper(object): # {{{ mapper class ASTToPymbolic(ASTMapper): + @staticmethod def _add(x, y): # noqa return p.Sum((x, y)) + @staticmethod def _sub(x, y): # noqa return p.Sum((x, p.Product(((-1), y)))) + @staticmethod def _mult(x, y): # noqa return p.Product((x, y)) @@ -127,8 +130,9 @@ class ASTToPymbolic(ASTMapper): return op_constructor(self.rec(expr.left), self.rec(expr.right)) + @staticmethod def _neg(x): # noqa - return p.Product((-1), x) + return p.Product((-1, x),) unary_op_map = { ast.Invert: _neg, diff --git a/pymbolic/interop/common.py b/pymbolic/interop/common.py index d8b75f5..23ea2ea 100644 --- a/pymbolic/interop/common.py +++ b/pymbolic/interop/common.py @@ -130,6 +130,13 @@ class SympyLikeToPymbolicMapper(SympyLikeMapperBase): class PymbolicToSympyLikeMapper(EvaluationMapper): + @property + def sym(self): + raise NotImplementedError + + def raise_conversion_error(self, message): + raise NotImplementedError + def map_variable(self, expr): return self.sym.Symbol(expr.name) diff --git a/pymbolic/interop/sympy.py b/pymbolic/interop/sympy.py index 1e31ead..76ef76c 100644 --- a/pymbolic/interop/sympy.py +++ b/pymbolic/interop/sympy.py @@ -61,7 +61,7 @@ class SympyToPymbolicMapper(SympyLikeToPymbolicMapper): # only called for Py2 def map_long(self, expr): - return long(expr) # noqa + return long(expr) # noqa pylint:disable=undefined-variable def map_Indexed(self, expr): # noqa return prim.Subscript( diff --git a/pymbolic/mapper/__init__.py b/pymbolic/mapper/__init__.py index a280d51..3ed5240 100644 --- a/pymbolic/mapper/__init__.py +++ b/pymbolic/mapper/__init__.py @@ -135,6 +135,9 @@ class Mapper(object): rec = __call__ + def map_algebraic_leaf(self, expr, *args, **kwargs): + raise NotImplementedError + def map_variable(self, expr, *args, **kwargs): return self.map_algebraic_leaf(expr, *args, **kwargs) @@ -153,6 +156,21 @@ class Mapper(object): def map_rational(self, expr, *args, **kwargs): return self.map_quotient(expr, *args, **kwargs) + def map_quotient(self, expr, *args, **kwargs): + raise NotImplementedError + + def map_constant(self, expr, *args, **kwargs): + raise NotImplementedError + + def map_list(self, expr, *args, **kwargs): + raise NotImplementedError + + def map_tuple(self, expr, *args, **kwargs): + raise NotImplementedError + + def map_numpy_array(self, expr, *args, **kwargs): + raise NotImplementedError + def map_foreign(self, expr, *args, **kwargs): """Mapper method dispatch for non-:mod:`pymbolic` objects.""" @@ -195,6 +213,9 @@ class CombineMapper(RecursiveMapper): :class:`pymbolic.mapper.dependency.DependencyMapper` is another example. """ + def combine(self, values): + raise NotImplementedError + def map_call(self, expr, *args, **kwargs): return self.combine( (self.rec(expr.function, *args, **kwargs),) diff --git a/pymbolic/mapper/constant_folder.py b/pymbolic/mapper/constant_folder.py index b642fa6..f40e4ad 100644 --- a/pymbolic/mapper/constant_folder.py +++ b/pymbolic/mapper/constant_folder.py @@ -47,7 +47,7 @@ class ConstantFoldingMapperBase(object): queue = list(expr.children) while queue: - child = self.rec(queue.pop(0)) + child = self.rec(queue.pop(0)) # pylint:disable=no-member if isinstance(child, klass): queue = list(child.children) + queue else: diff --git a/pymbolic/mapper/differentiator.py b/pymbolic/mapper/differentiator.py index 86ac2f9..b6ec695 100644 --- a/pymbolic/mapper/differentiator.py +++ b/pymbolic/mapper/differentiator.py @@ -174,7 +174,7 @@ class DifferentiationMapper(pymbolic.mapper.RecursiveMapper): return ( Polynomial(self.rec_undiff(expr.base, *args), - tuple(deriv_coeff), expr.unit) + + tuple(deriv_coeff), expr.unit) + Polynomial(self.rec_undiff(expr.base, *args), tuple(deriv_base), expr.unit)) diff --git a/pymbolic/mapper/unifier.py b/pymbolic/mapper/unifier.py index aa1f825..4ac8f2c 100644 --- a/pymbolic/mapper/unifier.py +++ b/pymbolic/mapper/unifier.py @@ -119,6 +119,9 @@ class UnifierBase(RecursiveMapper): self.rhs_mapping_candidates = rhs_mapping_candidates self.force_var_match = force_var_match + def treat_mismatch(self, expr, other, urecs): + raise NotImplementedError + def unification_record_from_equation(self, lhs, rhs): if isinstance(lhs, (tuple, list)) or isinstance(rhs, (tuple, list)): # Always force lists/tuples to agree elementwise, never diff --git a/pymbolic/parser.py b/pymbolic/parser.py index 00ef94a..8f199b3 100644 --- a/pymbolic/parser.py +++ b/pymbolic/parser.py @@ -212,7 +212,7 @@ class Parser(object): left_exp = self.parse_expression(pstate, _PREC_UNARY) elif pstate.is_next(_minus): pstate.advance() - left_exp = -self.parse_expression(pstate, _PREC_UNARY) + left_exp = -self.parse_expression(pstate, _PREC_UNARY) # noqa pylint:disable=invalid-unary-operand-type elif pstate.is_next(_not): pstate.advance() from pymbolic.primitives import LogicalNot diff --git a/pymbolic/polynomial.py b/pymbolic/polynomial.py index ad878fd..bcb04e2 100644 --- a/pymbolic/polynomial.py +++ b/pymbolic/polynomial.py @@ -56,6 +56,13 @@ def _sort_uniq(data): +def _get_dependencies(expr): + from pymbolic.mapper.dependency import DependencyMapper + return DependencyMapper()(expr) + + + + class LexicalMonomialOrder: def __call__(self, a, b): from pymbolic.primitives import Variable @@ -70,9 +77,6 @@ class LexicalMonomialOrder: return "LexicalMonomialOrder()" - - - class Polynomial(Expression): def __init__(self, base, data=None, unit=1, var_less=LexicalMonomialOrder()): self.Base = base @@ -218,7 +222,7 @@ class Polynomial(Expression): return quot * self, rem * self if other.degree == -1: - raise DivisionByZeroError + raise ZeroDivisionError quot = Polynomial(self.Base, ()) rem = self @@ -252,11 +256,11 @@ class Polynomial(Expression): __truediv__ = __div__ - def __floordiv__(self): - return self.__divmod__(self, other)[0] + def __floordiv__(self, other): + return self.__divmod__(other)[0] - def __mod__(self): - return self.__divmod__(self, other)[1] + def __mod__(self, other): + return self.__divmod__(other)[1] def _data(self): return self.Data @@ -283,7 +287,7 @@ class Polynomial(Expression): mapper_method = intern("map_polynomial") def as_primitives(self): - deps = pymbolic.get_dependencies(self) + deps = _get_dependencies(self) context = dict((dep, dep) for dep in deps) return pymbolic.evaluate(self, context) @@ -297,21 +301,6 @@ class Polynomial(Expression): -def from_primitives(expr, var_order): - from pymbolic import get_dependencies, evaluate - - deps = get_dependencies(expr) - var_deps = [dep for dep in deps if dep in var_order] - context = dict((vd, Polynomial(vd, var_order=var_order)) - for vd in var_deps) - - # FIXME not fast, but works - # (and exercises multivariate polynomial code) - return evaluate(expr, context) - - - - def differentiate(poly): return Polynomial( poly.base, @@ -335,7 +324,8 @@ def integrate_definite(poly, a, b): a_bound = pymbolic.substitute(antideriv, {poly.base: a}) b_bound = pymbolic.substitute(antideriv, {poly.base: b}) - return pymbolic.sum((b_bound, -a_bound)) + from pymbolic.primitives import Sum + return Sum((b_bound, -a_bound)) diff --git a/pymbolic/primitives.py b/pymbolic/primitives.py index d18c1c6..d6198e3 100644 --- a/pymbolic/primitives.py +++ b/pymbolic/primitives.py @@ -216,6 +216,14 @@ class Expression(object): .. automethod:: ge """ + # {{{ init arg names (override by subclass) + + @property + def init_arg_names(self): + raise NotImplementedError + + # }}} + # {{{ arithmetic def __add__(self, other): @@ -516,6 +524,9 @@ class Expression(object): self.hash_value = self.get_hash() return self.hash_value + def __getinitargs__(self): + raise NotImplementedError + def __getstate__(self): return self.__getinitargs__() @@ -1297,8 +1308,9 @@ class Vector(Expression): return Vector(tuple(other*x for x in self)) def __div__(self, other): + # Py2 only import operator - return Vector(tuple(operator.div(x, other) for x in self)) + return Vector(tuple(operator.div(x, other) for x in self)) # pylint: disable=no-member def __truediv__(self, other): import operator @@ -1557,7 +1569,7 @@ global VALID_CONSTANT_CLASSES global VALID_OPERANDS VALID_CONSTANT_CLASSES = (int, float, complex) if six.PY2: - VALID_CONSTANT_CLASSES += (long,) # noqa + VALID_CONSTANT_CLASSES += (long,) # noqa pylint:disable=undefined-variable VALID_OPERANDS = (Expression,) -- GitLab From 69fccd5732d4e715a6c82d58d49edce07ffccdbf Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 21 Jan 2019 18:54:32 -0600 Subject: [PATCH 03/11] Fix binding of staticmethods --- pymbolic/interop/ast.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pymbolic/interop/ast.py b/pymbolic/interop/ast.py index d7787b8..3b6d4fd 100644 --- a/pymbolic/interop/ast.py +++ b/pymbolic/interop/ast.py @@ -104,9 +104,9 @@ class ASTToPymbolic(ASTMapper): return p.Product((x, y)) bin_op_map = { - ast.Add: _add, - ast.Sub: _sub, - ast.Mult: _mult, + ast.Add: ASTToPymbolic._add, + ast.Sub: ASTToPymbolic._sub, + ast.Mult: ASTToPymbolic._mult, # MatMult ast.Div: p.Quotient, ast.FloorDiv: p.FloorDiv, @@ -135,10 +135,10 @@ class ASTToPymbolic(ASTMapper): return p.Product((-1, x),) unary_op_map = { - ast.Invert: _neg, + ast.Invert: ASTToPymbolic._neg, ast.Not: p.LogicalNot, # ast.UAdd: - ast.USub: _neg, + ast.USub: ASTToPymbolic._neg, } def map_UnaryOp(self, expr): # noqa -- GitLab From 5523ccb0bde2208cb2c28d8a8d96b8f7bedb7a13 Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 21 Jan 2019 18:56:47 -0600 Subject: [PATCH 04/11] Revert "Fix binding of staticmethods" This reverts commit 69fccd5732d4e715a6c82d58d49edce07ffccdbf. --- pymbolic/interop/ast.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pymbolic/interop/ast.py b/pymbolic/interop/ast.py index 3b6d4fd..d7787b8 100644 --- a/pymbolic/interop/ast.py +++ b/pymbolic/interop/ast.py @@ -104,9 +104,9 @@ class ASTToPymbolic(ASTMapper): return p.Product((x, y)) bin_op_map = { - ast.Add: ASTToPymbolic._add, - ast.Sub: ASTToPymbolic._sub, - ast.Mult: ASTToPymbolic._mult, + ast.Add: _add, + ast.Sub: _sub, + ast.Mult: _mult, # MatMult ast.Div: p.Quotient, ast.FloorDiv: p.FloorDiv, @@ -135,10 +135,10 @@ class ASTToPymbolic(ASTMapper): return p.Product((-1, x),) unary_op_map = { - ast.Invert: ASTToPymbolic._neg, + ast.Invert: _neg, ast.Not: p.LogicalNot, # ast.UAdd: - ast.USub: ASTToPymbolic._neg, + ast.USub: _neg, } def map_UnaryOp(self, expr): # noqa -- GitLab From 8513911ad0f6214549792f326a2ecac9a5a3058d Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 21 Jan 2019 19:12:32 -0600 Subject: [PATCH 05/11] Move functions outside class --- pymbolic/interop/ast.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/pymbolic/interop/ast.py b/pymbolic/interop/ast.py index d7787b8..3b871ff 100644 --- a/pymbolic/interop/ast.py +++ b/pymbolic/interop/ast.py @@ -90,18 +90,23 @@ class ASTMapper(object): # {{{ mapper -class ASTToPymbolic(ASTMapper): - @staticmethod - def _add(x, y): # noqa - return p.Sum((x, y)) +def _add(x, y): + return p.Sum((x, y)) + + +def _sub(x, y): + return p.Sum((x, p.Product(((-1), y)))) + + +def _mult(x, y): + return p.Product((x, y)) - @staticmethod - def _sub(x, y): # noqa - return p.Sum((x, p.Product(((-1), y)))) - @staticmethod - def _mult(x, y): # noqa - return p.Product((x, y)) +def _neg(x): + return p.Product((-1, x),) + + +class ASTToPymbolic(ASTMapper): bin_op_map = { ast.Add: _add, @@ -130,10 +135,6 @@ class ASTToPymbolic(ASTMapper): return op_constructor(self.rec(expr.left), self.rec(expr.right)) - @staticmethod - def _neg(x): # noqa - return p.Product((-1, x),) - unary_op_map = { ast.Invert: _neg, ast.Not: p.LogicalNot, -- GitLab From 430ca7ebf9313bd2db9defa8b735b73271d83f91 Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 21 Jan 2019 19:18:27 -0600 Subject: [PATCH 06/11] Flake8 fix --- pymbolic/primitives.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymbolic/primitives.py b/pymbolic/primitives.py index d6198e3..018cbaa 100644 --- a/pymbolic/primitives.py +++ b/pymbolic/primitives.py @@ -1310,7 +1310,7 @@ class Vector(Expression): def __div__(self, other): # Py2 only import operator - return Vector(tuple(operator.div(x, other) for x in self)) # pylint: disable=no-member + return Vector(tuple(operator.div(x, other) for x in self)) # noqa pylint: disable=no-member def __truediv__(self, other): import operator -- GitLab From 0cbc66aaab74add1edfce539b8bdc59f7f41ff3a Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 21 Jan 2019 23:38:52 -0600 Subject: [PATCH 07/11] Address missing numpy types --- pymbolic/mapper/constant_converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pymbolic/mapper/constant_converter.py b/pymbolic/mapper/constant_converter.py index cc7f94e..62e0a45 100644 --- a/pymbolic/mapper/constant_converter.py +++ b/pymbolic/mapper/constant_converter.py @@ -44,8 +44,8 @@ class ConstantToNumpyConversionMapper(pymbolic.mapper.IdentityMapper): complex_type = np.complex64 elif real_type is np.float64: complex_type = np.complex128 - elif real_type is np.float128: - complex_type = np.complex256 + elif real_type is np.float128: # pylint:disable=no-member + complex_type = np.complex256 # pylint:disable-no-member else: raise TypeError( "unable to determine corresponding complex type for '%s'" -- GitLab From a6ed4aa0fa4b3789da7a2f3851320e3a5a830fb3 Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 21 Jan 2019 23:39:42 -0600 Subject: [PATCH 08/11] Add symengine and scipy --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 71bf42d..70b78b9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -69,7 +69,7 @@ Python 3.5 Apple: Pylint: script: - - EXTRA_INSTALL="numpy sympy pexpect" + - EXTRA_INSTALL="numpy sympy symengine scipy pexpect" - py_version=3.6 - curl -L -O -k https://gitlab.tiker.net/inducer/ci-support/raw/master/prepare-and-run-pylint.sh - ". ./prepare-and-run-pylint.sh pymbolic test/test_*.py" -- GitLab From 54d07e0efd46556c68b16b803ff1e593463270b6 Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 21 Jan 2019 23:41:57 -0600 Subject: [PATCH 09/11] Add back missing whitespace --- pymbolic/polynomial.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pymbolic/polynomial.py b/pymbolic/polynomial.py index bcb04e2..a8e53b1 100644 --- a/pymbolic/polynomial.py +++ b/pymbolic/polynomial.py @@ -77,6 +77,9 @@ class LexicalMonomialOrder: return "LexicalMonomialOrder()" + + + class Polynomial(Expression): def __init__(self, base, data=None, unit=1, var_less=LexicalMonomialOrder()): self.Base = base -- GitLab From c04f98edd7c72e22238a64f5d70dd7691f3db47b Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 21 Jan 2019 23:44:08 -0600 Subject: [PATCH 10/11] Fix typo --- pymbolic/mapper/constant_converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymbolic/mapper/constant_converter.py b/pymbolic/mapper/constant_converter.py index 62e0a45..5a8f645 100644 --- a/pymbolic/mapper/constant_converter.py +++ b/pymbolic/mapper/constant_converter.py @@ -45,7 +45,7 @@ class ConstantToNumpyConversionMapper(pymbolic.mapper.IdentityMapper): elif real_type is np.float64: complex_type = np.complex128 elif real_type is np.float128: # pylint:disable=no-member - complex_type = np.complex256 # pylint:disable-no-member + complex_type = np.complex256 # pylint:disable=no-member else: raise TypeError( "unable to determine corresponding complex type for '%s'" -- GitLab From f69d4443904072fa4ad5e04b62875b6feaf9ca72 Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Mon, 21 Jan 2019 23:53:29 -0600 Subject: [PATCH 11/11] Address some pylint limitations --- pymbolic/algorithm.py | 2 +- test/test_pymbolic.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pymbolic/algorithm.py b/pymbolic/algorithm.py index 18cb09e..357fe9b 100644 --- a/pymbolic/algorithm.py +++ b/pymbolic/algorithm.py @@ -227,7 +227,7 @@ def csr_matrix_multiply(S, x): # noqa result = numpy.empty_like(x) for i in range(h): - result[i] = sum(S.data[idx]*x[S.indices[idx]] + result[i] = sum(S.data[idx]*x[S.indices[idx]] # noqa pylint:disable=unsupported-assignment-operation for idx in range(S.indptr[i], S.indptr[i+1])) return result diff --git a/test/test_pymbolic.py b/test/test_pymbolic.py index 09d2e7b..2cc3c82 100644 --- a/test/test_pymbolic.py +++ b/test/test_pymbolic.py @@ -97,7 +97,7 @@ def test_sympy_interaction(): x, y = sp.symbols("x y") f = sp.Function("f") - s1_expr = 1/f(x/sp.sqrt(x**2+y**2)).diff(x, 5) + s1_expr = 1/f(x/sp.sqrt(x**2+y**2)).diff(x, 5) # pylint:disable=not-callable from pymbolic.sympy_interface import ( SympyToPymbolicMapper, -- GitLab