From 4ff45187f20b9f2c31b390bd064cf7027e5c1c3b Mon Sep 17 00:00:00 2001
From: Andreas Kloeckner <inform@tiker.net>
Date: Wed, 26 Nov 2014 14:56:57 -0600
Subject: [PATCH] Modernize pymbolic

---
 doc/conf.py                              |  3 +-
 pymbolic/__init__.py                     |  1 +
 pymbolic/algorithm.py                    | 18 +++++---
 pymbolic/compiler.py                     |  3 +-
 pymbolic/cse.py                          |  6 ++-
 pymbolic/functions.py                    |  1 +
 pymbolic/geometric_algebra/__init__.py   | 57 +++++++++++++-----------
 pymbolic/geometric_algebra/mapper.py     |  7 ++-
 pymbolic/geometric_algebra/primitives.py |  1 +
 pymbolic/mapper/__init__.py              | 11 +++--
 pymbolic/mapper/coefficient.py           |  6 ++-
 pymbolic/mapper/collector.py             | 10 +++--
 pymbolic/mapper/unifier.py               |  6 ++-
 pymbolic/maxima.py                       | 12 ++---
 pymbolic/parser.py                       |  1 +
 pymbolic/polynomial.py                   | 17 ++++---
 pymbolic/primitives.py                   | 16 +++++--
 pymbolic/rational.py                     |  8 ++--
 pymbolic/traits.py                       |  7 ++-
 19 files changed, 120 insertions(+), 71 deletions(-)

diff --git a/doc/conf.py b/doc/conf.py
index d57aa79..c393bd3 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
 # -*- coding: utf-8 -*-
 #
 # pymbolic documentation build configuration file, created by
@@ -56,7 +57,7 @@ copyright = u'2013, Andreas Kloeckner'
 #
 # The short X.Y version.
 ver_dic = {}
-execfile("../pymbolic/version.py", ver_dic)
+exec(compile(open("../pymbolic/version.py").read(), "../pymbolic/version.py", 'exec'), ver_dic)
 version = ".".join(str(x) for x in ver_dic["VERSION"])
 # The full version, including alpha/beta/rc tags.
 release = ver_dic["VERSION_TEXT"]
diff --git a/pymbolic/__init__.py b/pymbolic/__init__.py
index 740febc..70a7bea 100644
--- a/pymbolic/__init__.py
+++ b/pymbolic/__init__.py
@@ -1,4 +1,5 @@
 from __future__ import division
+from __future__ import absolute_import
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
diff --git a/pymbolic/algorithm.py b/pymbolic/algorithm.py
index 5c4a227..77f861f 100644
--- a/pymbolic/algorithm.py
+++ b/pymbolic/algorithm.py
@@ -1,4 +1,10 @@
 from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+import six
+from six.moves import range
+from six.moves import zip
+from functools import reduce
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -224,7 +230,7 @@ def csr_matrix_multiply(S, x):
     import numpy
     result = numpy.empty_like(x)
 
-    for i in xrange(h):
+    for i in range(h):
         result[i] = sum(S.data[idx]*x[S.indices[idx]]
                 for idx in range(S.indptr[i], S.indptr[i+1]))
 
@@ -331,7 +337,7 @@ def solve_affine_equations_for(unknowns, equations):
 
     for i_eqn, (lhs, rhs) in enumerate(equations):
         for lhs_factor, coeffs in [(1, coeff_coll(lhs)), (-1, coeff_coll(rhs))]:
-            for key, coeff in coeffs.iteritems():
+            for key, coeff in six.iteritems(coeffs):
                 if key in unknowns_set:
                     mat[i_eqn, unknown_idx_lut[key]] = lhs_factor*coeff
                 elif key in parameters:
@@ -370,10 +376,10 @@ def solve_affine_equations_for(unknowns, equations):
 
     if 0:
         for lhs, rhs in equations:
-            print lhs, '=', rhs
-        print "-------------------"
-        for lhs, rhs in result.iteritems():
-            print lhs, '=', rhs
+            print(lhs, '=', rhs)
+        print("-------------------")
+        for lhs, rhs in six.iteritems(result):
+            print(lhs, '=', rhs)
 
     return result
 
