@staticmethod
    def build(op, a, b, out=None, **kwargs):
        """
        Build OpTreeNode.

        Arguments:
            a (OpTreeNode, Tensor, numeric): left-hand side operand.
            b (OpTreeNode, Tensor, numeric): right-hand side operand.
            out (Tensor, optional): where the result will be stored. If out is
                                    not None, the op-tree will be executed.
            kwargs: optional argument such as axis of the reducion.
        """
        # check type
        for arg in (a, b):
            if not isinstance(arg, (int, float, Tensor, OpTreeNode, type(None))):
                return NotImplemented
        # get shape
        out_shape = [1, 1]
        if isinstance(a, (OpTreeNode, Tensor)):
            a_shape = a.shape
        elif isinstance(a, (float, int)):
            a_shape = [1, 1]
        else:
            a_shape = [0, 0]
        if isinstance(b, (OpTreeNode, Tensor)):
            b_shape = b.shape
        elif isinstance(b, (float, int)):
            b_shape = [1, 1]
        else:
            b_shape = [0, 0]

        # TODO: fix shape in smarter way
        if len(a_shape) == 1:
            a_shape = a_shape + (1,)
        if len(b_shape) == 1:
            b_shape = b_shape + (1,)

        if op in OpCollection.ew_ops:
            for i in range(2):
                out_shape[i] = max(a_shape[i], b_shape[i])
        elif op in OpCollection.reduction_ops:
            if "axis" in kwargs:
                out_shape = list(a_shape)
                out_shape[kwargs["axis"]] = 1
            else:
                pass  # [1, 1]
        elif op == "assign":
            out_shape = a_shape
        elif op == "dot":
            assert (len(a_shape) == len(b_shape) and len(b_shape) == 2 and
                    a_shape[1] == b_shape[0])
            out_shape = (a_shape[0], b_shape[1])
        elif op == "transpose":
            assert b is None
            out_shape = tuple(reversed(a_shape))
        else:
            raise TypeError(op % "%s is not a valid operation")
        out_shape = tuple(out_shape)

        # build op dict
        op_dict = {"op": op, "shape": out_shape}
        op_dict.update(kwargs)

        node = OpTreeNode(op_dict, a, b)

        # execute explicit assignment
        if op == "assign":
            return node.execute()

        # passing in an out value counts as assignment
        if out is not None:
            return OpTreeNode({"op": "assign"}, out, node).execute()

        # delay execution until assignment
        return node
dataset/ETHPy150Open NervanaSystems/neon/neon/backends/backend.py/OpTreeNode.build/swapped operands of `%`