From 6dd1a9c9888419849468fd7f324cc7b4247c7386 Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Tue, 10 Dec 2019 19:43:55 -0600 Subject: [PATCH 1/2] Improve code stringification This makes code stringification deterministic, makes the initial phase clear in the stringified code, and renames STAGE in the output to PHASE. --- dagrt/language.py | 17 ++++++++++------- dagrt/utils.py | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/dagrt/language.py b/dagrt/language.py index a9f5dc1..60a3709 100644 --- a/dagrt/language.py +++ b/dagrt/language.py @@ -31,7 +31,7 @@ from pymbolic.imperative.statement import ( ConditionalAssignment as AssignBase, Nop as NopBase) -from dagrt.utils import get_variables +from dagrt.utils import get_variables, natsorted from contextlib import contextmanager import logging @@ -162,7 +162,7 @@ def _stringify_statements(roots, id_to_stmt, prefix=""): return printed_stmt_ids.add(stmt.id) - for dep_id in stmt.depends_on: + for dep_id in natsorted(stmt.depends_on): print_stmt(id_to_stmt[dep_id]) lines.append( @@ -693,14 +693,17 @@ class DAGCode(RecordWithoutPickling): def __str__(self): lines = [] for phase_name, phase in sorted(six.iteritems(self.phases)): - lines.append("STAGE %s" % phase_name) + phase_title = "PHASE \"%s\"" % phase_name + if phase_name == self.initial_phase: + phase_title += " (initial_phase)" + lines.append(phase_title) - for root_id in phase.depends_on: + for root_id in natsorted(phase.depends_on): lines.extend(_stringify_statements( [phase.id_to_stmt[root_id]], phase.id_to_stmt, prefix=" ")) - lines.append(" -> (next phase) %s" % phase.next_phase) + lines.append(" -> (next phase) \"%s\"" % phase.next_phase) lines.append("") return "\n".join(lines) @@ -1165,14 +1168,14 @@ def get_dot_dependency_graph(code, use_stmt_ids=False): def additional_lines_hook(): for i, (name, phase) in enumerate(six.iteritems(code.phases)): yield "subgraph cluster_%d { label=\"%s\"" % (i, name) - for dep in phase.depends_on: + for dep in natsorted(phase.depends_on): yield dep yield "}" statements = [ stmt if use_stmt_ids else stmt.copy(id=stmt.id) for phase_name, phase in six.iteritems(code.phases) - for stmt in phase.statements] + for stmt in natsorted(phase.statements, key=lambda stmt: stmt.id)] return get_dot_dependency_graph( statements, use_stmt_ids=use_stmt_ids, diff --git a/dagrt/utils.py b/dagrt/utils.py index bd8df2e..4ccb2ab 100644 --- a/dagrt/utils.py +++ b/dagrt/utils.py @@ -224,4 +224,24 @@ def run_fortran(sources, fortran_options=None, fortran_libraries=None): # }}} + +# {{{ sorting in natural order + +def natorder(key): + # Return natural ordering for strings, as opposed to dictionary order. + # E.g. will result in + # 'abc1' < 'abc9' < 'abc10' + # rather than + # 'abc1' < 'abc10' < 'abc9' + # Based on + # http://code.activestate.com/recipes/285264-natural-string-sorting/#c7 + import re + return [int(n) if n else s for n, s in re.findall(r'(\d+)|(\D+)', key)] + + +def natsorted(seq, key=lambda x: x): + return sorted(seq, key=lambda y: natorder(key(y))) + +# }}} + # vim: foldmethod=marker -- GitLab From aef137b0cb15084812dc7520df93b5f95e026e11 Mon Sep 17 00:00:00 2001 From: Matt Wala Date: Tue, 10 Dec 2019 20:04:04 -0600 Subject: [PATCH 2/2] Make natorder() actually deterministic --- dagrt/utils.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dagrt/utils.py b/dagrt/utils.py index 4ccb2ab..69f4640 100644 --- a/dagrt/utils.py +++ b/dagrt/utils.py @@ -236,7 +236,16 @@ def natorder(key): # Based on # http://code.activestate.com/recipes/285264-natural-string-sorting/#c7 import re - return [int(n) if n else s for n, s in re.findall(r'(\d+)|(\D+)', key)] + result = [] + for (int_val, string_val) in re.findall(r"(\d+)|(\D+)", key): + if int_val: + result.append(int(int_val)) + # Tie-breaker in case leading zeros in *int_val* cause distinct + # values to compare equally. + result.append(len(int_val)) + else: + result.append(string_val) + return result def natsorted(seq, key=lambda x: x): -- GitLab