diff --git a/pymbolic/compiler.py b/pymbolic/compiler.py
index 6cc3bfe..53c437b 100644
--- a/pymbolic/compiler.py
+++ b/pymbolic/compiler.py
@@ -1,4 +1,5 @@
 from __future__ import division
+from __future__ import absolute_import
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -129,7 +130,7 @@ class CompiledExpression:
         used_variables = DependencyMapper(
                 composite_leaves=False)(self._Expression)
         used_variables -= set(self._Variables)
-        used_variables -= set(pymbolic.var(key) for key in ctx.keys())
+        used_variables -= set(pymbolic.var(key) for key in list(ctx.keys()))
         used_variables = list(used_variables)
         used_variables.sort()
         all_variables = self._Variables + used_variables
diff --git a/pymbolic/cse.py b/pymbolic/cse.py
index 2ececf1..e57dd39 100644
--- a/pymbolic/cse.py
+++ b/pymbolic/cse.py
@@ -1,4 +1,6 @@
 from __future__ import division
+from __future__ import absolute_import
+import six
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -37,7 +39,7 @@ class NormalizedKeyGetter(object):
             for child in expr.children:
                 kid_count[child] = kid_count.get(child, 0) + 1
 
-            return type(expr), frozenset(kid_count.iteritems())
+            return type(expr), frozenset(six.iteritems(kid_count))
         else:
             return expr
 
@@ -147,7 +149,7 @@ def tag_common_subexpressions(exprs):
         ucm(expr)
 
     to_eliminate = set([subexpr_key
-        for subexpr_key, count in ucm.subexpr_counts.iteritems()
+        for subexpr_key, count in six.iteritems(ucm.subexpr_counts)
         if count > 1])
 
     cse_mapper = CSEMapper(to_eliminate, get_key)
diff --git a/pymbolic/functions.py b/pymbolic/functions.py
index 0a1af3e..181c686 100644
--- a/pymbolic/functions.py
+++ b/pymbolic/functions.py
@@ -1,4 +1,5 @@
 from __future__ import division
+from __future__ import absolute_import
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
diff --git a/pymbolic/geometric_algebra/__init__.py b/pymbolic/geometric_algebra/__init__.py
index e470280..d52cdca 100644
--- a/pymbolic/geometric_algebra/__init__.py
+++ b/pymbolic/geometric_algebra/__init__.py
@@ -1,4 +1,7 @@
 from __future__ import division
+from __future__ import absolute_import
+import six
+from six.moves import range
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -118,7 +121,7 @@ def permutation_sign(p):
     p = list(p)
     s = +1
 
-    for i in xrange(len(p)):
+    for i in range(len(p)):
         # j is the current position of item I.
         j = i
 
@@ -199,7 +202,7 @@ class Space(object):
             basis = int(metric_matrix.shape[0])
 
         if isinstance(basis, int):
-            basis = ["e%d" % i for i in xrange(basis)]
+            basis = ["e%d" % i for i in range(basis)]
 
         if metric_matrix is None:
             metric_matrix = np.eye(len(basis), dtype=np.object)
@@ -531,10 +534,10 @@ class MultiVector(object):
 
         from pytools import single_valued
         from pymbolic.primitives import is_zero
-        if data and single_valued(isinstance(k, tuple) for k in data.iterkeys()):
+        if data and single_valued(isinstance(k, tuple) for k in six.iterkeys(data)):
             # data is in non-normalized non-bits tuple form
             new_data = {}
-            for basis_indices, coeff in data.iteritems():
+            for basis_indices, coeff in six.iteritems(data):
                 bits, sign = space.bits_and_sign(basis_indices)
                 new_coeff = new_data.setdefault(bits, 0) + sign*coeff
 
@@ -550,7 +553,7 @@ class MultiVector(object):
         # assert that multivectors don't get nested
         from pytools import any
         assert not any(isinstance(coeff, MultiVector)
-                for coeff in data.itervalues())
+                for coeff in six.itervalues(data))
 
         self.space = space
         self.data = data
@@ -568,7 +571,7 @@ class MultiVector(object):
         from pymbolic.mapper.stringifier import PREC_PRODUCT, PREC_SUM
 
         terms = []
