Lecture02
Metaprogramming
产生最终实际运行程序的程序/编程方式
Metaprogramming in Taichi:
Unify the development of dimensionality-dependent code, such as 2D/3D physical simulations
Improve run-time performance by taking run-time costs to compile time
维度无关代码
Template
ti.template()
The Taichi kernels and functions with
ti.template()
arguments are template functionsTemplate functions are instantiated when needed. (Depends on the arguments.)
Allows you to pass "anything" supported by Taichi
Pass-by-reference, use with cautions
Computations in the Taichi scope can NOT modify Python scope data
Computations in the Taichi scope can modify Taichi fields
Computations in the Taichi scope can modify Taichi scope data 未使用模板时,由于是 pass-by-value 不会改变传入参数的值
Taichi kernels are instantiated whenever seeing a new parameter (even same typed) 根据变量的地址决定,如果为一个变量重新赋值,或者使用其他相同类型的变量,由于地址不同,Taichi 均会重新实例化模板函数
Dimension independent programming
ti.grouped()
@ti.kernel
def copy(x: ti.template(), y: ti.template()):
for I in ti.grouped(y):
# I is a vector with dimensionality same to y
# If y is 0D, then I = ti.Vector([]), which is equivalent to `None` used in x[I]
# If y is 1D, then I = ti.Vector([i])
# If y is 2D, then I = ti.Vector([i, j])
# If y is 3D, then I = ti.Vector([i, j, k])
# ...
x[I] = y[I]
Metadata
Field
field.dtype
: type of a fieldfield.shape
: shape of a field
Matrix / Vector
matrix.n
: rows of a matmatrix.m
: cols of a mat / vec
运行时性能
static
ti.static()
Compile-time branching
enable_projection = False
x = ti.field(ti.f32, shape=10)
@ti.kernel
def static():
if ti.static(enable_projection): # No runtime overhead
x[0] = 1
Forced loop unrolling for performance
@ti.kernel
def foo():
for i in ti.static(range(4)):
print(i)
# is equivalent to:
@ti.kernel
def foo():
print(0)
print(1)
print(2)
print(3)
Forced loop unrolling for element index access
Indices into compound Taichi types must be a compile-time constant
# Here we declare a field contains 8 vectors. Each vector contains 3 elements.
x = ti.Vector.field(3, ti.f32, shape=(8))
@ti.kernel
def reset():
for i in x:
for j in ti.static(range(x.n)):
# The inner loop must be unrolled since j is an index for accessing a vector
x[i][j] = 0
Object-oriented programming
Python OOP + Taichi DOP = ODOP
Objective data-oriented programming (ODOP)
@ti.data_oriented
class TaichiWheel:
def __init__(self, radius, width, rolling_fric):
self.radius = radius
self.width = width
self.rolling_fric = rolling_fric
self.pos = ti.Vector.field(3, ti.f32, shape=4)
@ti.kernel
def Roll(self):
...
@ti.func
def foo(self):
...
@ti.data_oriented
Compared with Python, the Taichi classes are more data_oriented:
Python class:
class PythonCelestialObject:
def __init__(self):
self.pos = ...
self.vel = ...
self.force = ...
Taichi class:
@ti.data_oriented
class CelestialObject:
def __init__(self):
self.pos = ti.Vector(2, ti.f32, shape = N)
self.vel = ti.Vector(2, ti.f32, shape = N)
self.force = ti.Vector(2, ti.f32, shape = N)
Taichi 更多使用面向数据的方法,因为使用数组计算效率更高
PDOP: Use Python scope variables in Taichi scope with caution
ODOP: Use Python scope members in Taichi scope with caution
Last updated