Skip to content

Commit

Permalink
Signature computation speedup (#94)
Browse files Browse the repository at this point in the history
* Run unique traversal

* Remove commented old code

* Unique traversal with appended operands

* Unique post traversal with cached ops

* Apply hashing during post traversal

* Convert bytes to hex directly
  • Loading branch information
michalhabera authored Apr 24, 2022
1 parent af99cad commit 2ad4ef1
Showing 1 changed file with 16 additions and 16 deletions.
32 changes: 16 additions & 16 deletions ufl/algorithms/signature.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
GeometricQuantity, ConstantValue, Constant,
ExprList, ExprMapping)
from ufl.log import error
from ufl.corealg.traversal import traverse_unique_terminals, pre_traversal
from ufl.corealg.traversal import traverse_unique_terminals, unique_post_traversal
from ufl.algorithms.domain_analysis import canonicalize_metadata


Expand Down Expand Up @@ -93,21 +93,22 @@ def compute_terminal_hashdata(expressions, renumbering):
return terminal_hashdata


def compute_expression_hashdata(expression, terminal_hashdata):
# The hashdata computed here can be interpreted as prefix operator
# notation, i.e. we store the equivalent of '+ * a b * c d' for
# the expression (a*b)+(c*d)
expression_hashdata = []
for expr in pre_traversal(expression):
def compute_expression_hashdata(expression, terminal_hashdata) -> bytes:
cache = {}

for expr in unique_post_traversal(expression):
# Uniquely traverse tree and hash each node
# E.g. (a + b*c) is hashed as hash([+, hash(a), hash([*, hash(b), hash(c)])])
# Traversal uses post pattern, so children hashes are cached
if expr._ufl_is_terminal_:
data = terminal_hashdata[expr]
data = [terminal_hashdata[expr]]
else:
data = expr._ufl_typecode_ # TODO: Use expr._ufl_signature_data_()? More extensible, but more overhead.
expression_hashdata.append(data)
# Oneliner: TODO: Benchmark, maybe use a generator?
# expression_hashdata = [(terminal_hashdata[expr] if expr._ufl_is_terminal_ else expr._ufl_typecode_)
# for expr in pre_traversal(expression)]
return expression_hashdata
data = [expr._ufl_typecode_]

for op in expr.ufl_operands:
data += [cache[op]]
cache[expr] = hashlib.sha512(str(data).encode("utf-8")).digest()
return cache[expression]


def compute_expression_signature(expr, renumbering): # FIXME: Fix callers
Expand All @@ -121,8 +122,7 @@ def compute_expression_signature(expr, renumbering): # FIXME: Fix callers

# Pass it through a seriously overkill hashing algorithm
# (should we use sha1 instead?)
data = str(expression_hashdata).encode("utf-8")
return hashlib.sha512(data).hexdigest()
return expression_hashdata.hex()


def compute_form_signature(form, renumbering): # FIXME: Fix callers
Expand Down

0 comments on commit 2ad4ef1

Please sign in to comment.