-        for bits in sorted(self.data.iterkeys(),
+        for bits in sorted(six.iterkeys(self.data),
                 key=lambda bits: (bit_count(bits), bits)):
             coeff = self.data[bits]
 
@@ -620,7 +623,7 @@ class MultiVector(object):
     def __neg__(self):
         return MultiVector(
                 dict((bits, -coeff)
-                    for bits, coeff in self.data.iteritems()),
+                    for bits, coeff in six.iteritems(self.data)),
                 self.space)
 
     def __add__(self, other):
@@ -631,7 +634,7 @@ class MultiVector(object):
         if self.space is not other.space:
             raise ValueError("can only add multivectors from identical spaces")
 
-        all_bits = set(self.data.iterkeys()) | set(other.data.iterkeys())
+        all_bits = set(six.iterkeys(self.data)) | set(six.iterkeys(other.data))
 
         from pymbolic.primitives import is_zero
         new_data = {}
@@ -672,8 +675,8 @@ class MultiVector(object):
 
         from pymbolic.primitives import is_zero
         new_data = {}
-        for sbits, scoeff in self.data.iteritems():
-            for obits, ocoeff in other.data.iteritems():
+        for sbits, scoeff in six.iteritems(self.data):
+            for obits, ocoeff in six.iteritems(other.data):
                 new_bits = sbits ^ obits
                 weight = bpw(sbits, obits, self.space)
 
@@ -809,13 +812,13 @@ class MultiVector(object):
         if len(self.data) > 1:
             if self.get_pure_grade() in [0, 1, self.space.dimensions]:
                 return MultiVector(dict(
-                    (bits, coeff/nsqr) for bits, coeff in self.data.iteritems()),
+                    (bits, coeff/nsqr) for bits, coeff in six.iteritems(self.data)),
                     self.space)
 
             else:
                 raise NotImplementedError("division by non-blades")
 
-        (bits, coeff), = self.data.iteritems()
+        (bits, coeff), = six.iteritems(self.data)
 
         # (1.1.54) in [HS]
         grade = bit_count(bits)
@@ -833,7 +836,7 @@ class MultiVector(object):
         Often written :math:`A^\dagger`.
         """
         new_data = {}
-        for bits, coeff in self.data.iteritems():
+        for bits, coeff in six.iteritems(self.data):
             grade = bit_count(bits)
             if grade*(grade-1)//2 % 2 == 0:
                 new_data[bits] = coeff
@@ -849,7 +852,7 @@ class MultiVector(object):
         Often written :math:`\widehat A`.
         """
         new_data = {}
-        for bits, coeff in self.data.iteritems():
+        for bits, coeff in six.iteritems(self.data):
             grade = bit_count(bits)
             if grade % 2 == 0:
                 new_data[bits] = coeff
@@ -889,7 +892,7 @@ class MultiVector(object):
     @memoize_method
     def __hash__(self):
         result = hash(self.space)
-        for bits, coeff in self.data.iteritems():
+        for bits, coeff in six.iteritems(self.data):
             result ^= hash(bits) ^ hash(coeff)
 
         return result
@@ -916,7 +919,7 @@ class MultiVector(object):
             tol = 1e-13
 
         new_data = {}
-        for bits, coeff in self.data.iteritems():
+        for bits, coeff in six.iteritems(self.data):
             if abs(coeff) > tol:
                 new_data[bits] = coeff
 
@@ -935,10 +938,10 @@ class MultiVector(object):
         """
 
         if grade is None:
-            for bits, coeff in self.data.iteritems():
+            for bits, coeff in six.iteritems(self.data):
                 yield MultiVector({bits: coeff}, self.space)
         else:
-            for bits, coeff in self.data.iteritems():
+            for bits, coeff in six.iteritems(self.data):
                 if bit_count(bits) == grade:
                     yield MultiVector({bits: coeff}, self.space)
 
@@ -948,7 +951,7 @@ class MultiVector(object):
         Often written :math:`\langle A\rangle_r`.
         """
         new_data = {}
-        for bits, coeff in self.data.iteritems():
+        for bits, coeff in six.iteritems(self.data):
             if bit_count(bits) == r:
                 new_data[bits] = coeff
 
@@ -969,7 +972,7 @@ class MultiVector(object):
     def all_grades(self):
         """Return a :class:`set` of grades occurring in *self*."""
 
