-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Sparse computation with kernels #902
Comments
Try
Thank for asking this! Sorry about the lacks a good doc on sparse data structures. To be honest as a org member I don't know how to operate them well either...
Let me try to tell something I know about solving this:
will mark
|
import taichi as ti
ti.init()
n = 256
x = ti.var(ti.f32)
blk1 = ti.root.bitmasked(ti.ij, (n, n))
blk1.place(x)
@ti.kernel
def act():
for i in range(n):
for j in range(n):
if (i>100)&(i<125)&(j>100)&(j<125):
# NOTE: all elements in bitmasked is initially deactivated
# So we have to **activate those elements we want**
# Instead of **deactivate those elements we don't want** (your case)
x[i, j] = 0 # assign any value to activate!
@ti.kernel
def paint(t: ti.f32):
for i, j in x: # use the struct-for syntax
# now, the loop body is only executed for active elements
# don't use: for i in range(n), it will execute on all element no matter it's active or not (your case)
x[i, j] = ti.sin(t) # make the activated part to blink
act()
gui = ti.GUI('Test', n)
for frame in range(10000):
paint(frame * 0.01)
gui.set_image(x)
gui.show() Hope this could be helpful. |
Is there a way to deactivate all elements at once, without range iterating over the entire structure? taichi/examples/taichi_sparse.py Line 87 in 6751bd5
|
Yes, it does :) |
Thanks a lot @archibate
How do you then run a struct for only on the bitmasked part of the structure ?
but again limited success :) |
Good question. You can do this by only activating import taichi as ti
ti.init()
n = 256
steps = 3
x = ti.var(ti.f32)
img = ti.var(ti.f32, shape=(n, n))
blk1 = ti.root.dense(ti.l, steps).bitmasked(ti.ij, (n, n))
blk1.place(x)
@ti.kernel
def act():
for i, j in ti.ndrange(n, n):
if (i>100)&(i<125)&(j>100)&(j<125):
x[0, i, j] = 0 # activate `x[0, i, j]`, but not activate `x[1, i, j]`.
@ti.kernel
def paint(n: ti.f32):
for t, i, j in x: # although t is included in indices, but it will be always 0 since only x[0, i, j] is activated in act()
x[t, i, j] = ti.sin(n)
@ti.kernel
def to2dimg():
for i, j in img:
img[i, j] = x[0, i, j] # convert to make gui.set_image() recognize
ti.root.deactivate_all()
act()
gui = ti.GUI('Test', n)
for frame in range(10000):
paint(frame * 0.01)
to2dimg()
gui.set_image(img)
gui.show() |
I think what @archibate said is really close, but slightly off from what @mathusalem2020 wants, since s/he does want How about define a mask taichi tensor, which is x = ti.var(ti.f32)
x_mask = ti.var(ti.i32)
ti.root.bitmasked(ti.ij, (n, n)).place(x_mask)
ti.root.dense(ti.l, steps).dense(ti.ij, (n, n)).place(x)
@ti.kernel
def act():
for i, j in ti.ndrange(n, n):
if ...:
x_mask[i, j] = 1 # the value doesn't matter, just to activate
@ti.kernel
def diffuse(t: ti.i32):
for i, j in x_mask: # will only iterate over those activated in |x_mask|
x[t, i, j] = ...
act()
for i in range(steps):
diffuse(i)
... One nice thing is that, the struct-for loop will only return you the index, but not the actual element of the tensor being iterated. So you can leverage the sparsity from one tensor for iterating over another, I think. |
A simpler way to write this: @ti.kernel
def act():
for I in ti.grouped(ti.ndrange(1, (101, 125), (101, 125))):
x[I] = 0 |
Cool! Your answer sounds much close. But there is two things to consider for your solution:
|
Yeah, then I guess a static mask variable won’t work. In that case, I’m not sure if sparse data structure is advantageous in any way, since you will have to iterate through the entire mesh grid to figure out which places to activate for every
I suppose you meant the other way around? That’s true, but I don’;t see memory being a major concern in this issue. |
> 1. What if we want to maintain a mask for different t?
Yeah, then I guess a static mask variable won’t work. In that case, I’m not sure if sparse data structure is advantageous in any way, since you will have to iterate through the entire mesh grid to figure out which places to activate?
No, I mean do we have something like `for i, j in x[0, :, :]`?
Since for each `t` the bitmasked is independent, this should be possible.
> 2. If we use `pointer` instead of `bitmasked`, then this won't save any memory since `x` is still `dense`.
I suppose you meant the other way around? That’s true, but I don’;t see memory being a major concern in this issue.
Yes, what if it's a major concern?
|
Dear Community,
If I were to simulate diffusion over a 2D grid with a square hole in the middle, how could I make use of sparse structures to avoid populating my kernel with a bunch of if statements ?
For completeness' sake, I pasted here a working example of a diffusion that avoids a central square hole. This runs in my jupyter notebook.
The concentration field that is updated at every time step, p(), is dense. So I need to tell the kernel to explicitly avoid that region, and also avoid (or rebuild) the initial condition (the borders).
To be honest, I tried playing around from the examples in the test functions for sparse structures, but to no avail. I tried for example this approach:
It does not work. Also, I do not understand how to play with pointers. ti.root.pointer(ti.ij,16).dense(ti.ij,16).shape is (256,256), and not (16,16,16,16). Etc.
Long story short, I have no idea how to play with sparse data structures. I was not successful at deactivating elements, or playing with the bitmasked structures.
Eventually, I would like to iteratively solve an extremely sparse linear system, where handling the datastructure correctly would come in real handy.
Let me know if I should rather post this on the forum.
The text was updated successfully, but these errors were encountered: