From f184474ee4a37bb6ac144748dde0ec2b83cae01b Mon Sep 17 00:00:00 2001 From: Chris Cummins Date: Fri, 14 Dec 2018 20:49:37 +0000 Subject: [PATCH] Work in progress refactoring reachability. --- .project/.idea/dictionaries/cec.xml | 2 + experimental/compilers/reachability/BUILD | 68 ++++++++-- .../reachability/control_flow_graph.py | 56 ++++++++ .../control_flow_graph_generator.py | 99 ++++++++++++++ .../control_flow_graph_generator_test.py | 67 +++++++++ .../reachability/control_flow_graph_test.py | 127 ++++++++++++++++++ .../compilers/reachability/notebooks/BUILD | 10 ++ .../reachability/notebooks/run_notebook.sh | 8 ++ .../compilers/reachability/proto/BUILD | 10 -- .../{proto => }/reachability.proto | 1 + .../compilers/reachability/reachability.py | 116 +--------------- .../compilers/reachability/train_model.py | 12 +- 12 files changed, 432 insertions(+), 144 deletions(-) create mode 100644 experimental/compilers/reachability/control_flow_graph.py create mode 100644 experimental/compilers/reachability/control_flow_graph_generator.py create mode 100644 experimental/compilers/reachability/control_flow_graph_generator_test.py create mode 100644 experimental/compilers/reachability/control_flow_graph_test.py create mode 100644 experimental/compilers/reachability/notebooks/BUILD create mode 100644 experimental/compilers/reachability/notebooks/run_notebook.sh delete mode 100644 experimental/compilers/reachability/proto/BUILD rename experimental/compilers/reachability/{proto => }/reachability.proto (99%) diff --git a/.project/.idea/dictionaries/cec.xml b/.project/.idea/dictionaries/cec.xml index 49b1fa4d7..7c0c73e43 100644 --- a/.project/.idea/dictionaries/cec.xml +++ b/.project/.idea/dictionaries/cec.xml @@ -81,6 +81,8 @@ proc protos randchar + reachability + reachables relpath relpaths relu diff --git a/experimental/compilers/reachability/BUILD b/experimental/compilers/reachability/BUILD index 5b94c99e1..0ec8cd533 100644 --- a/experimental/compilers/reachability/BUILD +++ b/experimental/compilers/reachability/BUILD @@ -1,13 +1,59 @@ # Experiments in learning reachability analysis. +load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") + +py_library( + name = "control_flow_graph", + srcs = ["control_flow_graph.py"], + deps = [ + "//third_party/py/absl", + "//third_party/py/networkx", + ], + visibility = ["//experimental/compilers/reachability:__subpackages__"], +) + +py_test( + name = "control_flow_graph_test", + srcs = ["control_flow_graph_test.py"], + deps = [ + ":control_flow_graph", + "//third_party/py/absl", + "//third_party/py/networkx", + "//third_party/py/pytest", + ], +) + +py_library( + name = "control_flow_graph_generator", + srcs = ["control_flow_graph_generator.py"], + deps = [ + ":control_flow_graph", + "//third_party/py/absl", + "//third_party/py/networkx", + "//third_party/py/numpy", + ], + visibility = ["//experimental/compilers/reachability:__subpackages__"], +) + +py_test( + name = "control_flow_graph_generator_test", + srcs = ["control_flow_graph_generator_test.py"], + deps = [ + ":control_flow_graph_generator", + "//third_party/py/absl", + "//third_party/py/networkx", + "//third_party/py/pytest", + ], +) + py_binary( name = "eval_model", srcs = ["eval_model.py"], deps = [ + ":reachability_py_pb2", ":train_model", "//deeplearning/clgen:telemetry", "//deeplearning/clgen/corpuses:atomizers", - "//experimental/compilers/reachability/proto:reachability_py_pb2", "//labm8:pbutil", "//third_party/py/absl", "//third_party/py/humanize", @@ -16,27 +62,21 @@ py_binary( ], ) -py_binary( - name = "reachability", - srcs = ["reachability.py"], - deps = [ - "//experimental/compilers/reachability/proto:reachability_py_pb2", - "//labm8:fmt", - "//labm8:fs", - "//labm8:graph", - "//third_party/py/absl", - "//third_party/py/numpy", - ], +py_proto_library( + name = "reachability_py_pb2", + protos = ["reachability.proto"], + deps = ["//third_party/py/protobuf"], + visibility = ["//experimental/compilers/reachability:__subpackages__"], ) py_binary( name = "train_model", srcs = ["train_model.py"], deps = [ - ":reachability", + ":control_flow_graph", + ":reachability_py_pb2", "//deeplearning/clgen:telemetry", "//deeplearning/clgen/corpuses:atomizers", - "//experimental/compilers/reachability/proto:reachability_py_pb2", "//labm8:pbutil", "//third_party/py/absl", "//third_party/py/humanize", diff --git a/experimental/compilers/reachability/control_flow_graph.py b/experimental/compilers/reachability/control_flow_graph.py new file mode 100644 index 000000000..ce0bbb115 --- /dev/null +++ b/experimental/compilers/reachability/control_flow_graph.py @@ -0,0 +1,56 @@ +"""A class representing a control flow graph.""" +import typing + +import networkx as nx +from absl import flags + + +FLAGS = flags.FLAGS + + +class ControlFlowGraph(nx.DiGraph): + """A control flow graph. + + For a control flow graph to be considered "valid", the following properties + should be adhered to: + + * All nodes in the graph should have a unique "name" attribute. This can be + set at creation time, e.g.: cfg.add_node(0, name='foo'). + * The graph should be fully connected. + + Use the IsValidControlFlowGraph() method to check if a graph instance has + these properties. + """ + + def __init__(self, name: str = "cfg"): + super(ControlFlowGraph, self).__init__(name=name) + + def IsReachable(self, src, dst) -> bool: + """Return whether dst node is reachable from src.""" + # TODO(cec): It seems that descendants() does not include self loops, so + # test for the node in both descendants and self loops. + return ((dst in nx.descendants(self, src)) or + (dst in self.nodes_with_selfloops())) + + def Reachables(self, src) -> typing.Iterator[bool]: + """Return whether each node is reachable from the src node.""" + return (self.IsReachable(src, dst) for dst in self.nodes) + + def IsValidControlFlowGraph(self) -> bool: + """Return true if the graph is a valid control flow graph.""" + number_of_nodes = self.number_of_nodes() + # CFGs must contain a node. + if not number_of_nodes: + return False + # CFGs must be fully connected. + # TODO: + # if nx.number_connected_components(self) != number_of_nodes: + # return False + # All nodes must have a name. + if not all('name' in self.nodes[node] for node in self.nodes): + return False + # All node names must be unique. + node_names_set = set(self.nodes[n]['name'] for n in self.nodes) + if len(node_names_set) != number_of_nodes: + return False + return True diff --git a/experimental/compilers/reachability/control_flow_graph_generator.py b/experimental/compilers/reachability/control_flow_graph_generator.py new file mode 100644 index 000000000..68eaeab1a --- /dev/null +++ b/experimental/compilers/reachability/control_flow_graph_generator.py @@ -0,0 +1,99 @@ +"""A generator for control flow graphs.""" +import typing + +import numpy as np +from absl import flags + +from experimental.compilers.reachability import control_flow_graph as cfg + + +FLAGS = flags.FLAGS + + +class UniqueNameSequence(object): + + def __init__(self, base_char: str, prefix: str = ''): + if base_char not in {'a', 'A'}: + raise ValueError(f"Invalid base_char '{base_char}'") + self._base_ord = ord(base_char) + self._prefix = prefix + self._i = 0 + + def StringInSequence(self, i: int) -> str: + if i < 0: + raise ValueError + s = [self._prefix] + + while (i > 25): + k = i // 26 + i %= 26 + s.append(chr(self._base_ord - 1 + k)) + s.append(chr(self._base_ord + i)) + + return ''.join(s) + + def __next__(self): + s = self.StringInSequence(self._i) + self._i += 1 + return s + + +class ControlFlowGraphGenerator(object): + """A generator for control flow graphs.""" + + def __init__(self, rand: np.random.RandomState, + num_nodes_min_max: typing.Tuple[int, int], + connections_scaling_param: float): + """Instantiate a control flow graph generator. + + Args: + rand: A random state instance. + num_nodes: The number of CFG nodes. + connections_scaling_param: Scaling parameter to use to determine the + likelihood of edges between CFG nodes. + """ + self._rand = rand + self._num_nodes_min_max = num_nodes_min_max + self._connections_scaling_param = connections_scaling_param + + @property + def rand(self) -> np.random.RandomState: + return self._rand + + @property + def num_nodes_min_max(self) -> typing.Tuple[int, int]: + return self._num_nodes_min_max + + @property + def connections_scaling_param(self) -> float: + return self._connections_scaling_param + + def GenerateOne(self) -> 'ControlFlowGraph': + """Create a random CFG. + + Returns: + A ControlFlowGraph instance. + """ + num_nodes = self.rand.randint(*self.num_nodes_min_max) + + nodes = [cfg.ControlFlowGraph(NumberToLetters(i)) for i in range(num_nodes)] + for node in nodes: + node.all_nodes = nodes + adjacency_matrix = ( + self.rand.rand(num_nodes, num_nodes) * self.connections_scaling_param) + adjacency_matrix = np.clip(adjacency_matrix, 0, 1) + adjacency_matrix = np.rint(adjacency_matrix) + # CFG nodes cannot be connected to self. + for i in range(len(adjacency_matrix)): + adjacency_matrix[i][i] = 0 + for j, row in enumerate(adjacency_matrix): + for i, col in enumerate(row): + if col: + nodes[j].children.add(nodes[i]) + for i, node in enumerate(nodes): + if not node.children: + j = i + while j == i: + j = self.rand.randint(0, len(nodes) - 1) + node.children.add(nodes[j]) + return nodes[0] diff --git a/experimental/compilers/reachability/control_flow_graph_generator_test.py b/experimental/compilers/reachability/control_flow_graph_generator_test.py new file mode 100644 index 000000000..cd3bb73e3 --- /dev/null +++ b/experimental/compilers/reachability/control_flow_graph_generator_test.py @@ -0,0 +1,67 @@ +"""Unit tests for :control_flow_graph_generator.""" +import sys +import typing + +import pytest +from absl import app +from absl import flags + +from experimental.compilers.reachability import control_flow_graph_generator + + +FLAGS = flags.FLAGS + + +def test_UniqueNameSequence_next(): + """Test iterator interface.""" + g = control_flow_graph_generator.UniqueNameSequence('a') + assert next(g) == 'a' + assert next(g) == 'b' + assert next(g) == 'c' + + +def test_UniqueNameSequence_StringInSequence_single_char(): + """Test single character sequence output.""" + g = control_flow_graph_generator.UniqueNameSequence('a') + assert g.StringInSequence(0) == 'a' + assert g.StringInSequence(1) == 'b' + assert g.StringInSequence(2) == 'c' + assert g.StringInSequence(25) == 'z' + + +def test_UniqueNameSequence_StringInSequence_multi_char(): + """Test multi character sequence output.""" + g = control_flow_graph_generator.UniqueNameSequence('a') + assert g.StringInSequence(26) == 'aa' + assert g.StringInSequence(27) == 'ab' + assert g.StringInSequence(28) == 'ac' + + +def test_UniqueNameSequence_StringInSequence_prefix(): + """Test prefix.""" + g = control_flow_graph_generator.UniqueNameSequence('a', prefix='prefix_') + assert g.StringInSequence(0) == 'prefix_a' + + +def test_UniqueNameSequence_StringInSequence_base_char(): + """Test different base char.""" + g = control_flow_graph_generator.UniqueNameSequence('A') + assert g.StringInSequence(0) == 'A' + + +def test_UniqueNameSequence_StringInSequence_invalid_base_char(): + """Test that invalid base char raises error.""" + with pytest.raises(ValueError): + control_flow_graph_generator.UniqueNameSequence('AA') + + +def main(argv: typing.List[str]): + """Main entry point.""" + if len(argv) > 1: + raise app.UsageError("Unknown arguments: '{}'.".format(' '.join(argv[1:]))) + sys.exit(pytest.main([__file__, '-vv'])) + + +if __name__ == '__main__': + flags.FLAGS(['argv[0]', '-v=1']) + app.run(main) diff --git a/experimental/compilers/reachability/control_flow_graph_test.py b/experimental/compilers/reachability/control_flow_graph_test.py new file mode 100644 index 000000000..c4ad9f1b8 --- /dev/null +++ b/experimental/compilers/reachability/control_flow_graph_test.py @@ -0,0 +1,127 @@ +"""Unit tests for //experimental/compilers/reachability:control_flow_graph.""" +import sys +import typing + +import networkx as nx +import pytest +from absl import app +from absl import flags + +from experimental.compilers.reachability import control_flow_graph + + +FLAGS = flags.FLAGS + + +def test_ControlFlowGraph_IsReachable_reachable(): + """Test reachable node.""" + g = control_flow_graph.ControlFlowGraph() + g.add_edge(0, 1) + assert g.IsReachable(0, 1) + + +def test_ControlFlowGraph_IsReachable_indirectly_reachable(): + """Test indirectly reachable node.""" + g = control_flow_graph.ControlFlowGraph() + g.add_edge(0, 1) + g.add_edge(1, 2) + assert g.IsReachable(0, 2) + + +def test_ControlFlowGraph_IsReachable_unreachable(): + """Test unreachable node.""" + g = control_flow_graph.ControlFlowGraph() + g.add_edge(0, 1) + assert not g.IsReachable(1, 0) + + +def test_ControlFlowGraph_IsReachable_non_existent_node_raises_error(): + """Test that error is raised if node is not in graph.""" + g = control_flow_graph.ControlFlowGraph() + with pytest.raises(nx.exception.NetworkXError): + g.IsReachable(1, 0) + + +def test_ControlFlowGraph_Reachables_empty_graph(): + """An empty graph has no reachables.""" + g = control_flow_graph.ControlFlowGraph() + assert list(g.Reachables(0)) == [] + + +def test_ControlFlowGraph_Reachables_self_loop(): + """A self loop makes a node reachable.""" + g = control_flow_graph.ControlFlowGraph() + g.add_edge(0, 0) + assert list(g.Reachables(0)) == [True] + + +def test_ControlFlowGraph_Reachables_simple_graph(): + """An empty graph has no reachables.""" + g = control_flow_graph.ControlFlowGraph() + g.add_edge(0, 1) + g.add_edge(1, 2) + assert list(g.Reachables(0)) == [False, True, True] + assert list(g.Reachables(1)) == [False, False, True] + assert list(g.Reachables(2)) == [False, False, False] + + +def test_ControlFlowGraph_Reachables_back_edge(): + """Test reachability with a back edge in the graph.""" + g = control_flow_graph.ControlFlowGraph() + g.add_edge(0, 1) + g.add_edge(1, 0) + g.add_edge(1, 2) + assert list(g.Reachables(0)) == [False, True, True] # FIXME + assert list(g.Reachables(1)) == [True, False, True] # FIXME + assert list(g.Reachables(2)) == [False, False, False] + + +def test_ControlFlowGraph_IsValidControlFlowGraph_empty_graph(): + """Test that empty graph is invalid.""" + g = control_flow_graph.ControlFlowGraph() + assert not g.IsValidControlFlowGraph() + + +def test_ControlFlowGraph_IsValidControlFlowGraph_disconnected_graph(): + """Test simple_.""" + g = control_flow_graph.ControlFlowGraph() + g.add_node(0, name='A') + g.add_node(1, name='B') + # FIXME: assert not g.IsValidControlFlowGraph() + + +def test_ControlFlowGraph_IsValidControlFlowGraph_unamed_nodes(): + """Test simple_.""" + g = control_flow_graph.ControlFlowGraph() + g.add_edge(0, 1) + assert not g.IsValidControlFlowGraph() + + +def test_ControlFlowGraph_IsValidControlFlowGraph_duplicate_names(): + """Test simple_.""" + g = control_flow_graph.ControlFlowGraph() + g.add_node(0, name='A') + g.add_node(1, name='A') + g.add_edge(0, 1) + assert not g.IsValidControlFlowGraph() + + +def test_ControlFlowGraph_IsValidControlFlowGraph_valid_graph(): + """Test that a simple graph is valid.""" + g = control_flow_graph.ControlFlowGraph() + g.add_node(0, name='A') + g.add_node(1, name='B') + g.add_edge(0, 1) + assert g.IsValidControlFlowGraph() + + +def main(argv: typing.List[str]): + """Main entry point.""" + if len(argv) > 1: + raise app.UsageError("Unknown arguments: '{}'.".format(' '.join(argv[1:]))) + sys.exit(pytest.main([__file__, '-vv'])) + + +if __name__ == '__main__': + flags.FLAGS(['argv[0]', '-v=1']) + app.run(main) diff --git a/experimental/compilers/reachability/notebooks/BUILD b/experimental/compilers/reachability/notebooks/BUILD new file mode 100644 index 000000000..6ef732040 --- /dev/null +++ b/experimental/compilers/reachability/notebooks/BUILD @@ -0,0 +1,10 @@ +# Jupyter notebook with project dependencies. + +py_binary( + name = "notebooks", + srcs = ["//notebooks"], + deps = [ + "//experimental/compilers/reachability:control_flow_graph", + "//experimental/compilers/reachability:control_flow_graph_generator", + ], +) diff --git a/experimental/compilers/reachability/notebooks/run_notebook.sh b/experimental/compilers/reachability/notebooks/run_notebook.sh new file mode 100644 index 000000000..f4c60ef21 --- /dev/null +++ b/experimental/compilers/reachability/notebooks/run_notebook.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Script to run Jupyter notebook server from root of the source tree. +set -eux + +# The --run_under argument runs the Jupyter server from the root of the source +# tree rather than the root of the build tree. +bazel run --run_under="cd \"$(pwd)\"; " \ + //experimental/compilers/reachability/notebooks diff --git a/experimental/compilers/reachability/proto/BUILD b/experimental/compilers/reachability/proto/BUILD deleted file mode 100644 index bf15f6644..000000000 --- a/experimental/compilers/reachability/proto/BUILD +++ /dev/null @@ -1,10 +0,0 @@ -# Protocol buffers for DeepSmith. - -load("@org_pubref_rules_protobuf//python:rules.bzl", "py_proto_library") - -py_proto_library( - name = "reachability_py_pb2", - protos = ["reachability.proto"], - visibility = ["//experimental/compilers/reachability:__subpackages__"], - deps = ["//third_party/py/protobuf"], -) diff --git a/experimental/compilers/reachability/proto/reachability.proto b/experimental/compilers/reachability/reachability.proto similarity index 99% rename from experimental/compilers/reachability/proto/reachability.proto rename to experimental/compilers/reachability/reachability.proto index 9d86eae93..a15e69f7a 100644 --- a/experimental/compilers/reachability/proto/reachability.proto +++ b/experimental/compilers/reachability/reachability.proto @@ -1,6 +1,7 @@ // Protos for reachability analysis. syntax = "proto2"; + package phd.experimental.compilers.reachability; message ControlFlowGraphNode { diff --git a/experimental/compilers/reachability/reachability.py b/experimental/compilers/reachability/reachability.py index 8aae2b308..89b849a55 100644 --- a/experimental/compilers/reachability/reachability.py +++ b/experimental/compilers/reachability/reachability.py @@ -1,16 +1,11 @@ """A generator for Control Flow Graphs.""" import pathlib -import random -import typing -import numpy as np from absl import app from absl import flags -from experimental.compilers.reachability.proto import reachability_pb2 -from labm8 import fmt +from experimental.compilers.reachability import control_flow_graph from labm8 import fs -from labm8 import graph as libgraph FLAGS = flags.FLAGS @@ -31,119 +26,12 @@ 'Path to dot file to generate.') -def NumberToLetters(num: int) -> str: - """Convert number to name, e.g. 0 -> 'A', 1 -> 'B'.""" - if num >= 26: - raise ValueError - return chr(ord('A') + num) - - -class ControlFlowGraph(libgraph.Graph): - """A control flow graph.""" - - def __init__(self, name: str): - super(ControlFlowGraph, self).__init__(name) - self.all_nodes: typing.List['ControlFlowGraph'] = None - - def _IsReachable(self, node: 'ControlFlowGraph', visited) -> bool: - visited.add(self) - if node == self: - return True - else: - for child in self.children: - if child not in visited: - if child._IsReachable(node, visited): - return True - return False - - def IsReachable(self, node: 'ControlFlowGraph') -> bool: - """Return whether a node is reachable.""" - return self._IsReachable(node, set()) - - @classmethod - def GenerateRandom(cls, num_nodes: int, - connections_scaling_param: float = 1.0, - seed: typing.Optional[int] = None) -> 'ControlFlowGraph': - """Create a random CFG. - - Args: - num_nodes: The number of CFG nodes. - connections_scaling_param: Scaling parameter to use to determine the - likelihood of edges between CFG nodes. - seed: Random number seed. - - Returns: - A ControlFlowGraph instance. - """ - if isinstance(seed, int): - np.random.seed(seed) - random.seed(seed) - nodes = [cls(NumberToLetters(i)) for i in range(num_nodes)] - for node in nodes: - node.all_nodes = nodes - adjacency_matrix = ( - np.random.rand(num_nodes, num_nodes) * connections_scaling_param) - adjacency_matrix = np.clip(adjacency_matrix, 0, 1) - adjacency_matrix = np.rint(adjacency_matrix) - # CFG nodes cannot be connected to self. - for i in range(len(adjacency_matrix)): - adjacency_matrix[i][i] = 0 - for j, row in enumerate(adjacency_matrix): - for i, col in enumerate(row): - if col: - nodes[j].children.add(nodes[i]) - for i, node in enumerate(nodes): - if not node.children: - j = i - while j == i: - j = random.randint(0, len(nodes) - 1) - node.children.add(nodes[j]) - return nodes[0] - - def ToSuccessorsList(self) -> str: - """Get a list of successors for all nodes in the graph.""" - s = [] - for node in self.all_nodes: - successors = ' '.join(child.name for child in sorted(node.children)) - s.append(f'{node.name}: {successors}\n') - return ''.join(s) - - def ToDot(self) -> str: - """Get dot syntax graph.""" - strings = [] - for node in self.all_nodes: - strings += [f'{node.name} -> {child}' for child in node.children] - dot = fmt.IndentList(2, strings) - return f"digraph graphname {{\n {dot}\n}}" - - def Reachables(self) -> typing.List[bool]: - """Return whether each node is reachable from the root node.""" - src = self.all_nodes[0] - return [src.IsReachable(node) for node in self.all_nodes] - - def SetCfgWithReachabilityProto( - self, proto: reachability_pb2.CfgWithReachability) -> None: - """Set proto fields from graph instance.""" - for node in self.all_nodes: - proto_node = proto.graph.node.add() - proto_node.name = node.name - proto_node.child.extend([c.name for c in node.children]) - proto.reachable.extend(self.Reachables()) - - def ToCfgWithReachabilityProto( - self) -> reachability_pb2.CfgWithReachability: - """Create proto from graph instance.""" - data = reachability_pb2.CfgWithReachability() - self.SetCfgWithReachabilityProto(data) - return data - - def main(argv): """Main entry point.""" if len(argv) > 1: raise app.UsageError("Unknown arguments: '{}'.".format(' '.join(argv[1:]))) - graph = ControlFlowGraph.GenerateRandom( + graph = control_flow_graph.ControlFlowGraph.GenerateRandom( FLAGS.reachability_num_nodes, seed=FLAGS.reachability_seed, connections_scaling_param=FLAGS.reachability_scaling_param) diff --git a/experimental/compilers/reachability/train_model.py b/experimental/compilers/reachability/train_model.py index 14586dcea..9e8435e87 100644 --- a/experimental/compilers/reachability/train_model.py +++ b/experimental/compilers/reachability/train_model.py @@ -10,12 +10,12 @@ from absl import app from absl import flags from absl import logging +from experimental.compilers.reachability.proto import reachability_pb2 from keras.preprocessing import sequence from deeplearning.clgen import telemetry from deeplearning.clgen.corpuses import atomizers -from experimental.compilers.reachability import reachability -from experimental.compilers.reachability.proto import reachability_pb2 +from experimental.compilers.reachability import control_flow_graph from labm8 import pbutil @@ -58,15 +58,15 @@ def MakeReachabilityDataset( data = reachability_pb2.ReachabilityDataset() seed = 0 while len(data.entry) < num_data_points: - graph = reachability.ControlFlowGraph.GenerateRandom( + graph = control_flow_graph.ControlFlowGraph.GenerateRandom( FLAGS.reachability_num_nodes, seed=seed, connections_scaling_param=FLAGS.reachability_scaling_param) seed += 1 - seq = graph.ToSuccessorsList() + seq = graph.ToSuccessorsListString() if seq not in seqs: seqs.add(seq) proto = data.entry.add() - graph.SetCfgWithReachabilityProto(proto) + graph.SetProto(proto) proto.seed = seed return data @@ -108,7 +108,7 @@ def BuildKerasModel( x = keras.layers.Dense(dnn_size, activation='relu')(x) outs = [ keras.layers.Dense(1, activation='sigmoid', - name=reachability.NumberToLetters(i))(x) + name=control_flow_graph.NumberToLetters(i))(x) for i in range(num_classes) ]