-        return set(bit_count(bits) for bits, coeff in self.data.iteritems())
+        return set(bit_count(bits) for bits, coeff in six.iteritems(self.data))
 
     def get_pure_grade(self):
         """If *self* only has components of a single grade, return
@@ -980,7 +983,7 @@ class MultiVector(object):
 
         result = None
 
-        for bits, coeff in self.data.iteritems():
+        for bits, coeff in six.iteritems(self.data):
             grade = bit_count(bits)
             if result is None:
                 result = grade
@@ -994,7 +997,7 @@ class MultiVector(object):
     def odd(self):
         """Extract the odd-grade blades."""
         new_data = {}
-        for bits, coeff in self.data.iteritems():
+        for bits, coeff in six.iteritems(self.data):
             if bit_count(bits) % 2:
                 new_data[bits] = coeff
 
@@ -1003,7 +1006,7 @@ class MultiVector(object):
     def even(self):
         """Extract the even-grade blades."""
         new_data = {}
-        for bits, coeff in self.data.iteritems():
+        for bits, coeff in six.iteritems(self.data):
             if bit_count(bits) % 2 == 0:
                 new_data[bits] = coeff
 
@@ -1025,7 +1028,7 @@ class MultiVector(object):
 
     def as_scalar(self):
         result = 0
-        for bits, coeff in self.data.iteritems():
+        for bits, coeff in six.iteritems(self.data):
             if bits != 0:
                 raise ValueError("multivector is not a scalar")
             result = coeff
@@ -1044,9 +1047,9 @@ class MultiVector(object):
         else:
             result = [0] * self.space.dimensions
 
-        log_table = dict((2**i, i) for i in xrange(self.space.dimensions))
+        log_table = dict((2**i, i) for i in range(self.space.dimensions))
         try:
-            for bits, coeff in self.data.iteritems():
+            for bits, coeff in six.iteritems(self.data):
                 result[log_table[bits]] = coeff
         except KeyError:
             raise ValueError("multivector is not a purely grade-1")
@@ -1066,7 +1069,7 @@ class MultiVector(object):
         new coefficient.
         """
         new_data = {}
-        for bits, coeff in self.data.iteritems():
+        for bits, coeff in six.iteritems(self.data):
             new_data[bits] = f(coeff)
 
         return MultiVector(new_data, self.space)
diff --git a/pymbolic/geometric_algebra/mapper.py b/pymbolic/geometric_algebra/mapper.py
index a33fce0..6d242ea 100644
--- a/pymbolic/geometric_algebra/mapper.py
+++ b/pymbolic/geometric_algebra/mapper.py
@@ -1,4 +1,7 @@
 from __future__ import division
+from __future__ import absolute_import
+from six.moves import range
+from six.moves import zip
 
 __copyright__ = "Copyright (C) 2014 Andreas Kloeckner"
 
@@ -117,7 +120,7 @@ class Dimensionalizer(EvaluationMapper):
         from pytools.obj_array import make_obj_array
         return MultiVector(make_obj_array(
             [prim.NablaComponent(axis, expr.nabla_id)
-                for axis in xrange(self.ambient_dim)]))
+                for axis in range(self.ambient_dim)]))
 
     def map_derivative_source(self, expr):
         rec_op = self.rec(expr.operand)
@@ -242,7 +245,7 @@ class DerivativeBinder(IdentityMapper):
 
             new_result = []
             for prod_term_list in result:
-                for axis in xrange(n_axes):
+                for axis in range(n_axes):
                     new_ptl = prod_term_list[:]
                     dsfinder = self.derivative_source_finder(nabla_id, self, axis)
 
diff --git a/pymbolic/geometric_algebra/primitives.py b/pymbolic/geometric_algebra/primitives.py
index b6b43d6..ea6bccf 100644
--- a/pymbolic/geometric_algebra/primitives.py
+++ b/pymbolic/geometric_algebra/primitives.py
@@ -1,4 +1,5 @@
 from __future__ import division
+from __future__ import absolute_import
 
 __copyright__ = "Copyright (C) 2014 Andreas Kloeckner"
 
diff --git a/pymbolic/mapper/__init__.py b/pymbolic/mapper/__init__.py
index 210570a..1c1f65e 100644
--- a/pymbolic/mapper/__init__.py
+++ b/pymbolic/mapper/__init__.py
@@ -1,4 +1,7 @@
 from __future__ import division
