def test_set_inputs_property(): in0 = Constant(0) in1 = Constant(1) value = Apply([in0], Graph()) value.inputs = [in1] assert in0.uses == set() assert in1.uses == {(value, 0)}
def test_del_inputs(index): in0 = Constant(0) in1 = Constant(1) value = Apply([in0, in1], Graph()) del value.inputs[index] assert in0.uses == set() assert in1.uses == {(value, 0)} assert value.inputs[0] is in1
def test_dfs_graphs(): g0 = Graph() in0 = Constant(g0) in1 = Constant(1) g0.return_ = in1 value = Apply([in0], Graph()) assert set(dfs(value)) == {value, in0} assert set(dfs(value, follow_graph=True)) == {value, in0, in1}
def test_set_inputs(index): in0 = Constant(0) in1 = Constant(1) value = Apply([in0], Graph()) value.inputs[index] = in1 assert value.inputs[0] is in1 assert in0.uses == set() assert in1.uses == {(value, 0)}
def test_slice_inputs(): in0 = Constant(0) in1 = Constant(1) value = Apply([in0, in1], Graph()) assert value.inputs[:] == [in0, in1] with pytest.raises(ValueError): del value.inputs[:] with pytest.raises(ValueError): value.inputs[:] = [in0]
def test_insert_inputs(index): in0 = Constant(0) in1 = Constant(1) value = Apply([in1], Graph()) value.inputs.insert(index, in0) assert value.inputs[0] is in0 assert value.inputs[1] is in1 assert in0.uses == {(value, 0)} assert in1.uses == {(value, 1)}
def test_toposort(): g0 = Graph() g0.output = Constant(1) g1 = Graph() in0 = Constant(g0) value = Apply([in0], g1) g1.output = value order = list(toposort(g1.return_)) _check_toposort(order, g1.return_, succ_incoming)
def test_toposort2(): g0 = Graph() g0.output = Constant(33) g1 = Graph() in0 = Constant(g0) in1 = Constant(1) v1 = Apply([in0, in1], g1) v2 = Apply([in0, v1, in1], g1) g1.output = v2 order = list(toposort(g1.return_)) _check_toposort(order, g1.return_, succ_incoming)
def test_helpers(): g = Graph() cg = Constant(g) assert is_constant_graph(cg) one = Constant(1) assert not is_constant_graph(one) assert is_constant(one) a = Apply([cg, one], g) assert is_apply(a) p = Parameter(g) assert is_parameter(p)
def test_str_coverage(): """Just a coverage test for __str__ and __repr__ Doesn't check that they take particular values since that could change easily. """ g = Graph() p = Parameter(g) p.name = 'param' objects = [g, Apply([], g), p, Parameter(g), Constant(0), Constant(g)] for o in objects: str(o) repr(o) o.debug.debug_name
def get_block_function(self, block: 'Block') -> Constant: """Return node representing the function corresponding to a block.""" if block in self.block_map: return self.block_map[block] node = Constant(block.graph) self.block_map[block] = node return node
def test_graph(): """Construct a small graph. Note that this graph is strictly speaking nonsensical, because it doesn't use any actual primitive operations. """ g = Graph() x = Parameter(g) assert x.value is PARAMETER one = Constant(1) add = Constant('add') return_ = Constant('return') value = Apply([add, x, one], g) return_ = Apply([return_, value], g) g.return_ = return_ g.parameters.append(x)
def test_graph_output(): g = Graph() with pytest.raises(Exception): print(g.output) one = Constant(1) g.output = one assert g.output is one assert isinstance(g.return_, Apply) and \ len(g.return_.inputs) == 2 and \ isinstance(g.return_.inputs[0], Constant) and \ g.return_.inputs[0].value is primops.return_ and \ g.return_.inputs[1] is one old_return = g.return_ two = Constant(2) g.output = two assert g.return_ is old_return assert g.return_.inputs[1] is two
def process_Return(self, block: 'Block', node: ast.Return) -> 'Block': """Process a return statement.""" inputs = [ Constant(primops.return_), self.process_node(block, node.value) ] return_ = Apply(inputs, block.graph) block.graph.return_ = return_ return block
def test_copy(): in0 = Constant(0) value0 = Apply([in0], Graph()) value1 = copy.copy(value0) in1 = copy.copy(in0) assert value1.inputs == value0.inputs assert value1.inputs is not value0.inputs assert in0.uses == {(value0, 0), (value1, 0)} assert in1.uses == set()
def process_Tuple(self, block: 'Block', node: ast.Tuple) -> ANFNode: """Process tuple literals.""" op = Constant(primops.cons_tuple) elts = [self.process_node(block, e) for e in node.elts] def cons(elts): if len(elts) == 0: return Constant(()) else: x, *rest = elts return Apply([op, x, cons(rest)], block.graph) return cons(elts)
def cond(self, cond: ANFNode, true: 'Block', false: 'Block') -> Apply: """Perform a conditional jump. This method will generate the call to the if expression and return its value. The predecessor blocks of the branches will be updated appropriately. Args: cond: The node representing the condition (true or false). true: The block to jump to if the condition is true. false: The block to jump to if the condition is false. """ inputs = [ Constant(primops.if_), cond, self.parser.get_block_function(true), self.parser.get_block_function(false) ] if_ = Apply(inputs, self.graph) inputs = [Constant(primops.return_), if_] return_ = Apply(inputs, self.graph) self.graph.return_ = return_ return return_
def write(targ, anf_node): if isinstance(targ, ast.Name): # CASE: x = value anf_node.debug.name = targ.id block.write(targ.id, anf_node) elif isinstance(targ, ast.Tuple): # CASE: x, y = value for i, elt in enumerate(targ.elts): op = self.environment.map(operator.getitem) new_node = Apply([op, anf_node, Constant(i)], block.graph) write(elt, new_node) else: raise NotImplementedError(node.targets) # pragma: no cover
def jump(self, target: 'Block') -> Apply: """Jumping from one block to the next becomes a tail call. This method will generate the tail call by calling the graph corresponding to the target block using an `Apply` node, and returning its value with a `Return` node. It will update the predecessor blocks of the target appropriately. Args: target: The block to jump to from this statement. """ jump = Apply([self.parser.get_block_function(target)], self.graph) self.jumps[target] = jump target.preds.append(self) inputs = [Constant(primops.return_), jump] return_ = Apply(inputs, self.graph) self.graph.return_ = return_ return return_
def map(self, obj: Any) -> ANFNode: """Map a Python object to an ANF node. If the object was already converted, the existing Myia node will be returned. """ if id(obj) in self._object_map: return self._object_map[id(obj)] elif isinstance(obj, (bool, float, int, str, primops.Primitive)): node = Constant(obj) self._object_map[id(obj)] = node return node elif isinstance(obj, FunctionType): parser = Parser(self, obj) # This will insert object into the map parser.parse() return self._object_map[id(obj)] else: raise ValueError(obj)
def __hrepr__(self, H, hrepr): """Return HTML representation (uses buche-cytoscape).""" if hrepr.config.depth > 1 and not hrepr.config.graph_expand_all: return hrepr(Constant(self)) dc = hrepr.config.duplicate_constants dfv = hrepr.config.duplicate_free_variables fin = hrepr.config.function_in_node fr = hrepr.config.follow_references tgen = hrepr.config.node_tooltip cgen = hrepr.config.node_class xsty = hrepr.config.graph_style gpr = MyiaGraphPrinter( {self}, duplicate_constants=True if dc is None else dc, duplicate_free_variables=True if dfv is None else dfv, function_in_node=True if fin is None else fin, follow_references=True if fr is None else fr, tooltip_gen=tgen, class_gen=cgen, extra_style=xsty) gpr.process() return gpr.__hrepr__(H, hrepr)
def test_incoming(): in0 = Constant(0) value = Apply([in0], Graph()) assert list(value.incoming) == [in0] assert list(in0.incoming) == []
def test_get_inputs(index): in0 = Constant(0) value = Apply([in0], Graph()) assert value.inputs[index] == in0
def test_outgoing(): in0 = Constant(0) value = Apply([in0], Graph()) assert list(value.outgoing) == [] assert list(in0.outgoing) == [value]
def test_dfs(): in0 = Constant(0) in1 = Constant(1) value = Apply([in0, in1], Graph()) assert next(dfs(value)) == value assert set(dfs(value)) == {value, in0, in1}
def coverage(self) -> Iterable[Graph]: """Return a collection of graphs accessible from the root.""" root: ANFNode = Constant(self.root) nodes = dfs(root, succ_deeper) return set(node.value if is_constant_graph(node) else node.graph for node in nodes) - {None}
def test_init_inputs(): in0 = Constant(0) value = Apply([in0], Graph()) assert in0.uses == {(value, 0)}
def test_len_inputs(): in0 = Constant(0) in1 = Constant(1) value = Apply([in0, in1], Graph()) assert len(value.inputs) == 2
def cons(elts): if len(elts) == 0: return Constant(()) else: x, *rest = elts return Apply([op, x, cons(rest)], block.graph)
def process_Attribute(self, block: 'Block', node: ast.Attribute) -> ANFNode: """Process attributes: `x.y`.""" op = self.environment.map(getattr) value = self.process_node(block, node.value) return Apply([op, value, Constant(node.attr)], block.graph)