in tensorflow_fold/blocks/blocks.py [0:0]
def _validate(self, compiler_ctx):
# pylint: disable=protected-access
# Sort children in topological order, and detect cycles.
topo_children = []
visited = {}
def visit(child):
"""Depth-first traversal."""
if child is self._input_ph:
return
visited[child] = 1 # mark as visiting for cycle detection
if child in self._child_input_wire_dict:
for (b, _) in self._child_input_wire_dict[child]:
if b in visited:
if visited[b] == 1:
raise ValueError('Composition cannot have cycles.')
else:
visit(b)
topo_children.append(child)
visited[child] = 2 # mark as visited
sinks = set(self.children)
for input_wires in six.itervalues(self._child_input_wire_dict):
for wire in input_wires:
sinks.discard(wire.block)
if self._output_wires:
for source, _ in self._output_wires:
if source not in visited: visit(source)
# Reorder sinks to match children to avoid nondeterminism.
sinks = [c for c in self.children if c in sinks]
# Find any children that were not reachable from the output.
for child in sinks:
assert child not in visited
visit(child)
self._children = topo_children
# TODO(delesley): write test cases for error conditions
self._child_input_wires = [[]]
self._child_to_index[self.input] = 0
for (i, b) in enumerate(self.children, 1):
# Find the list of input wires for child b
self._child_to_index[b] = i
in_wires = self._child_input_wire_dict.get(b, [])
# Set _child_input_wires for fast lookup during evaluation
self._child_input_wires.append(in_wires)
# Validate child, which will ensure it has an output type.
b._validate(compiler_ctx)
# Check that all child outputs are used.
unused = [b for b in sinks if not isinstance(b.output_type, tdt.VoidType)]
if unused:
raise TypeError('children have unused outputs: %s' %
', '.join(str(u) for u in unused))
# Corner case: set input type to Void if all children have Void input.
if self.input_type is None:
if all([isinstance(child.input_type, tdt.VoidType)
for child in self._children]):
self.set_input_type(tdt.VoidType())
# Check that composition has an input type.
self._check_input_type()
# Infer the composition output type.
if not (self._output_wires or isinstance(self.output_type, tdt.VoidType)):
# We could infer void output type here but more likely the user made a
# mistake, so we throw unless the VoidType was set explicitly.
raise TypeError('Composition block has no output: %s' % self)
self._check_output_type()