Type System¶
约 1062 个字 86 行代码 预计阅读时间 5 分钟
Taichi 是一门静态类型的编程语言,Taichi 中的变量类型是在编译时就确定的,一旦声明了变量,就不能再为其分配不同类型的值
Example
上述代码的最后一行会报错,因为
ti.Vector()
类型的值不能赋值给变量x
Taichi 中的ti.types
模块定义了所有 Taichi 支持的数据类型,这些数据类型分为两类 : 基本类型 (primitive) 和复合类型 (compound)
- 基本类型包括常用的数值数据类型,比如
ti.i32(int32)
,ti.u8(uint8)
, 和ti.f64(float64)
- 复合类型包括类似数组或类似结构的数据类型,这些类型由多个成员组成,这些成员可以是基本类型,也可以是其他复合类型,比如
ti.types.matrix
,ti.types.ndarray
, 和ti.types.struct
基本类型 ¶
用i
表示有符号整数,u
表示无符号整数,f
表示浮点数,后面跟的位数可以是 8,16,32,64,最常用的两种基本类型为
i32
: 32 位有符号整数,也是默认的整数类型f32
: 32 位浮点数,也是默认的浮点数类型
需要注意,不同 backend 对 Taichi 基本类型的支持会有所不同,详见下表:
Taichi 允许在调用ti.init()
时指定默认的基本数据类型,用法如下:
ti.init(default_ip=ti.i64) # Sets the default integer type to ti.i64
ti.init(default_fp=ti.f64) # Sets the default floating-point type to ti.f64
在应用中如果要保持数据的高精度,建议将
default_fp
设置为ti.F64
数据类型别名 ¶
在 Taichi scope 中,int
和float
会被分别用作默认整数和浮点类型的别名
ti.init(default_ip=ti.i64, default_fp=ti.f64)
@ti.kernel
def example_cast() -> int: # the returned type is ti.i64
x = 3.14 # x is of ti.f64 type
y = int(x) # equivalent to ti.i64(x)
return y
在 Python scope 中,创建一个 Taichi 的 data container 并指定类型时,使用的也是别名
除了 Taichi scope 和 Python scope 创建的 Taichi data container 以外,
int
和float
作为 Python 中的内置函数
显式类型转换 ¶
可以用ti.cast()
函将给定值转换为特定的目标类型
还有一种更方便的方式,使用基本类型直接转换
@ti.kernel
def foo():
a = 3.14
x = int(a) # 3
y = float(a) # 3.14
z = ti.i32(a) # 3
w = ti.f64(a) # 3.14
隐式类型转换 ¶
在 Taichi 里,隐式类型转换发生在二元操作和赋值操作中
Warning
隐式类型转换通常是 bug 产生的来源,因此不推荐使用隐式类型转换,而是显式地指定变量类型和传入的数据
隐式类型转换的规则如下:
有一些例外:
- 逻辑运算的返回值类型为
i32
- 比较运算的返回值类型为
i32
赋值操作中发生的隐式类型转换
将变量
a
的值从int 1
转成float 1.0
将变量
a
的值从float 3.14
转成int 3
由此可见,初始化时的变量类型决定了隐式类型转换的结果
复合类型 ¶
矩阵和向量 ¶
可以用ti.types.matrix()
和ti.types.vector()
来自定义创建矩阵和向量数据类型
Example
在上述代码中,我们分别创建了两个类型
vec4d
: 元素为 64 位浮点数的 4 维向量类型mat4x3i
: 元素为整数的 4x3 矩阵类型
可以利用自定义的复合类型来实例化向量和矩阵,以及作为函数参数的数据类型
Example
结构体和数据类 (dataclass) ¶
可以用ti.types.struct()
函数来创建一个结构体类型,以下是一个创建球体类型 ( sphere_type
) 的例子
Example
# Define a compound type vec3 to represent a sphere's center
vec3 = ti.types.vector(3, float)
# Define a compound type sphere_type to represent a sphere
sphere_type = ti.types.struct(center=vec3, radius=float)
# Initialize sphere1, whose center is at [0,0,0] and whose radius is 1.0
sphere1 = sphere_type(center=vec3([0, 0, 0]), radius=1.0)
# Initialize sphere2, whose center is at [1,1,1] and whose radius is 1.0
sphere2 = sphere_type(center=vec3([1, 1, 1]), radius=1.0)
如果定义的结构体有很多成员变量的时候,使用ti.types.struct
会导致代码混乱、组织性很差,这个时候可以用一个修饰器ti.dataclass
,它包装了 struct 类型
使用ti.dataclass
还可以让我们在数据类中定义成员函数,从而实现 OOP 的功能
初始化 ¶
Taichi 中有很多初始化 struct 或者 dataclass 的方式,除了直接调用类型进行实例化之外,还可以用以下几种方式:
- 按照定义的参数顺序将位置参数传递给类型
- 利用关键字参数设置特定的成员变量
- 未指定的成员变量将被自动设置为 0
Example
@ti.dataclass
class Ray:
ro: vec3
rd: vec3
t: float
# The definition above is equivalent to
#Ray = ti.types.struct(ro=vec3, rd=vec3, t=float)
# Use positional arguments to set struct members in order
ray = Ray(vec3(0), vec3(1, 0, 0), 1.0)
# ro is set to vec3(0) and t will be set to 0
ray = Ray(vec3(0), rd=vec3(1, 0, 0))
# both ro and rd are set to vec3(0)
ray = Ray(t=1.0)
# ro is set to vec3(1), rd=vec3(0) and t=0.0
ray = Ray(1)
# All members are set to 0
ray = Ray()
类型转换 ¶
目前 Taichi 的复合类型中只有 vector 和 matrix 支持类型转换,并且是 element-wise 的
Example