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] Support matrix initialization with a list of vectors #811

Merged
merged 35 commits into from
Apr 18, 2020
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0ea865a
dynamic range support at num_threads = 1
archibate Apr 14, 2020
9df3e7e
add test
archibate Apr 14, 2020
098556e
better TI_DEBUG
archibate Apr 14, 2020
df11e62
no print accessor glsl
archibate Apr 14, 2020
3fa88a7
fix test_loop_args_as_range
archibate Apr 14, 2020
15bde3b
fix long-lasting state-leakage (related to the multi-offloading bug)
archibate Apr 14, 2020
7d9d33a
add ScopeIndent
archibate Apr 14, 2020
c085c96
Merge branch 'master' into dyn
archibate Apr 15, 2020
22a5324
[skip ci] no ad-hoc
archibate Apr 15, 2020
c5c7059
[skip ci] pre
archibate Apr 15, 2020
68bea5e
dyn range = dyn work group size
archibate Apr 15, 2020
e384922
[skip ci] clean
archibate Apr 15, 2020
12d8869
[skip ci] nit
archibate Apr 16, 2020
3b85e4a
fix long-lasting NV-GL-not-preserving-data issue
archibate Apr 16, 2020
1bd1887
map/unmap gtmp for dyn range
archibate Apr 16, 2020
ca2c318
[skip travis] fix win-build
archibate Apr 16, 2020
5f136ca
[skip travis] fix non-GL again
archibate Apr 17, 2020
3e8aed7
[skip travis] fix
archibate Apr 17, 2020
ea17448
[skip travis] apply reviews
archibate Apr 17, 2020
da33271
use class RangeSizeEvaluator_
archibate Apr 17, 2020
5cc25d1
[skip ci] revert mpm128
archibate Apr 17, 2020
eb629bb
[skip ci] nit: move rse
archibate Apr 17, 2020
a84208d
[skip ci] enforce code format
taichi-gardener Apr 17, 2020
76e4026
[OpenGL] Support range for-loops with non-constant bounds (#785)
yuanming-hu Apr 17, 2020
919bfdb
support matrix init form vectors and add test
Apr 17, 2020
95c55bc
support matrix init form vectors and add test
Apr 17, 2020
8dd4914
require row/cols when initializing matrix with list of vectors, updat…
Apr 18, 2020
2ed28ea
merge
Apr 18, 2020
fdd1255
fix merge
Apr 18, 2020
5e7ddd1
[skip ci] enforce code format
taichi-gardener Apr 18, 2020
a6dbda1
update doc
Apr 18, 2020
96c3692
Merge branch 'vec_to_matrix' of https://github.com/KLozes/taichi into…
Apr 18, 2020
00fe2a6
update doc 2
Apr 18, 2020
5e2b4aa
update docs and more input value checking for matrix init
Apr 18, 2020
197d5a6
[skip ci] enforce code format
taichi-gardener Apr 18, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
143 changes: 142 additions & 1 deletion docs/linalg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,145 @@ Matrices
- ``R, S = ti.polar_decompose(A, ti.f32)``
- ``U, sigma, V = ti.svd(A, ti.f32)`` (Note that ``sigma`` is a ``3x3`` diagonal matrix)

TODO: doc here better like Vector.
TODO: doc here better like Vector. WIP

A matrix in Taichi can have two forms:

- as a temporary local variable. An ``n by m`` matrix consists of ``n * m`` scalar values.
- as a an element of a global tensor. In this case, the tensor is an ND array of ``n by m`` matrices.
KLozes marked this conversation as resolved.
Show resolved Hide resolved

Declaration
-----------

As global tensors of matrices
++++++++++++++++++++++++++++

.. function:: ti.Matrix(n, m, dt=type, shape=shape)

:parameter n: (scalar) the number of rows in the matrix
:parameter m: (scalar) the number of columns in the matrix
:parameter type: (DataType) data type of the components
:parameter shape: (scalar or tuple) shape the tensor of vectors, see :ref:`tensor`

For example, this creates a 5x4 tensor of 3x3 matrices:
::

# Python-scope
a = ti.Matrix(3, 3, dt=ti.f32, shape=(5, 4))

.. note::

In Python-scope, ``ti.var`` declares :ref:`scalar_tensor`, while ``ti.Matrix`` declares tensors of matrices.


As a temporary local variable
+++++++++++++++++++++++++++++

.. function:: ti.Matrix([x, y, ...])

:parameter x: (scalar) the first component of the vector
:parameter y: (scalar) the second component of the vector

For example, this creates a 3x1 matrix with components (2, 3, 4):
::

# Taichi-scope
a = ti.Matrix([2, 3, 4])

.. note::

this is equivalent to ti.Vector([x, y, ...])


.. function:: ti.Matrix([[x, y, ...], [z, w, ...], ...])

:parameter x: (scalar) the first component of the first column
KLozes marked this conversation as resolved.
Show resolved Hide resolved
:parameter y: (scalar) the second component of the first column
:parameter z: (scalar) the first component of the second column
:parameter w: (scalar) the second component of the second column

For example, this creates a 2x2 matrix with components (2, 3) in the first column and (4, 5) in the second column:
KLozes marked this conversation as resolved.
Show resolved Hide resolved
::

# Taichi-scope
a = ti.Matrix([[2, 3], [4, 5])


.. function:: ti.Matrix(rows=[v0, v1, v2, ...])

:parameter v0: (vector) vector of elements forming first row (or column)
:parameter v1: (vector) vector of elements forming second row (or column)
:parameter v2: (vector) vector of elements forming third row (or column)

For example, this creates a 3x3 matrix by concactinating vectors into rows (or columns):
::

# Taichi-scope
v0 = ti.Vector([1.0, 2.0, 3.0])
v1 = ti.Vector([4.0, 5.0, 6.0])
v2 = ti.Vector([7.0, 8.0, 9.0])

# to specify data in rows
a = ti.Matrix(rows=[v0, v1, v2])

# to specify data in columns instead
a = ti.Matrix(cols=[v0, v1, v2])

# lists can be used instead of vectors
a = ti.Matrix(rows=[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]])


Accessing components
--------------------

As global tensors of vectors
++++++++++++++++++++++++++++
.. attribute:: a[p, q, ...][i, j]

:parameter a: (tensor of matrices) the tensor of matrices
:parameter p: (scalar) index of the first tensor dimension
:parameter q: (scalar) index of the second tensor dimension
:parameter i: (scalar) row index of the matrix
:parameter j: (scalar) column index of the matrix

This extracts the first component of vector ``a[6, 3]``:
::

x = a[6, 3][0]

# or
vec = a[6, 3]
x = vec[0]

.. note::

**Always** use two pair of square brackets to access scalar elements from tensors of matrices.

- The indices in the first pair of brackets locate the matrix inside the tensor of matrices;
- The indices in the second pair of brackets locate the scalar element inside the matrix.

For 0-D tensors of matrices, indices in the first pair of brackets should be ``[None]``.



As a temporary local variable
+++++++++++++++++++++++++++++

.. attribute:: a[i, j]

:parameter a: (Matrix) the matrix
:parameter i: (scalar) row index of the matrix
:parameter j: (scalar) column index of the matrix

For example, this extracts the element in row 0 column 1 of matrix ``a``:
::

x = a[0, 1]

This sets the element in row 1 column 3 of ``a`` to 4:
::

a[1, 3] = 4

Methods
-------
19 changes: 9 additions & 10 deletions docs/vector.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ Vectors

A vector in Taichi can have two forms:

- as a temporary local variable, an ``n``-D vector consists of ``n`` scalar values.
- as a global tensor, where each tensor element is a vector. In this case, an ``n``-D vector consists of ``n`` global tensors of scalars.
The tensors of scalars, when treated together, can be considered to be **a global tensor of vectors**.
- as a temporary local variable. An ``n`` component vector consists of ``n`` scalar values.
- as an element of a global tensor. In this case, the tensor is an ND array of ``n`` component vectors
KLozes marked this conversation as resolved.
Show resolved Hide resolved

Declaration
-----------
Expand All @@ -21,7 +20,7 @@ As global tensors of vectors
:parameter type: (DataType) data type of the components
:parameter shape: (scalar or tuple) shape the tensor of vectors, see :ref:`tensor`

For example, this creates a 5x4 tensor of 3D vectors:
For example, this creates a 5x4 tensor of 3 component vectors:
::

# Python-scope
Expand Down Expand Up @@ -57,7 +56,7 @@ As global tensors of vectors
:parameter a: (Vector) the vector
:parameter p: (scalar) index of the first tensor dimension
:parameter q: (scalar) index of the second tensor dimension
:parameter i: (scalar) index of the vector dimension
:parameter i: (scalar) index of the vector component

This extracts the first component of vector ``a[6, 3]``:
::
Expand All @@ -72,8 +71,8 @@ As global tensors of vectors

**Always** use two pair of square brackets to access scalar elements from tensors of vectors.

- The indices in the first pair of brackets locate the vector index inside the tensor of vectors;
- The indices in the second pair of brackets locate the scalar element index inside the vector.
- The indices in the first pair of brackets locate the vector inside the tensor of vectors;
- The indices in the second pair of brackets locate the scalar element inside the vector.

For 0-D tensors of vectors, indices in the first pair of brackets should be ``[None]``.

Expand Down Expand Up @@ -136,8 +135,8 @@ Methods

.. function:: ti.cross(a, b)

:parameter a: (Vector, 3D)
:parameter b: (Vector, 3D)
:parameter a: (Vector, 3 component)
:parameter b: (Vector, 3 component)
:return: (Vector, 3D) the cross product of ``a`` and ``b``

We use right-handed coordinate system, E.g.,
Expand All @@ -163,7 +162,7 @@ Methods
# c = [[1*4, 1*5, 1*6], [2*4, 2*5, 2*6], [3*4, 3*5, 3*6]]

.. note::
This is not the same as `ti.cross`. ``a`` and ``b`` do not have to be 3D vectors.
This is not the same as `ti.cross`. ``a`` and ``b`` do not have to be 3 component vectors.


.. function:: a.cast(dt)
Expand Down
29 changes: 26 additions & 3 deletions python/taichi/lang/matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,36 @@ class Matrix:
is_taichi_class = True

def __init__(self,
n,
n=1,
m=1,
dt=None,
empty=False,
shape=None,
layout=None,
needs_grad=False,
keep_raw=False):
keep_raw=False,
rows=None,
cols=None):
self.grad = None
if isinstance(n, list):
if rows is not None or cols is not None:
KLozes marked this conversation as resolved.
Show resolved Hide resolved
if cols is not None:
rows = cols
self.n = len(rows)
if isinstance(rows[0], Matrix):
self.m = rows[0].n
self.entries = [row(i) for row in rows for i in range(row.n)]
elif isinstance(rows[0], list):
self.m = len(rows[0])
self.entries = [x for row in rows for x in row]
else:
raise Exception(
'rows/cols must be list of lists or list of vectors')
if cols is not None:
t = self.transposed(self)
self.n = t.n
self.m = t.m
self.entries = t.entries
elif isinstance(n, list):
if n == []:
mat = []
elif not isinstance(n[0], list):
Expand All @@ -40,6 +60,9 @@ def __init__(self,
mat = [list([expr.Expr(x)]) for x in n]
else:
mat = [[x] for x in n]
elif isinstance(n[0], Matrix):
raise Exception(
'cols/rows required when using list of vectors')
else:
mat = n
self.n = len(mat)
Expand Down
5 changes: 2 additions & 3 deletions taichi/transforms/ir_printer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,8 @@ class IRPrinter : public IRVisitor {
}

void visit(WhileControlStmt *stmt) override {
print("{} : while control {}, {}",
stmt->name(), stmt->mask ? stmt->mask->name() : "nullptr",
stmt->cond->name());
print("{} : while control {}, {}", stmt->name(),
stmt->mask ? stmt->mask->name() : "nullptr", stmt->cond->name());
}

void visit(ContinueStmt *stmt) override {
Expand Down
30 changes: 30 additions & 0 deletions tests/python/test_linalg.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,33 @@ def fill():
for i in range(3):
for j in range(3):
assert a[i][j] == int(i == j)


@ti.all_archs
def test_init_matrix_from_vectors():
m1 = ti.Matrix(3, 3, dt=ti.f32, shape=(3))
m2 = ti.Matrix(3, 3, dt=ti.f32, shape=(3))
m3 = ti.Matrix(3, 3, dt=ti.f32, shape=(3))
m4 = ti.Matrix(3, 3, dt=ti.f32, shape=(3))

@ti.kernel
def fill():
for i in range(3):
a = ti.Vector([1.0, 4.0, 7.0])
b = ti.Vector([2.0, 5.0, 8.0])
c = ti.Vector([3.0, 6.0, 9.0])
m1[i] = ti.Matrix(rows=[a, b, c])
m2[i] = ti.Matrix(cols=[a, b, c])
m3[i] = ti.Matrix(
rows=[[1.0, 4.0, 7.0], [2.0, 5.0, 8.0], [3.0, 6.0, 9.0]])
m4[i] = ti.Matrix(
cols=[[1.0, 4.0, 7.0], [2.0, 5.0, 8.0], [3.0, 6.0, 9.0]])

fill()

for j in range(3):
for i in range(3):
assert m1[0][i, j] == int(i + 3 * j + 1)
assert m2[0][j, i] == int(i + 3 * j + 1)
assert m3[0][i, j] == int(i + 3 * j + 1)
assert m4[0][j, i] == int(i + 3 * j + 1)