Beispiel #1
0
 def __str__(self):
     """Python scope struct array print support."""
     if impl.inside_kernel():
         item_str = ", ".join(
             [str(k) + "=" + str(v) for k, v in self.items])
         return f'<ti.Struct {item_str}>'
     return str(self.to_dict())
Beispiel #2
0
    def __call__(self, *args, **kwargs):
        args = _process_args(self, args, kwargs)

        if not impl.inside_kernel():
            if not self.pyfunc:
                raise TaichiSyntaxError(
                    "Taichi functions cannot be called from Python-scope.")
            return self.func(*args)

        if self.is_real_function:
            if impl.get_runtime(
            ).current_kernel.autodiff_mode != AutodiffMode.NONE:
                raise TaichiSyntaxError(
                    "Real function in gradient kernels unsupported.")
            instance_id, _ = self.mapper.lookup(args)
            key = _ti_core.FunctionKey(self.func.__name__, self.func_id,
                                       instance_id)
            if self.compiled is None:
                self.compiled = {}
            if key.instance_id not in self.compiled:
                self.do_compile(key=key, args=args)
            return self.func_call_rvalue(key=key, args=args)
        tree, ctx = _get_tree_and_ctx(
            self,
            is_kernel=False,
            args=args,
            ast_builder=impl.get_runtime().prog.current_ast_builder(),
            is_real_function=self.is_real_function)
        ret = transform_tree(tree, ctx)
        if not self.is_real_function:
            if self.return_type and ctx.returned != ReturnStatus.ReturnedValue:
                raise TaichiSyntaxError(
                    "Function has a return type but does not have a return statement"
                )
        return ret
Beispiel #3
0
 def z(self):
     """Get the third element of a matrix."""
     _taichi_skip_traceback = 1
     if impl.inside_kernel():
         return self.subscript(2)
     else:
         return self[2]
Beispiel #4
0
 def w(self):
     """Get the fourth element of a matrix."""
     _taichi_skip_traceback = 1
     if impl.inside_kernel():
         return self.subscript(3)
     else:
         return self[3]
Beispiel #5
0
 def y(self):
     """Get the second element of a matrix."""
     _taichi_skip_traceback = 1
     if impl.inside_kernel():
         return self.subscript(1)
     else:
         return self[1]
Beispiel #6
0
 def x(self):
     """Get the first element of a matrix."""
     _taichi_skip_traceback = 1
     if impl.inside_kernel():
         return self.subscript(0)
     else:
         return self[0]
Beispiel #7
0
    def fill(self, val):
        if impl.inside_kernel():

            def assign_renamed(x, y):
                return ti.assign(x, y)

            return self.element_wise_writeback_binary(assign_renamed, val)

        if isinstance(val, numbers.Number):
            val = tuple(
                [tuple([val for _ in range(self.m)]) for _ in range(self.n)])
        elif isinstance(val,
                        (list, tuple)) and isinstance(val[0], numbers.Number):
            assert self.m == 1
            val = tuple([(v, ) for v in val])
        if isinstance(val, Matrix):
            val_tuple = []
            for i in range(val.n):
                row = []
                for j in range(val.m):
                    row.append(val.get_entry(i, j))
                row = tuple(row)
                val_tuple.append(row)
            val = tuple(val_tuple)
        assert len(val) == self.n
        assert len(val[0]) == self.m
        from taichi.lang.meta import fill_matrix
        fill_matrix(self, val)
Beispiel #8
0
    def __call__(self, *args):
        _taichi_skip_traceback = 1
        if not impl.inside_kernel():
            if not self.pyfunc:
                raise TaichiSyntaxError(
                    "Taichi functions cannot be called from Python-scope."
                    " Use @ti.pyfunc if you wish to call Taichi functions "
                    "from both Python-scope and Taichi-scope.")
            return self.func(*args)

        if impl.get_runtime().experimental_ast_refactor:
            tree, global_vars = _get_tree_and_global_vars(self, args)
            visitor = ASTTransformerTotal(is_kernel=False,
                                          func=self,
                                          globals=global_vars)
            return visitor.visit(tree, *args)

        if impl.get_runtime().experimental_real_function:
            if impl.get_runtime().current_kernel.is_grad:
                raise TaichiSyntaxError(
                    "Real function in gradient kernels unsupported.")
            instance_id, arg_features = self.mapper.lookup(args)
            key = _ti_core.FunctionKey(self.func.__name__, self.func_id,
                                       instance_id)
            if self.compiled is None:
                self.compiled = {}
            if key.instance_id not in self.compiled:
                self.do_compile(key=key, args=args)
            return self.func_call_rvalue(key=key, args=args)
        else:
            if self.compiled is None:
                self.do_compile(key=None, args=args)
            ret = self.compiled(*args)
            return ret