+from __future__ import absolute_import
+import six
+from functools import reduce
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -281,7 +284,7 @@ class CombineMapper(RecursiveMapper):
         return self.combine(self.rec(el) for el in expr.flat)
 
     def map_multivector(self, expr, *args, **kwargs):
-        return self.combine(self.rec(coeff) for bits, coeff in expr.data.iteritems())
+        return self.combine(self.rec(coeff) for bits, coeff in six.iteritems(expr.data))
 
     def map_common_subexpression(self, expr, *args, **kwargs):
         return self.rec(expr.child, *args, **kwargs)
@@ -359,7 +362,7 @@ class IdentityMapper(Mapper):
                     for child in expr.parameters),
                 dict(
                     (key, self.rec(val, *args, **kwargs))
-                    for key, val in expr.kw_parameters.iteritems())
+                    for key, val in six.iteritems(expr.kw_parameters))
                     )
 
     def map_subscript(self, expr, *args, **kwargs):
@@ -525,7 +528,7 @@ class WalkMapper(RecursiveMapper):
         for child in expr.parameters:
             self.rec(child, *args, **kwargs)
 
-        for child in expr.kw_parameters.values():
+        for child in list(expr.kw_parameters.values()):
             self.rec(child, *args, **kwargs)
 
     def map_subscript(self, expr, *args, **kwargs):
@@ -596,7 +599,7 @@ class WalkMapper(RecursiveMapper):
         if not self.visit(expr, *args):
             return
 
-        for bits, coeff in expr.data.iteritems():
+        for bits, coeff in six.iteritems(expr.data):
             self.rec(coeff)
 
     def map_common_subexpression(self, expr, *args, **kwargs):
diff --git a/pymbolic/mapper/coefficient.py b/pymbolic/mapper/coefficient.py
index 4592c35..647a2f7 100644
--- a/pymbolic/mapper/coefficient.py
+++ b/pymbolic/mapper/coefficient.py
@@ -1,4 +1,6 @@
 from __future__ import division
+from __future__ import absolute_import
+import six
 
 __copyright__ = "Copyright (C) 2013 Andreas Kloeckner"
 
@@ -35,7 +37,7 @@ class CoefficientCollector(Mapper):
 
         result = {}
         for stride_dict in stride_dicts:
-            for var, stride in stride_dict.iteritems():
+            for var, stride in six.iteritems(stride_dict):
                 if var in result:
                     result[var] += stride
                 else:
@@ -70,7 +72,7 @@ class CoefficientCollector(Mapper):
             return dict(
                     (var, other_coeffs*coeff)
                     for var, coeff in
-                    children_coeffs[idx_of_child_with_vars].iteritems())
+                    six.iteritems(children_coeffs[idx_of_child_with_vars]))
 
         return result
 
diff --git a/pymbolic/mapper/collector.py b/pymbolic/mapper/collector.py
index 4c7f289..fce56e6 100644
--- a/pymbolic/mapper/collector.py
+++ b/pymbolic/mapper/collector.py
@@ -1,4 +1,6 @@
 from __future__ import division
+from __future__ import absolute_import
+import six
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -73,7 +75,7 @@ class TermCollector(IdentityMapper):
         elif not bool(self.get_dependencies(mul_term)):
             terms = [mul_term]
         else:
-            raise RuntimeError, "split_term expects a multiplicative term"
+            raise RuntimeError("split_term expects a multiplicative term")
 
         base2exp = {}
         for term in terms:
@@ -87,14 +89,14 @@ class TermCollector(IdentityMapper):
 
         coefficients = []
         cleaned_base2exp = {}
-        for base, exp in base2exp.iteritems():
+        for base, exp in six.iteritems(base2exp):
             term = base**exp
             if  self.get_dependencies(term) <= self.parameters:
                 coefficients.append(term)
             else:
                 cleaned_base2exp[base] = exp
 
-        term = frozenset((base,exp) for base, exp in cleaned_base2exp.iteritems())
+        term = frozenset((base,exp) for base, exp in six.iteritems(cleaned_base2exp))
         return term, pymbolic.flattened_product(coefficients)
 
     def map_sum(self, mysum):
