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())
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
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]
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]
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]
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]
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)
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
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
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
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
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())
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)
def __str__(self): if impl.inside_kernel(): return self.__repr__() # make pybind11 happy, see Matrix.__str__ else: return str(self.to_numpy())
def in_taichi_scope(): return impl.inside_kernel()
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())
def new(cls, n, m): if impl.inside_kernel(): return cls(n, m) else: return cls.empty(n, m)
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)
def w(self): _taichi_skip_traceback = 1 if impl.inside_kernel(): return self.subscript(3) else: return self[3]
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)
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