Beispiel #9
0
    def __call__(self, *args):
        if not impl.inside_kernel():
            if not self.pyfunc:
                raise TaichiSyntaxError(
                    "Taichi functions cannot be called from Python-scope."
                    " Use @ti.pyfunc if you wish to call Taichi functions "
                    "from both Python-scope and Taichi-scope.")
            return self.func(*args)

        if impl.get_runtime().experimental_real_function:
            if impl.get_runtime().current_kernel.is_grad:
                raise TaichiSyntaxError(
                    "Real function in gradient kernels unsupported.")
            instance_id, _ = self.mapper.lookup(args)
            key = _ti_core.FunctionKey(self.func.__name__, self.func_id,
                                       instance_id)
            if self.compiled is None:
                self.compiled = {}
            if key.instance_id not in self.compiled:
                self.do_compile(key=key, args=args)
            return self.func_call_rvalue(key=key, args=args)
        tree, ctx = _get_tree_and_ctx(
            self,
            is_kernel=False,
            args=args,
            ast_builder=impl.get_runtime().prog.current_ast_builder())
        ret = transform_tree(tree, ctx)
        if not impl.get_runtime().experimental_real_function:
            if self.return_type and not ctx.returned:
                raise TaichiSyntaxError(
                    "Function has a return type but does not have a return statement"
                )
        return ret
Beispiel #10
0
 def set_entry(self, i, j, e):
     idx = self.linearize_entry_id(i, j)
     if impl.inside_kernel():
         self.entries[idx].assign(e)
     else:
         if isinstance(self.entries[idx], SNodeHostAccess):
             self.entries[idx].accessor.setter(e, *self.entries[idx].key)
         else:
             self.entries[idx] = e
Beispiel #11
0
 def __call__(self, *args):
     _taichi_skip_traceback = 1
     if not impl.inside_kernel():
         if not self.pyfunc:
             raise TaichiSyntaxError(
                 "Taichi functions cannot be called from Python-scope."
                 " Use @ti.pyfunc if you wish to call Taichi functions "
                 "from both Python-scope and Taichi-scope.")
         return self.func(*args)
     if self.compiled is None:
         self.do_compile()
     ret = self.compiled(*args)
     return ret
Beispiel #12
0
    def __str__(self):
        """Python scope matrix print support."""
        if impl.inside_kernel():
            '''
            It seems that when pybind11 got an type mismatch, it will try
            to invoke `repr` to show the object... e.g.:

            TypeError: make_const_expr_f32(): incompatible function arguments. The following argument types are supported:
                1. (arg0: float) -> taichi_core.Expr

            Invoked with: <Taichi 2x1 Matrix>

            So we have to make it happy with a dummy string...
            '''
            return f'<{self.n}x{self.m} ti.Matrix>'
        else:
            return str(self.to_numpy())
Beispiel #13
0
    def fill(self, val):
        """Fill the element with values.

        Args:
            val (Union[Number, List, Tuple, Matrix]): the dimension of val should be consistent with the dimension of element.

        Examples:

            Fill a scalar field:

            >>> v = ti.field(float,10)
            >>> v.fill(10.0)

            Fill a vector field:

            >>> v = ti.Vector.field(2, float,4)
            >>> v.fill([10.0,11.0])

        """
        if impl.inside_kernel():

            def assign_renamed(x, y):
                return ti.assign(x, y)

            return self.element_wise_writeback_binary(assign_renamed, val)

        if isinstance(val, numbers.Number):
            val = tuple(
                [tuple([val for _ in range(self.m)]) for _ in range(self.n)])
        elif isinstance(val,
                        (list, tuple)) and isinstance(val[0], numbers.Number):
            assert self.m == 1
            val = tuple([(v, ) for v in val])
        if isinstance(val, Matrix):
            val_tuple = []
            for i in range(val.n):
                row = []
                for j in range(val.m):
                    row.append(val.get_entry(i, j))
                row = tuple(row)
                val_tuple.append(row)
            val = tuple(val_tuple)
        assert len(val) == self.n
        assert len(val[0]) == self.m
        from taichi.lang.meta import fill_matrix
        fill_matrix(self, val)
Beispiel #14
0
 def __str__(self):
     if impl.inside_kernel():
         return self.__repr__()  # make pybind11 happy, see Matrix.__str__
     else:
         return str(self.to_numpy())
Beispiel #15
0
def in_taichi_scope():
    return impl.inside_kernel()
Beispiel #16
0
 def __str__(self):
     """Python scope field print support."""
     if impl.inside_kernel():
         return '<ti.Expr>'  # make pybind11 happy, see Matrix.__str__
     else:
         return str(self.to_numpy())
Beispiel #17
0
 def new(cls, n, m):
     if impl.inside_kernel():
         return cls(n, m)
     else:
         return cls.empty(n, m)
