Skip to content

Commit e8406a4

Browse files
Add a CachedMapper and use it for the IdentityMapper
1 parent 1d23d56 commit e8406a4

7 files changed

+38
-1
lines changed

pymbolic/cse.py

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ def __init__(self, to_eliminate, get_key):
7878
self.get_key = get_key
7979

8080
self.canonical_subexprs = {}
81+
super().__init__()
8182

8283
def get_cse(self, expr, key=None):
8384
if key is None:

pymbolic/mapper/__init__.py

+32-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from abc import ABC, abstractmethod
2424
import pymbolic.primitives as primitives
25+
from typing import Generic, TypeVar, Any, Dict
2526

2627
__doc__ = """
2728
Basic dispatch
@@ -73,6 +74,8 @@
7374
.. autoclass:: CSECachingMapperMixin
7475
"""
7576

77+
CachedMapperT = TypeVar("CachedMapperT") # used in CachedMapper
78+
7679

7780
try:
7881
import numpy
@@ -200,6 +203,34 @@ def map_foreign(self, expr, *args, **kwargs):
200203
RecursiveMapper = Mapper
201204

202205

206+
# {{{ CachedMapper
207+
208+
class CachedMapper(Mapper, Generic[CachedMapperT]):
209+
"""Mapper class that maps each subexpression exactly once. This loses some
210+
information compared to :class:`Mapper` as a subexpression is visited only from
211+
one of its predecessors.
212+
"""
213+
214+
def __init__(self) -> None:
215+
self._cache: Dict[CachedMapperT, Any] = {}
216+
217+
def cache_key(self, expr: CachedMapperT) -> Any:
218+
return expr
219+
220+
# type-ignore-reason: incompatible with super class
221+
# type: ignore[override]
222+
def rec(self, expr: CachedMapperT, *args, **kwargs) -> Any:
223+
key = self.cache_key(expr)
224+
try:
225+
return self._cache[key]
226+
except KeyError:
227+
result = super().rec(expr, *args, **kwargs) # type: ignore[type-var]
228+
self._cache[key] = result
229+
return result
230+
231+
# }}}
232+
233+
203234
# {{{ combine mapper
204235

205236
class CombineMapper(RecursiveMapper):
@@ -364,7 +395,7 @@ def map_constant(self, expr):
364395

365396
# {{{ identity mapper
366397

367-
class IdentityMapper(Mapper):
398+
class IdentityMapper(CachedMapper):
368399
"""A :class:`Mapper` whose default mapper methods
369400
make a deep copy of each subexpression.
370401

pymbolic/mapper/collector.py

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def __init__(self, parameters=None):
3636
if parameters is None:
3737
parameters = set()
3838
self.parameters = parameters
39+
super().__init__()
3940

4041
def get_dependencies(self, expr):
4142
from pymbolic.mapper.dependency import DependencyMapper

pymbolic/mapper/constant_converter.py

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def __init__(self, real_type, complex_type=None, integer_type=None):
5151
self.complex_type = complex_type
5252

5353
self.integer_type = integer_type
54+
super().__init__()
5455

5556
def map_constant(self, expr):
5657
if expr.imag:

pymbolic/mapper/cse_tagger.py

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def visit(self, expr):
3737
class CSETagMapper(IdentityMapper):
3838
def __init__(self, walk_mapper):
3939
self.subexpr_histogram = walk_mapper.subexpr_histogram
40+
super().__init__()
4041

4142
def map_call(self, expr):
4243
if self.subexpr_histogram.get(expr, 0) > 1:

pymbolic/mapper/distributor.py

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def __init__(self, collector=None, const_folder=None):
4848

4949
self.collector = collector
5050
self.const_folder = const_folder
51+
super().__init__()
5152

5253
def collect(self, expr):
5354
return self.collector(self.const_folder(expr))

pymbolic/mapper/substitutor.py

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
class SubstitutionMapper(pymbolic.mapper.IdentityMapper):
2727
def __init__(self, subst_func):
2828
self.subst_func = subst_func
29+
super().__init__()
2930

3031
def map_variable(self, expr):
3132
result = self.subst_func(expr)

0 commit comments

Comments
 (0)