@@ -107,5 +109,5 @@ class TermCollector(IdentityMapper):
             return pymbolic.flattened_product(base**exp for base, exp in rep)
 
         result = pymbolic.flattened_sum(coeff*rep2term(termrep)
-                for termrep, coeff in term2coeff.iteritems())
+                for termrep, coeff in six.iteritems(term2coeff))
         return result
diff --git a/pymbolic/mapper/unifier.py b/pymbolic/mapper/unifier.py
index 6dd22cf..b9fa9d7 100644
--- a/pymbolic/mapper/unifier.py
+++ b/pymbolic/mapper/unifier.py
@@ -1,4 +1,8 @@
 from __future__ import division
+from __future__ import absolute_import
+import six
+from six.moves import range
+from six.moves import zip
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -30,7 +34,7 @@ from pymbolic.primitives import Variable
 
 def unify_map(map1, map2):
     result = map1.copy()
-    for name, value in map2.iteritems():
+    for name, value in six.iteritems(map2):
         if name in map1:
             if map1[name] != value:
                 return None
diff --git a/pymbolic/maxima.py b/pymbolic/maxima.py
index 1fbee38..47dbd8f 100644
--- a/pymbolic/maxima.py
+++ b/pymbolic/maxima.py
@@ -1,4 +1,6 @@
 from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -289,7 +291,7 @@ class MaximaKernel:
     def exec_str(self, s):
         cmd = s+";"
         if _DEBUG & 1:
-            print "[MAXIMA INPUT]", cmd
+            print("[MAXIMA INPUT]", cmd)
 
         self._sendline(s+";")
         self._expect_prompt(IN_PROMPT_RE)
@@ -299,7 +301,7 @@ class MaximaKernel:
 
         cmd = s+";"
         if _DEBUG & 1:
-            print "[MAXIMA INPUT]", cmd
+            print("[MAXIMA INPUT]", cmd)
 
         self._sendline(cmd)
         s_echo = self.child.readline()
@@ -312,7 +314,7 @@ class MaximaKernel:
         result, _ = MULTI_WHITESPACE.subn(" ", self.child.before)
 
         if _DEBUG & 1:
-            print "[MAXIMA RESPONSE]", result
+            print("[MAXIMA RESPONSE]", result)
         return result
 
     def reset(self):
@@ -335,7 +337,7 @@ class MaximaKernel:
         result_str = self.eval_str(input_str)
         parsed = MaximaParser()(result_str)
         if _DEBUG & 2:
-            print "[MAXIMA PARSED]", parsed
+            print("[MAXIMA PARSED]", parsed)
         return parsed
 
     def clean_eval_expr_with_setup(self, assignments, expr):
@@ -344,7 +346,7 @@ class MaximaKernel:
 
         parsed = MaximaParser()(result_str)
         if _DEBUG & 2:
-            print "[MAXIMA PARSED  ]", parsed
+            print("[MAXIMA PARSED  ]", parsed)
         return parsed
 
     # }}}
diff --git a/pymbolic/parser.py b/pymbolic/parser.py
index fb90aed..4a280e1 100644
--- a/pymbolic/parser.py
+++ b/pymbolic/parser.py
@@ -1,4 +1,5 @@
 from __future__ import division
+from __future__ import absolute_import
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
diff --git a/pymbolic/polynomial.py b/pymbolic/polynomial.py
index de28e45..48959ef 100644
--- a/pymbolic/polynomial.py
+++ b/pymbolic/polynomial.py
@@ -1,4 +1,7 @@
 from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
+from six.moves import range
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -31,7 +34,7 @@ from pymbolic.traits import traits, EuclideanRingTraits, FieldTraits
 
 
 def _sort_uniq(data):
-    def sortkey((exp, coeff)): return exp
+    def sortkey(xxx_todo_changeme): (exp, coeff) = xxx_todo_changeme; return exp
     data.sort(key=sortkey)
 
     uniq_result = []
@@ -244,7 +247,7 @@ class Polynomial(Expression):
             return 1/other * self
         q, r = divmod(self, other)
         if r.degree != -1:
-            raise ValueError, "division yielded a remainder"
+            raise ValueError("division yielded a remainder")
         return q
 
     __truediv__ = __div__
@@ -369,8 +372,8 @@ if __name__ == "__main__":
 
     u = (x+1)**5
     v = pymbolic.evaluate_kw(u, x=x)