Beispiel #18
0
    def __init__(self,
                 n=1,
                 m=1,
                 dt=None,
                 shape=None,
                 offset=None,
                 empty=False,
                 layout=Layout.AOS,
                 needs_grad=False,
                 keep_raw=False,
                 disable_local_tensor=False,
                 rows=None,
                 cols=None):
        self.local_tensor_proxy = None
        self.any_array_access = None
        self.grad = None

        # construct from rows or cols (deprecated)
        if rows is not None or cols is not None:
            warning(
                f"ti.Matrix(rows=[...]) or ti.Matrix(cols=[...]) is deprecated, use ti.Matrix.rows([...]) or ti.Matrix.cols([...]) instead.",
                DeprecationWarning,
                stacklevel=2)
            if rows is not None and cols is not None:
                raise Exception("cannot specify both rows and columns")
            self.dt = dt
            mat = Matrix.cols(cols) if cols is not None else Matrix.rows(rows)
            self.n = mat.n
            self.m = mat.m
            self.entries = mat.entries
            return

        elif empty == True:
            warning(
                f"ti.Matrix(n, m, empty=True) is deprecated, use ti.Matrix.empty(n, m) instead",
                DeprecationWarning,
                stacklevel=2)
            self.dt = dt
            self.entries = [[None] * m for _ in range(n)]
            return

        elif isinstance(n, (list, tuple, np.ndarray)):
            if len(n) == 0:
                mat = []
            elif isinstance(n[0], Matrix):
                raise Exception(
                    'cols/rows required when using list of vectors')
            elif not isinstance(n[0], Iterable):
                if impl.inside_kernel():
                    # wrap potential constants with Expr
                    if keep_raw:
                        mat = [list([x]) for x in n]
                    else:
                        if in_python_scope(
                        ) or disable_local_tensor or not ti.current_cfg(
                        ).dynamic_index:
                            mat = [list([expr.Expr(x)]) for x in n]
                        else:
                            if not ti.is_extension_supported(
                                    ti.cfg.arch, ti.extension.dynamic_index):
                                raise Exception(
                                    'Backend ' + str(ti.cfg.arch) +
                                    ' doesn\'t support dynamic index')
                            if dt is None:
                                if isinstance(n[0], int):
                                    dt = impl.get_runtime().default_ip
                                elif isinstance(n[0], float):
                                    dt = impl.get_runtime().default_fp
                                else:
                                    raise Exception(
                                        'dt required when using dynamic_index for local tensor'
                                    )
                            self.local_tensor_proxy = impl.expr_init_local_tensor(
                                [len(n)], dt,
                                expr.make_expr_group([expr.Expr(x)
                                                      for x in n]))
                            mat = []
                            for i in range(len(n)):
                                mat.append(
                                    list([
                                        ti.local_subscript_with_offset(
                                            self.local_tensor_proxy, (i, ),
                                            (len(n), ))
                                    ]))
                else:
                    mat = [[x] for x in n]
            else:
                if in_python_scope(
                ) or disable_local_tensor or not ti.current_cfg(
                ).dynamic_index:
                    mat = [list(r) for r in n]
                else:
                    if not ti.is_extension_supported(
                            ti.cfg.arch, ti.extension.dynamic_index):
                        raise Exception('Backend ' + str(ti.cfg.arch) +
                                        ' doesn\'t support dynamic index')
                    if dt is None:
                        if isinstance(n[0][0], int):
                            dt = impl.get_runtime().default_ip
                        elif isinstance(n[0][0], float):
                            dt = impl.get_runtime().default_fp
                        else:
                            raise Exception(
                                'dt required when using dynamic_index for local tensor'
                            )
                    self.local_tensor_proxy = impl.expr_init_local_tensor(
                        [len(n), len(n[0])], dt,
                        expr.make_expr_group(
                            [expr.Expr(x) for row in n for x in row]))
                    mat = []
                    for i in range(len(n)):
                        mat.append([])
                        for j in range(len(n[0])):
                            mat[i].append(
                                ti.local_subscript_with_offset(
                                    self.local_tensor_proxy, (i, j),
                                    (len(n), len(n[0]))))
            self.n = len(mat)
            if len(mat) > 0:
                self.m = len(mat[0])
            else:
                self.m = 1
            self.entries = [x for row in mat for x in row]

        else:
            if dt is None:
                # create a local matrix with specific (n, m)
                self.entries = [impl.expr_init(None) for i in range(n * m)]
                self.n = n
                self.m = m
            else:
                # construct global matrix (deprecated)
                warning(
                    "Declaring global matrices using `ti.Matrix(n, m, dt, shape)` is deprecated, "
                    "use `ti.Matrix.field(n, m, dtype, shape)` instead",
                    DeprecationWarning,
                    stacklevel=2)
                mat = Matrix.field(n=n,
                                   m=m,
                                   dtype=dt,
                                   shape=shape,
                                   offset=offset,
                                   needs_grad=needs_grad,
                                   layout=layout)
                self.n = mat.n
                self.m = mat.m
                self.entries = mat.entries
                self.grad = mat.grad

        if self.n * self.m > 32:
            warning(
                f'Taichi matrices/vectors with {self.n}x{self.m} > 32 entries are not suggested.'
                ' Matrices/vectors will be automatically unrolled at compile-time for performance.'
                ' So the compilation time could be extremely long if the matrix size is too big.'
                ' You may use a field to store a large matrix like this, e.g.:\n'
                f'    x = ti.field(ti.f32, ({self.n}, {self.m})).\n'
                ' See https://taichi.readthedocs.io/en/stable/tensor_matrix.html#matrix-size'
                ' for more details.',
                UserWarning,
                stacklevel=2)
