Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Lang] Experimental sparse matrix support on CPUs #2792

Merged
merged 77 commits into from
Aug 28, 2021
Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
f4d15f9
add eigen
yuanming-hu Aug 10, 2021
05cde50
sparse matrix class
yuanming-hu Aug 10, 2021
a70566e
InternalFuncStmt with arguments
yuanming-hu Aug 10, 2021
9cc04d9
FrontendInternalFuncStmt
yuanming-hu Aug 10, 2021
2c13631
insert_triple test
yuanming-hu Aug 10, 2021
cf722e5
pass arguments
yuanming-hu Aug 10, 2021
8d2eedf
internal func call with multiple arguments
yuanming-hu Aug 10, 2021
45db6f4
frontend
yuanming-hu Aug 10, 2021
8b91c29
backend
yuanming-hu Aug 10, 2021
5aa0fbd
sparse_matrix.cpp
yuanming-hu Aug 10, 2021
0bbd154
bug fix
yuanming-hu Aug 10, 2021
a0abc24
build and print
yuanming-hu Aug 10, 2021
10dd0d3
syntax sugar
yuanming-hu Aug 10, 2021
c0802bd
enhance
yuanming-hu Aug 10, 2021
5a1eea7
linear solve
yuanming-hu Aug 10, 2021
462fac4
remove eigen for submodule
yuanming-hu Aug 10, 2021
d1cfe8b
Auto Format
taichi-gardener Aug 10, 2021
6f699ad
merge with master
yuanming-hu Aug 18, 2021
2e7ce7b
fix
yuanming-hu Aug 18, 2021
9c4d605
fixes
yuanming-hu Aug 18, 2021
c18c2b5
[ci] Reduce the number of python wheels built nightly (#2726)
Leonz5288 Aug 18, 2021
7d19225
Create Sparse Matrix Builder
FantasyVR Aug 23, 2021
bb3ae5a
SparseMatrix from SparseMatrix builder
FantasyVR Aug 23, 2021
3921cd9
Typo fix
FantasyVR Aug 23, 2021
56c529b
build sparse matrix with -=
FantasyVR Aug 23, 2021
ddf0198
move matrix from builder class to sparse matrix class
FantasyVR Aug 23, 2021
a131c03
Basic operations for Sparse Matrix
FantasyVR Aug 23, 2021
54e62ef
Bug fix
FantasyVR Aug 24, 2021
c8350f1
enhance
FantasyVR Aug 24, 2021
040b8dc
add sparse matrix test script
FantasyVR Aug 24, 2021
2da43a4
Merge branch 'master' into sparse
FantasyVR Aug 24, 2021
61f3e03
Auto Format
taichi-gardener Aug 24, 2021
7e1a967
Update program.cpp
FantasyVR Aug 24, 2021
7caee63
Update program.cpp
FantasyVR Aug 24, 2021
b6647da
Update program.cpp
FantasyVR Aug 24, 2021
8eac60c
Update kernel_impl.py
FantasyVR Aug 24, 2021
e9b5258
Update sparse_matrix.h
FantasyVR Aug 24, 2021
4afe913
Update sparse_matrix.h
FantasyVR Aug 24, 2021
0b4e6fe
Update sparse_matrix.cpp
FantasyVR Aug 24, 2021
4c87a8a
Update misc/sparse_matrix.py
FantasyVR Aug 24, 2021
d9f470a
Update python/taichi/lang/kernel_impl.py
FantasyVR Aug 24, 2021
e8b5d2b
Update python/taichi/lang/sparse_matrix.py
FantasyVR Aug 24, 2021
58eb9bc
Update sparse_matrix.cpp
FantasyVR Aug 24, 2021
8e4b6cf
Update sparse_matrix.py
FantasyVR Aug 24, 2021
5031b80
Update sparse_matrix.py
FantasyVR Aug 24, 2021
20cf407
Auto Format
taichi-gardener Aug 24, 2021
d6e354d
Update sparse_matrix.py
FantasyVR Aug 24, 2021
800580c
Update kernel_impl.py
FantasyVR Aug 24, 2021
e045a62
Fix windows bug
FantasyVR Aug 25, 2021
ca08509
Auto Format
taichi-gardener Aug 25, 2021
74e667e
Merge branch 'master' into sparse
FantasyVR Aug 25, 2021
a59c525
return std::unique_ptr
FantasyVR Aug 25, 2021
219f6b1
remove std::unique_ptr
FantasyVR Aug 25, 2021
09157b6
remove pointers and add matrix dimension assertion
FantasyVR Aug 25, 2021
144cc48
Auto Format
taichi-gardener Aug 25, 2021
9e125a5
build sparse matrix as return value
FantasyVR Aug 25, 2021
99a1aa9
Auto Format
taichi-gardener Aug 25, 2021
f3918f1
Update taichi/program/sparse_matrix.h
FantasyVR Aug 25, 2021
c3e5965
add __str__ and fix some nits
FantasyVR Aug 25, 2021
a198630
remove builder from program
FantasyVR Aug 26, 2021
e43069f
Auto Format
taichi-gardener Aug 26, 2021
744f923
Enhance
FantasyVR Aug 26, 2021
3901e21
Remove FrontendInternalStatement
FantasyVR Aug 26, 2021
ca7c1db
Auto Format
taichi-gardener Aug 26, 2021
e069487
Improve test script
FantasyVR Aug 26, 2021
83505d8
Improve test_sparse_matrix.py
FantasyVR Aug 26, 2021
5a0b9b9
Improve
FantasyVR Aug 26, 2021
18cb8fb
Enhance
FantasyVR Aug 27, 2021
13c2d7f
Test Improve
FantasyVR Aug 27, 2021
9d96335
Auto Format
taichi-gardener Aug 27, 2021
dad433a
Add left scalar-matrix multiplication
FantasyVR Aug 27, 2021
5bb5d4e
use alias sparse_matrix_builder as kernel args
FantasyVR Aug 28, 2021
5031d8f
Improve format and grammar
FantasyVR Aug 28, 2021
454cea2
Improve code format
FantasyVR Aug 28, 2021
4963026
Auto Format
taichi-gardener Aug 28, 2021
96bf95f
Update Nonsymmetric matrix multiplication
FantasyVR Aug 28, 2021
4b74365
Bug fix
FantasyVR Aug 28, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ if (TI_BUILD_TESTS)
include(cmake/TaichiTests.cmake)
endif()

include_directories(${PROJECT_SOURCE_DIR}/external/eigen)

message("C++ Flags: ${CMAKE_CXX_FLAGS}")
message("Build type: ${CMAKE_BUILD_TYPE}")

Expand Down
2 changes: 2 additions & 0 deletions cmake/TaichiCore.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ llvm_map_components_to_libnames(llvm_libs
)
target_link_libraries(${LIBRARY_NAME} ${llvm_libs})

include_directories(${LLVM_INCLUDE_DIRS})
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved

if (APPLE AND "${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "arm64")
llvm_map_components_to_libnames(llvm_aarch64_libs AArch64)
target_link_libraries(${LIBRARY_NAME} ${llvm_aarch64_libs})
Expand Down
60 changes: 60 additions & 0 deletions misc/sparse_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import taichi as ti
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved

ti.init(arch=ti.x64)

n = 8

K = ti.SparseMatrixBuilder(n, n, max_num_triplets=100)
f = ti.SparseMatrixBuilder(n, 1, max_num_triplets=100)


@ti.kernel
def fill(A: ti.SparseMatrixBuilder, b: ti.SparseMatrixBuilder,
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
interval: ti.i32):
for i in range(n):
if i > 0:
A[i - 1, i] += -1.0
A[i, i] += 1
if i < n - 1:
A[i + 1, i] += -1.0
A[i, i] += 1.0

if i % interval == 0:
b[i, 0] += 1.0


fill(K, f, 3)

print(">>>>>>>> Before build: ")
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
K.print_triplets()

A = K.build()

print(">>>>>>>> After build: ")
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
print(A)

print(">>>>>>> Summation Test: ")
C = A + A
print(C)

print(">>>> Subtraction Test")
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
D = A - A
print(D)

print(">>>> Multiplication with scalar")
E = A * 3.0
print(E)

print(">>>> Transpose Test")
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
F = A.transpose()
print(F)

print(">>>> Matrix Multiplication")
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
G = E @ A
print(G)

print(">>> Elment-wise Multiplication")
H = E * A
print(H)

print(f">>> Element Access: A[0,0] = {A[0,0]}")
1 change: 1 addition & 0 deletions python/taichi/lang/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from taichi.lang.ops import *
from taichi.lang.quant_impl import quant
from taichi.lang.runtime_ops import async_flush, sync
from taichi.lang.sparse_matrix import SparseMatrix, SparseMatrixBuilder
from taichi.lang.transformer import TaichiSyntaxError
from taichi.lang.type_factory_impl import type_factory
from taichi.lang.util import (has_pytorch, is_taichi_class, python_scope,
Expand Down
9 changes: 9 additions & 0 deletions python/taichi/lang/kernel_arguments.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from taichi.core.primitive_types import u64
from taichi.core.util import ti_core as _ti_core
from taichi.lang.enums import Layout
from taichi.lang.expr import Expr
from taichi.lang.ext_array import AnyArray, ExtArray
from taichi.lang.snode import SNode
from taichi.lang.sparse_matrix import SparseMatrixProxy
from taichi.lang.util import cook_dtype, to_taichi_type


Expand Down Expand Up @@ -129,6 +131,13 @@ def decl_ext_arr_arg(dtype, dim):
return ExtArray(_ti_core.make_external_tensor_expr(dtype, dim, arg_id))


def decl_sparse_matrix():
ptr_type = cook_dtype(u64)
# Treat sparse matrix argument as a scalar since we only need to pass in the base pointer
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
arg_id = _ti_core.decl_arg(ptr_type, False)
return SparseMatrixProxy(_ti_core.make_arg_load_expr(arg_id, ptr_type))


def decl_any_arr_arg(dtype, dim, element_shape, layout):
dtype = cook_dtype(dtype)
arg_id = _ti_core.decl_arg(dtype, True)
Expand Down
6 changes: 6 additions & 0 deletions python/taichi/lang/kernel_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from taichi.lang.kernel_arguments import any_arr, ext_arr, template
from taichi.lang.ndarray import ScalarNdarray
from taichi.lang.shell import _shell_pop_print, oinspect
from taichi.lang.sparse_matrix import SparseMatrixBuilder
from taichi.lang.transformer import ASTTransformerTotal
from taichi.misc.util import obsolete

Expand Down Expand Up @@ -368,6 +369,8 @@ def extract_arguments(self):
pass
elif id(annotation) in primitive_types.type_ids:
pass
elif id(annotation) == id(SparseMatrixBuilder):
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
pass
else:
_taichi_skip_traceback = 1
raise KernelDefError(
Expand Down Expand Up @@ -483,6 +486,9 @@ def func__(*args):
if not isinstance(v, int):
raise KernelArgError(i, needed.to_string(), provided)
launch_ctx.set_arg_int(actual_argument_slot, int(v))
elif id(needed) == id(SparseMatrixBuilder):
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
# Pass only the base pointer of the ti.SparseMatrixBuilder argument
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
launch_ctx.set_arg_int(actual_argument_slot, v.get_addr())
elif (isinstance(needed, (any_arr, ext_arr)) and self.match_ext_arr(v)) or \
(isinstance(needed, any_arr) and isinstance(v, ScalarNdarray)):
if isinstance(v, ScalarNdarray):
Expand Down
92 changes: 92 additions & 0 deletions python/taichi/lang/sparse_matrix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
class SparseMatrix:
def __init__(self, n=None, m=None, sm=None):
if sm is None:
self.n = n
self.m = m if m else n
from taichi.core.util import ti_core as _ti_core
self.matrix = _ti_core.create_sparse_matrix(n, m)
else:
self.n = sm.num_rows()
self.m = sm.num_cols()
self.matrix = sm

def __add__(self, other):
assert self.n == other.n and self.m == other.m, f"Dimension mismatch between sparse matrices ({self.n}, {self.m}), ({other.n}, {other.m})"
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
sm = self.matrix + other.matrix
return SparseMatrix(sm=sm)

def __sub__(self, other):
assert self.n == other.n and self.m == other.m, f"Dimension mismatch between sparse matrices ({self.n}, {self.m}), ({other.n}, {other.m})"
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
sm = self.matrix - other.matrix
return SparseMatrix(sm=sm)

def __mul__(self, other):
if isinstance(other, float):
sm = other * self.matrix
return SparseMatrix(sm=sm)
elif isinstance(other, SparseMatrix):
assert self.n == other.n and self.m == other.m, f"Dimension mismatch between sparse matrices ({self.n}, {self.m}), ({other.n}, {other.m})"
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
sm = self.matrix * other.matrix
return SparseMatrix(sm=sm)

def transpose(self):
sm = self.matrix.transpose()
return SparseMatrix(sm=sm)

def __matmul__(self, other):
sm = self.matrix.matmult(other.matrix)
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
return SparseMatrix(sm=sm)

def __getitem__(self, item):
return self.matrix.get_coeff(item[0], item[1])

def __str__(self):
return self.matrix.to_string()

def __repr__(self):
return self.matrix.to_string()


class SparseMatrixBuilder:
def __init__(self, n, m=None, max_num_triplets=0):
self.n = n
self.m = m if m else n
from taichi.core.util import ti_core as _ti_core
self.ptr = _ti_core.create_sparse_matrix_builder(
n, m, max_num_triplets)

def get_addr(self):
return self.ptr.get_addr()

def print_triplets(self):
self.ptr.print_triplets()

def build(self):
sm = self.ptr.build()
return SparseMatrix(sm=sm)


class SparseMatrixEntry:
def __init__(self, ptr, i, j):
self.ptr = ptr
self.i = i
self.j = j

def augassign(self, value, op):
from taichi.lang.impl import call_internal
if op == 'Add':
call_internal("insert_triplet", self.ptr, self.i, self.j, float(value))
elif op == 'Sub':
call_internal("insert_triplet", self.ptr, self.i, self.j, -value)
else:
assert False, f"Only operations '+=' and '-=' are supported on sparse matrices."


class SparseMatrixProxy:
FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
is_taichi_class = True
squarefk marked this conversation as resolved.
Show resolved Hide resolved

def __init__(self, ptr):
self.ptr = ptr

def subscript(self, i, j):
return SparseMatrixEntry(self.ptr, i, j)
7 changes: 7 additions & 0 deletions python/taichi/lang/stmt_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from taichi.lang.ast_resolver import ASTResolver
from taichi.lang.exception import TaichiSyntaxError
from taichi.lang.expr_builder import build_expr, build_exprs
from taichi.lang.sparse_matrix import SparseMatrixBuilder
from taichi.lang.util import to_taichi_type

import taichi as ti
Expand Down Expand Up @@ -555,6 +556,12 @@ def transform_as_kernel():
arg_init.value.args[0] = dt
arg_init.value.args[1] = parse_expr("{}".format(array_dim))
arg_decls.append(arg_init)
elif ctx.func.argument_annotations[i] is SparseMatrixBuilder:
arg_init = parse_stmt(
'x = ti.lang.kernel_arguments.decl_sparse_matrix()')
arg_init.targets[0].id = arg.arg
ctx.create_variable(arg.arg)
arg_decls.append(arg_init)
elif isinstance(ctx.func.argument_annotations[i], ti.any_arr):
arg_init = parse_stmt(
'x = ti.lang.kernel_arguments.decl_any_arr_arg(0, 0, 0, 0)'
Expand Down
16 changes: 16 additions & 0 deletions taichi/ir/frontend_ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,22 @@ class FrontendAssertStmt : public Stmt {
TI_DEFINE_ACCEPT
};

class FrontendInternalFuncStmt : public Stmt {
public:
std::string func_name;
std::vector<Expr> args;

FrontendInternalFuncStmt(const std::string &func_name,
std::vector<Expr> args_)
: func_name(func_name) {
for (auto &a : args_) {
args.push_back(load_if_ptr(a));
}
}

TI_DEFINE_ACCEPT
};

FantasyVR marked this conversation as resolved.
Show resolved Hide resolved
class FrontendAssignStmt : public Stmt {
public:
Expr lhs, rhs;
Expand Down
8 changes: 4 additions & 4 deletions taichi/program/kernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Kernel::LaunchContextBuilder::LaunchContextBuilder(Kernel *kernel)

void Kernel::LaunchContextBuilder::set_arg_float(int arg_id, float64 d) {
TI_ASSERT_INFO(!kernel_->args[arg_id].is_external_array,
"Assigning scalar value to external(numpy) array argument is "
"Assigning scalar value to external (numpy) array argument is "
"not allowed.");

ActionRecorder::get_instance().record(
Expand Down Expand Up @@ -198,7 +198,7 @@ void Kernel::LaunchContextBuilder::set_arg_float(int arg_id, float64 d) {

void Kernel::LaunchContextBuilder::set_arg_int(int arg_id, int64 d) {
TI_ASSERT_INFO(!kernel_->args[arg_id].is_external_array,
"Assigning scalar value to external(numpy) array argument is "
"Assigning scalar value to external (numpy) array argument is "
"not allowed.");

ActionRecorder::get_instance().record(
Expand Down Expand Up @@ -242,7 +242,7 @@ void Kernel::LaunchContextBuilder::set_arg_external_array(int arg_id,
uint64 size) {
TI_ASSERT_INFO(
kernel_->args[arg_id].is_external_array,
"Assigning external(numpy) array to scalar argument is not allowed.");
"Assigning external (numpy) array to scalar argument is not allowed.");

ActionRecorder::get_instance().record(
"set_kernel_arg_ext_ptr",
Expand All @@ -256,7 +256,7 @@ void Kernel::LaunchContextBuilder::set_arg_external_array(int arg_id,

void Kernel::LaunchContextBuilder::set_arg_raw(int arg_id, uint64 d) {
TI_ASSERT_INFO(!kernel_->args[arg_id].is_external_array,
"Assigning scalar value to external(numpy) array argument is "
"Assigning scalar value to external (numpy) array argument is "
"not allowed.");

if (!kernel_->is_evaluator) {
Expand Down
1 change: 1 addition & 0 deletions taichi/program/program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "taichi/program/snode_expr_utils.h"
#include "taichi/util/statistics.h"
#include "taichi/math/arithmetic.h"

#if defined(TI_WITH_CC)
#include "taichi/backends/cc/struct_cc.h"
#include "taichi/backends/cc/cc_layout.h"
Expand Down
1 change: 1 addition & 0 deletions taichi/program/program.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "taichi/system/memory_pool.h"
#include "taichi/system/threading.h"
#include "taichi/system/unified_allocator.h"
#include "taichi/program/sparse_matrix.h"

namespace taichi {
namespace lang {
Expand Down
Loading