From f38d4951f6265ab6f9659515a39e18030b6a94fe Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Wed, 3 Jun 2020 17:00:19 +0800 Subject: [PATCH 1/7] [Lang] [refactor] shows an error if not called from correct Taichi/Python-scope --- python/taichi/lang/expr.py | 13 +++++++++++-- python/taichi/lang/matrix.py | 35 +++++++++++++++++++++++++++++++++-- python/taichi/lang/util.py | 26 ++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/python/taichi/lang/expr.py b/python/taichi/lang/expr.py index 83332b710f3b7..3009607755244 100644 --- a/python/taichi/lang/expr.py +++ b/python/taichi/lang/expr.py @@ -37,6 +37,7 @@ def __init__(self, *args, tb=None): self.grad = None self.val = self + @python_scope def __setitem__(self, key, value): if not Expr.layout_materialized: self.materialize_layout_callback() @@ -50,9 +51,8 @@ def __setitem__(self, key, value): (taichi_lang_core.get_max_num_indices() - len(key))) self.setter(value, *key) + @python_scope def __getitem__(self, key): - import taichi as ti - assert not ti.get_runtime().inside_kernel if not Expr.layout_materialized: self.materialize_layout_callback() self.initialize_accessor() @@ -70,6 +70,7 @@ def loop_range(self): def serialize(self): return self.ptr.serialize() + @python_scope def initialize_accessor(self): if self.getter: return @@ -103,16 +104,19 @@ def setter(value, *key): self.getter = getter self.setter = setter + @python_scope def set_grad(self, grad): self.grad = grad self.ptr.set_grad(grad.ptr) + @python_scope def clear(self, deactivate=False): assert not deactivate node = self.ptr.snode().parent assert node node.clear_data() + @python_scope def fill(self, val): # TODO: avoid too many template instantiations from .meta import fill_tensor @@ -145,6 +149,7 @@ def shape(self): def data_type(self): return self.snode().data_type() + @python_scope def to_numpy(self): from .meta import tensor_to_ext_arr import numpy as np @@ -155,6 +160,7 @@ def to_numpy(self): ti.sync() return arr + @python_scope def to_torch(self, device=None): from .meta import tensor_to_ext_arr import torch @@ -166,6 +172,7 @@ def to_torch(self, device=None): ti.sync() return arr + @python_scope def from_numpy(self, arr): assert self.dim() == len(arr.shape) s = self.shape() @@ -178,9 +185,11 @@ def from_numpy(self, arr): import taichi as ti ti.sync() + @python_scope def from_torch(self, arr): self.from_numpy(arr.contiguous()) + @python_scope def copy_from(self, other): assert isinstance(other, Expr) from .meta import tensor_to_tensor diff --git a/python/taichi/lang/matrix.py b/python/taichi/lang/matrix.py index 14f45b8448c8c..f738217c48b79 100644 --- a/python/taichi/lang/matrix.py +++ b/python/taichi/lang/matrix.py @@ -3,7 +3,7 @@ import copy import numbers import numpy as np -from .util import to_numpy_type, to_pytorch_type, deprecated +from .util import * from .common_ops import TaichiOperations from collections.abc import Iterable @@ -144,6 +144,7 @@ def is_global(self): 0], "Matrices with mixed global/local entries are not allowed" return results[0] + @taichi_scope def element_wise_binary(self, foo, other): ret = self.empty_copy() if isinstance(other, (list, tuple)): @@ -163,12 +164,14 @@ def element_wise_binary(self, foo, other): ret.entries[i] = foo(self.entries[i], other) return ret + @taichi_scope def element_wise_unary(self, foo): ret = self.empty_copy() for i in range(self.n * self.m): ret.entries[i] = foo(self.entries[i]) return ret + @taichi_scope def __matmul__(self, other): assert self.m == other.n ret = Matrix(self.n, other.m) @@ -243,6 +246,7 @@ def __setitem__(self, key, value): self.mat(*key)[self.index] = value # host access + @python_scope def __getitem__(self, index): return Matrix.Proxy(self, index) ret = [[] for _ in range(self.n)] @@ -252,6 +256,7 @@ def __getitem__(self, index): return ret # host access + @python_scope def __setitem__(self, index, item): if not isinstance(item[0], list): item = [[i] for i in item] @@ -270,11 +275,13 @@ def copy(self): ret.entries = copy.copy(self.entries) return ret + @taichi_scope def variable(self): ret = self.copy() ret.entries = [impl.expr_init(e) for e in ret.entries] return ret + @taichi_scope def cast(self, dt): ret = self.copy() if type(dt) is type and issubclass(dt, numbers.Number): @@ -289,6 +296,7 @@ def cast(self, dt): ret.entries[i] = impl.cast(ret.entries[i], dt) return ret + @taichi_scope def trace(self): assert self.n == self.m sum = expr.Expr(self(0, 0)) @@ -296,6 +304,7 @@ def trace(self): sum = sum + self(i, i) return sum + @taichi_scope def inverse(self): assert self.n == self.m, 'Only square matrices are invertible' if self.n == 1: @@ -349,6 +358,7 @@ def E(x, y): inversed = deprecated('a.inversed()', 'a.inverse()')(inverse) + @taichi_scope def normalized(self, eps=0): assert self.m == 1 invlen = 1.0 / (Matrix.norm(self) + eps) @@ -363,6 +373,7 @@ def transposed(a): def T(self): return self.transpose() + @taichi_scope def transpose(a): ret = Matrix(a.m, a.n, empty=True) for i in range(a.n): @@ -370,6 +381,7 @@ def transpose(a): ret.set_entry(j, i, a(i, j)) return ret + @taichi_scope def determinant(a): if a.n == 2 and a.m == 2: return a(0, 0) * a(1, 1) - a(0, 1) * a(1, 0) @@ -429,32 +441,37 @@ def make_grad(self): ret.entries[i] = self.entries[i].grad return ret + @taichi_scope def sum(self): ret = self.entries[0] for i in range(1, len(self.entries)): ret = ret + self.entries[i] return ret + @taichi_scope def norm(self, l=2, eps=0): assert l == 2 return impl.sqrt(self.norm_sqr() + eps) - # TODO: avoid using sqr here since people might consider "sqr" as "square root". New name TBD. + @taichi_scope def norm_sqr(self): return (self**2).sum() + @taichi_scope def max(self): ret = self.entries[0] for i in range(1, len(self.entries)): ret = impl.max(ret, self.entries[i]) return ret + @taichi_scope def min(self): ret = self.entries[0] for i in range(1, len(self.entries)): ret = impl.min(ret, self.entries[i]) return ret + @taichi_scope def any(self): import taichi as ti ret = (self.entries[0] != ti.expr_init(0)) @@ -462,6 +479,7 @@ def any(self): ret = ret + (self.entries[i] != ti.expr_init(0)) return -(ret < ti.expr_init(0)) + @taichi_scope def all(self): import taichi as ti ret = self.entries[0] != ti.expr_init(0) @@ -497,6 +515,7 @@ def assign_renamed(x, y): from .meta import fill_matrix fill_matrix(self, val) + @python_scope def to_numpy(self, keep_dims=False): # Discussion: https://github.com/taichi-dev/taichi/pull/1046#issuecomment-633548858 as_vector = self.m == 1 and not keep_dims @@ -510,6 +529,7 @@ def to_numpy(self, keep_dims=False): ti.sync() return ret + @python_scope def to_torch(self, device=None, keep_dims=False): import torch as_vector = self.m == 1 and not keep_dims @@ -524,6 +544,7 @@ def to_torch(self, device=None, keep_dims=False): ti.sync() return ret + @python_scope def from_numpy(self, ndarray): if len(ndarray.shape) == self.loop_range().dim() + 1: as_vector = True @@ -538,9 +559,11 @@ def from_numpy(self, ndarray): import taichi as ti ti.sync() + @python_scope def from_torch(self, torch_tensor): return self.from_numpy(torch_tensor.contiguous()) + @taichi_scope def __ti_repr__(self): if self.m != 1: yield '[' @@ -559,18 +582,21 @@ def __ti_repr__(self): yield ']' @staticmethod + @taichi_scope def zero(dt, n, m=1): import taichi as ti return ti.Matrix([[ti.cast(0, dt) for _ in range(m)] for _ in range(n)]) @staticmethod + @taichi_scope def one(dt, n): import taichi as ti return ti.Matrix([[ti.cast(1, dt) for _ in range(n)] for _ in range(n)]) @staticmethod + @taichi_scope def unit(n, i, dt=None): import taichi as ti if dt is None: @@ -579,12 +605,14 @@ def unit(n, i, dt=None): return ti.Matrix([ti.cast(int(j == i), dt) for j in range(n)]) @staticmethod + @taichi_scope def identity(dt, n): import taichi as ti return ti.Matrix([[ti.cast(int(i == j), dt) for j in range(n)] for i in range(n)]) @staticmethod + @taichi_scope def rotation2d(alpha): import taichi as ti return ti.Matrix([[ti.cos(alpha), -ti.sin(alpha)], @@ -596,11 +624,13 @@ def __hash__(self): # using matrices as template arguments. return id(self) + @taichi_scope def dot(self, other): assert self.m == 1 assert other.m == 1 return (self.transpose() @ other).subscript(0, 0) + @taichi_scope def cross(self, b): if self.n == 3 and self.m == 1 and b.n == 3 and b.m == 1: return Matrix([ @@ -617,6 +647,7 @@ def cross(self, b): "Cross product is only supported between pairs of 2D/3D vectors" ) + @taichi_scope def outer_product(self, b): assert self.m == 1 assert b.m == 1 diff --git a/python/taichi/lang/util.py b/python/taichi/lang/util.py index cc03018c3146c..3b90f3a462994 100644 --- a/python/taichi/lang/util.py +++ b/python/taichi/lang/util.py @@ -177,3 +177,29 @@ def wrapped(*args, **kwargs): return wrapped return decorator + + +def taichi_scope(func): + import functools + from . import impl + + @functools.wraps(func) + def wrapped(*args, **kwargs): + assert impl.inside_kernel(), \ + f'{func.__name__} cannot be called in Python-scope' + return func(*args, **kwargs) + + return wrapped + + +def python_scope(func): + import functools + from . import impl + + @functools.wraps(func) + def wrapped(*args, **kwargs): + assert not impl.inside_kernel(), \ + f'{func.__name__} cannot be called in Taichi-scope' + return func(*args, **kwargs) + + return wrapped From 316a34a6d4fad58aff72906e7f0d95e3f02ee0dc Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Wed, 3 Jun 2020 19:03:49 +0800 Subject: [PATCH 2/7] [skip ci] fix deprecation warning (instead of raising error) --- python/taichi/lang/matrix.py | 6 +++++- python/taichi/lang/util.py | 3 +-- python/taichi/misc/gui.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/python/taichi/lang/matrix.py b/python/taichi/lang/matrix.py index f738217c48b79..59747b677ffb1 100644 --- a/python/taichi/lang/matrix.py +++ b/python/taichi/lang/matrix.py @@ -516,8 +516,12 @@ def assign_renamed(x, y): fill_matrix(self, val) @python_scope - def to_numpy(self, keep_dims=False): + def to_numpy(self, keep_dims=False, as_vector=None): # Discussion: https://github.com/taichi-dev/taichi/pull/1046#issuecomment-633548858 + if as_vector is not None: + import warnings + warnings.warn('v.to_numpy(as_vector=True) is deprecated, ' + 'please use v.to_numpy() directly instead', DeprecationWarning) as_vector = self.m == 1 and not keep_dims dim_ext = (self.n, ) if as_vector else (self.n, self.m) ret = np.empty(self.loop_range().shape() + dim_ext, diff --git a/python/taichi/lang/util.py b/python/taichi/lang/util.py index 3b90f3a462994..ead52db86b851 100644 --- a/python/taichi/lang/util.py +++ b/python/taichi/lang/util.py @@ -170,8 +170,7 @@ def decorator(foo): def wrapped(*args, **kwargs): import warnings msg = f'{old} is deprecated, please use {new} instead' - #warnings.warn(msg, DeprecationWarning) - raise DeprecationWarning(msg) + warnings.warn(msg, DeprecationWarning) return foo(*args, **kwargs) return wrapped diff --git a/python/taichi/misc/gui.py b/python/taichi/misc/gui.py index 7267d8eb8d65a..e4e36918de2e9 100644 --- a/python/taichi/misc/gui.py +++ b/python/taichi/misc/gui.py @@ -146,7 +146,7 @@ def show(self, file=None): self.core.update() if file: self.core.screenshot(file) - self.clear(self.background_color) + self.clear() class EventFilter: def __init__(self, *filter): From 031625c963ba7882d2a904c387d2a6c479883aa0 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Thu, 4 Jun 2020 08:19:48 +0800 Subject: [PATCH 3/7] also use deprecated deco for classkernel & classfunc --- python/taichi/lang/kernel.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/python/taichi/lang/kernel.py b/python/taichi/lang/kernel.py index b3375670e63d5..07537710a47dd 100644 --- a/python/taichi/lang/kernel.py +++ b/python/taichi/lang/kernel.py @@ -121,11 +121,8 @@ def extract_arguments(self): self.argument_names.append(param.name) +@deprecated('@ti.classfunc', '@ti.func directly') def classfunc(foo): - import warnings - warnings.warn('@ti.classfunc is deprecated. Please use @ti.func directly.', - DeprecationWarning) - func = Func(foo, classfunc=True) @functools.wraps(foo) @@ -545,11 +542,8 @@ def kernel(func): return _kernel_impl(func, level_of_class_stackframe=3) +@deprecated('@ti.classkernel', '@ti.kernel directly') def classkernel(func): - import warnings - warnings.warn( - '@ti.classkernel is deprecated. Please use @ti.kernel directly.', - DeprecationWarning) return _kernel_impl(func, level_of_class_stackframe=3) From b1741650476810e634ee707b7f9bbf233175bdcc Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Thu, 4 Jun 2020 08:20:31 +0800 Subject: [PATCH 4/7] [skip ci] format --- python/taichi/lang/matrix.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/python/taichi/lang/matrix.py b/python/taichi/lang/matrix.py index 59747b677ffb1..5e23018c6389a 100644 --- a/python/taichi/lang/matrix.py +++ b/python/taichi/lang/matrix.py @@ -520,8 +520,9 @@ def to_numpy(self, keep_dims=False, as_vector=None): # Discussion: https://github.com/taichi-dev/taichi/pull/1046#issuecomment-633548858 if as_vector is not None: import warnings - warnings.warn('v.to_numpy(as_vector=True) is deprecated, ' - 'please use v.to_numpy() directly instead', DeprecationWarning) + warnings.warn( + 'v.to_numpy(as_vector=True) is deprecated, ' + 'please use v.to_numpy() directly instead', DeprecationWarning) as_vector = self.m == 1 and not keep_dims dim_ext = (self.n, ) if as_vector else (self.n, self.m) ret = np.empty(self.loop_range().shape() + dim_ext, From cca4bc67e1314a96bf724dc838130f52125c5b59 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Thu, 4 Jun 2020 08:49:13 +0800 Subject: [PATCH 5/7] [skip ci] deprecation warning use stacklevel --- python/taichi/core/util.py | 4 ++++ python/taichi/lang/matrix.py | 3 ++- python/taichi/lang/util.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/python/taichi/core/util.py b/python/taichi/core/util.py index 8c97b36b3727d..c103382c7494a 100644 --- a/python/taichi/core/util.py +++ b/python/taichi/core/util.py @@ -3,6 +3,7 @@ import shutil import sys import ctypes +import warnings from pathlib import Path from colorama import Fore, Back, Style from taichi.misc.settings import get_output_directory, get_build_directory, get_bin_directory, get_repo_directory, get_runtime_directory @@ -13,6 +14,9 @@ print("Current Python version:", sys.version_info) exit(-1) +warnings.filterwarnings('always') + + ti_core = None diff --git a/python/taichi/lang/matrix.py b/python/taichi/lang/matrix.py index 5e23018c6389a..b1c1460f9366b 100644 --- a/python/taichi/lang/matrix.py +++ b/python/taichi/lang/matrix.py @@ -522,7 +522,8 @@ def to_numpy(self, keep_dims=False, as_vector=None): import warnings warnings.warn( 'v.to_numpy(as_vector=True) is deprecated, ' - 'please use v.to_numpy() directly instead', DeprecationWarning) + 'please use v.to_numpy() directly instead', + DeprecationWarning, stacklevel=3) as_vector = self.m == 1 and not keep_dims dim_ext = (self.n, ) if as_vector else (self.n, self.m) ret = np.empty(self.loop_range().shape() + dim_ext, diff --git a/python/taichi/lang/util.py b/python/taichi/lang/util.py index ead52db86b851..acbaa6634d6b1 100644 --- a/python/taichi/lang/util.py +++ b/python/taichi/lang/util.py @@ -170,7 +170,7 @@ def decorator(foo): def wrapped(*args, **kwargs): import warnings msg = f'{old} is deprecated, please use {new} instead' - warnings.warn(msg, DeprecationWarning) + warnings.warn(msg, DeprecationWarning, stacklevel=2) return foo(*args, **kwargs) return wrapped From 8f189beedae92eba28a2b1c04758be6f59459eec Mon Sep 17 00:00:00 2001 From: Taichi Gardener Date: Wed, 3 Jun 2020 20:53:26 -0400 Subject: [PATCH 6/7] [skip ci] enforce code format --- python/taichi/core/util.py | 1 - python/taichi/lang/matrix.py | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/taichi/core/util.py b/python/taichi/core/util.py index cd48d6efcb177..d4846f5be71a2 100644 --- a/python/taichi/core/util.py +++ b/python/taichi/core/util.py @@ -16,7 +16,6 @@ warnings.filterwarnings('always') - ti_core = None diff --git a/python/taichi/lang/matrix.py b/python/taichi/lang/matrix.py index b1c1460f9366b..dafc86a5a4fc7 100644 --- a/python/taichi/lang/matrix.py +++ b/python/taichi/lang/matrix.py @@ -523,7 +523,8 @@ def to_numpy(self, keep_dims=False, as_vector=None): warnings.warn( 'v.to_numpy(as_vector=True) is deprecated, ' 'please use v.to_numpy() directly instead', - DeprecationWarning, stacklevel=3) + DeprecationWarning, + stacklevel=3) as_vector = self.m == 1 and not keep_dims dim_ext = (self.n, ) if as_vector else (self.n, self.m) ret = np.empty(self.loop_range().shape() + dim_ext, From 39895bbc28be12068bb81e1659e3bf5895cafdd6 Mon Sep 17 00:00:00 2001 From: archibate <17721388340@163.com> Date: Thu, 4 Jun 2020 09:09:18 +0800 Subject: [PATCH 7/7] [skip ci] more taichi_scope --- python/taichi/lang/impl.py | 10 ++++++++++ python/taichi/lang/matrix.py | 1 + 2 files changed, 11 insertions(+) diff --git a/python/taichi/lang/impl.py b/python/taichi/lang/impl.py index 9ea33a94869da..617d089489b14 100644 --- a/python/taichi/lang/impl.py +++ b/python/taichi/lang/impl.py @@ -6,6 +6,7 @@ from .util import * +@taichi_scope def expr_init(rhs): import taichi as ti if rhs is None: @@ -29,6 +30,7 @@ def expr_init(rhs): return Expr(taichi_lang_core.expr_var(Expr(rhs).ptr)) +@taichi_scope def expr_init_func(rhs): # temporary solution to allow passing in tensors as import taichi as ti if isinstance(rhs, Expr) and rhs.ptr.is_global_var(): @@ -45,6 +47,7 @@ def wrap_scalar(x): return x +@taichi_scope def subscript(value, *indices): import numpy as np if isinstance(value, np.ndarray): @@ -76,6 +79,7 @@ def subscript(value, *indices): return Expr(taichi_lang_core.subscript(value.ptr, indices_expr_group)) +@taichi_scope def chain_compare(comparators, ops): assert len(comparators) == len(ops) + 1, \ f'Chain comparison invoked with {len(comparators)} comparators but {len(ops)} operators' @@ -180,6 +184,7 @@ def get_runtime(): return pytaichi +@taichi_scope def make_constant_expr(val): if isinstance(val, int): if pytaichi.default_ip == i32: @@ -229,6 +234,7 @@ def __getattribute__(self, item): root = Root() +@python_scope def var(dt, shape=None, offset=None, needs_grad=False): if isinstance(shape, numbers.Number): shape = (shape, ) @@ -277,6 +283,7 @@ def __init__(self, soa=False): AOS = Layout(soa=False) +@python_scope def layout(func): assert not pytaichi.materialized, "All layout must be specified before the first kernel launch / data access." warnings.warn( @@ -286,6 +293,7 @@ def layout(func): pytaichi.layout_functions.append(func) +@taichi_scope def ti_print(*vars): def entry2content(var): if isinstance(var, str): @@ -327,6 +335,7 @@ def fused_string(entries): taichi_lang_core.create_print(contentries) +@taichi_scope def ti_int(var): if hasattr(var, '__ti_int__'): return var.__ti_int__() @@ -334,6 +343,7 @@ def ti_int(var): return int(var) +@taichi_scope def ti_float(var): if hasattr(var, '__ti_float__'): return var.__ti_float__() diff --git a/python/taichi/lang/matrix.py b/python/taichi/lang/matrix.py index dafc86a5a4fc7..8e039e5b98480 100644 --- a/python/taichi/lang/matrix.py +++ b/python/taichi/lang/matrix.py @@ -215,6 +215,7 @@ def place(self, snode): for e in self.entries: snode.place(e) + @taichi_scope def subscript(self, *indices): if self.is_global(): ret = self.empty_copy()