Beispiel #19
0
 def w(self):
     _taichi_skip_traceback = 1
     if impl.inside_kernel():
         return self.subscript(3)
     else:
         return self[3]
Beispiel #20
0
    def __init__(self,
                 n=1,
                 m=1,
                 dt=None,
                 shape=None,
                 offset=None,
                 empty=False,
                 layout=None,
                 needs_grad=False,
                 keep_raw=False,
                 rows=None,
                 cols=None):
        self.grad = None

        # construct from rows or cols (deprecated)
        if rows is not None or cols is not None:
            warning(
                f"ti.Matrix(rows=[...]) or ti.Matrix(cols=[...]) is deprecated, use ti.Matrix.rows([...]) or ti.Matrix.cols([...]) instead.",
                DeprecationWarning,
                stacklevel=2)
            if rows is not None and cols is not None:
                raise Exception("cannot specify both rows and columns")
            self.dt = dt
            mat = Matrix.cols(cols) if cols is not None else Matrix.rows(rows)
            self.n = mat.n
            self.m = mat.m
            self.entries = mat.entries
            return

        elif empty == True:
            warning(
                f"ti.Matrix(n, m, empty=True) is deprecated, use ti.Matrix.empty(n, m) instead",
                DeprecationWarning,
                stacklevel=2)
            self.dt = dt
            self.entries = [[None] * m for _ in range(n)]
            return

        elif isinstance(n, (list, tuple, np.ndarray)):
            if len(n) == 0:
                mat = []
            elif isinstance(n[0], Matrix):
                raise Exception(
                    'cols/rows required when using list of vectors')
            elif not isinstance(n[0], Iterable):
                if impl.inside_kernel():
                    # wrap potential constants with Expr
                    if keep_raw:
                        mat = [list([x]) for x in n]
                    else:
                        mat = [list([expr.Expr(x)]) for x in n]
                else:
                    mat = [[x] for x in n]
            else:
                mat = [list(r) for r in n]
            self.n = len(mat)
            if len(mat) > 0:
                self.m = len(mat[0])
            else:
                self.m = 1
            self.entries = [x for row in mat for x in row]

        else:
            if dt is None:
                # create a local matrix with specific (n, m)
                self.entries = [impl.expr_init(None) for i in range(n * m)]
                self.n = n
                self.m = m
            else:
                # construct global matrix (deprecated)
                warning(
                    "Declaring global matrices using `ti.Matrix(n, m, dt, shape)` is deprecated, "
                    "use `ti.Matrix.field(n, m, dtype, shape)` instead",
                    DeprecationWarning,
                    stacklevel=2)
                mat = Matrix.field(n=n,
                                   m=m,
                                   dtype=dt,
                                   shape=shape,
                                   offset=offset,
                                   needs_grad=needs_grad,
                                   layout=layout)
                self.n = mat.n
                self.m = mat.m
                self.entries = mat.entries
                self.grad = mat.grad

        if self.n * self.m > 32:
            warning(
                f'Taichi matrices/vectors with {self.n}x{self.m} > 32 entries are not suggested.'
                ' Matrices/vectors will be automatically unrolled at compile-time for performance.'
                ' So the compilation time could be extremely long if the matrix size is too big.'
                ' You may use a field to store a large matrix like this, e.g.:\n'
                f'    x = ti.field(ti.f32, ({self.n}, {self.m})).\n'
                ' See https://taichi.readthedocs.io/en/stable/tensor_matrix.html#matrix-size'
                ' for more details.',
                UserWarning,
                stacklevel=2)
Beispiel #21
0
 def set_entry(self, i, j, e):
     idx = self.linearize_entry_id(i, j)
     if impl.inside_kernel():
         self.entries[idx].assign(e)
     else:
         self.entries[idx] = e