-    print u
-    print v
+    print(u)
+    print(v)
 
     if False:
         # NOT WORKING INTRODUCE TESTS
@@ -379,8 +382,8 @@ if __name__ == "__main__":
         #u = x+1
         #v = 3*x+1
         q, r = divmod(u, v)
-        print q, "R", r
-        print q*v
-        print "REASSEMBLY:", q*v + r
+        print(q, "R", r)
+        print(q*v)
+        print("REASSEMBLY:", q*v + r)
 
 
diff --git a/pymbolic/primitives.py b/pymbolic/primitives.py
index 660aed6..df9ffde 100644
--- a/pymbolic/primitives.py
+++ b/pymbolic/primitives.py
@@ -1,4 +1,5 @@
 from __future__ import division
+from __future__ import absolute_import
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -24,6 +25,10 @@ THE SOFTWARE.
 
 import pymbolic.traits as traits
 
+import six
+from six.moves import range
+from six.moves import zip
+
 __doc__ = """
 .. autofunction:: disable_subscript_by_getitem
 
@@ -679,7 +684,7 @@ class CallWithKwargs(AlgebraicLeaf):
         return (self.function,
                 self.parameters,
                 tuple(sorted(
-                    self.kw_parameters.items(),
+                    list(self.kw_parameters.items()),
                     key=lambda item: item[0])))
 
     mapper_method = intern("map_call_with_kwargs")
@@ -1426,7 +1431,10 @@ def quotient(numerator, denominator):
 
 global VALID_CONSTANT_CLASSES
 global VALID_OPERANDS
-VALID_CONSTANT_CLASSES = (int, long, float, complex)
+VALID_CONSTANT_CLASSES = (int, float, complex)
+if six.PY2:
+    VALID_CONSTANT_CLASSES += (long,)
+
 VALID_OPERANDS = (Expression,)
 
 try:
@@ -1516,7 +1524,7 @@ def make_common_subexpression(field, prefix=None, scope=None):
     from pymbolic.geometric_algebra import MultiVector
     if isinstance(field, MultiVector):
         new_data = {}
-        for bits, coeff in field.data.iteritems():
+        for bits, coeff in six.iteritems(field.data):
             if prefix is not None:
                 blade_str = field.space.blade_bits_to_str(bits, "")
                 component_prefix = prefix+"_"+blade_str
@@ -1559,7 +1567,7 @@ def make_sym_vector(name, components):
     :param components: The number of components in the vector.
     """
     if isinstance(components, int):
-        components = range(components)
+        components = list(range(components))
 
     from pytools.obj_array import join_fields
     vfld = Variable(name)
diff --git a/pymbolic/rational.py b/pymbolic/rational.py
index ea24db7..4ca699d 100644
--- a/pymbolic/rational.py
+++ b/pymbolic/rational.py
@@ -1,4 +1,6 @@
 from __future__ import division
+from __future__ import absolute_import
+from __future__ import print_function
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -135,6 +137,6 @@ class Rational(primitives.Expression):
 
 if __name__ == "__main__":
     one = Rational(1)
-    print 3 + 1/(1 - 3/(one + 17))
-    print one/3 + 2*one/3
-    print one/3 + 2*one/3 + 0*one/1771
+    print(3 + 1/(1 - 3/(one + 17)))
+    print(one/3 + 2*one/3)
+    print(one/3 + 2*one/3 + 0*one/1771)
diff --git a/pymbolic/traits.py b/pymbolic/traits.py
index bbcc854..ac1d7a3 100644
--- a/pymbolic/traits.py
+++ b/pymbolic/traits.py
@@ -1,4 +1,7 @@
 from __future__ import division
+from __future__ import absolute_import
+import six
+from functools import reduce
 
 __copyright__ = "Copyright (C) 2009-2013 Andreas Kloeckner"
 
@@ -22,7 +25,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 """
 
-import algorithm
+from . import algorithm
 
 
 class NoTraitsError(Exception):
@@ -39,7 +42,7 @@ def traits(x):
     except AttributeError:
         if isinstance(x, (complex, float)):
             return FieldTraits()
-        elif isinstance(x, (int, long)):
+        elif isinstance(x, six.integer_types):
             return IntegerTraits()
         else:
             raise NoTraitsError
-- 
GitLab