gridpoints 1.0.2__tar.gz → 1.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gridpoints-1.0.2 → gridpoints-1.0.4}/PKG-INFO +27 -21
- {gridpoints-1.0.2 → gridpoints-1.0.4}/README.md +28 -22
- {gridpoints-1.0.2 → gridpoints-1.0.4}/pyproject.toml +1 -1
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/griddemo/__init__.py +1 -1
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/griddemo/quick_demo.py +3 -3
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/gridpoints/__init__.py +1 -1
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/gridpoints/array_libs.py +5 -6
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/gridpoints/mlg_sort.py +12 -16
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/gridpoints.egg-info/PKG-INFO +27 -21
- {gridpoints-1.0.2 → gridpoints-1.0.4}/LICENSE +0 -0
- {gridpoints-1.0.2 → gridpoints-1.0.4}/setup.cfg +0 -0
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/gridpoints/diagonal_tricks.py +0 -0
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/gridpoints/kdtree.py +0 -0
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/gridpoints.egg-info/SOURCES.txt +0 -0
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/gridpoints.egg-info/dependency_links.txt +0 -0
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/gridpoints.egg-info/requires.txt +0 -0
- {gridpoints-1.0.2 → gridpoints-1.0.4}/src/gridpoints.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gridpoints
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: fast multidimensional sorting tool for point clouds using the monotonic lagrangian grid
|
|
5
5
|
Author: Armand de Cacqueray
|
|
6
6
|
License: MIT
|
|
@@ -16,25 +16,31 @@ Dynamic: license-file
|
|
|
16
16
|
|
|
17
17
|
## ❒ Gridpoints — Multi dimensional sort for point clouds
|
|
18
18
|
|
|
19
|
-
`Gridpoints` maps unstructured **point clouds** to structured grids through a **bijective transformation**: one point, one cell, no overlap, fully invertible. It replaces and enhances the squarenet project with a
|
|
19
|
+
`Gridpoints` maps unstructured **point clouds** to structured grids through a **bijective transformation**: one point, one cell, no overlap, fully invertible. It replaces and enhances the squarenet project with a more powerfull sorting algorithm.
|
|
20
20
|
|
|
21
|
-
Take raw point cloud `
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
What it does: Take raw point cloud `P(N, D)` and find a grid shape and an index permutation `order` such that Pgrid = P[order].reshape(*gridshape, D)
|
|
22
|
+
is sorted along every axis of the grid. E.g. in 3D, for Pgrid = (x, y, z):
|
|
23
|
+
```text
|
|
24
|
+
x[i+1, j, k] >= x[i, j, k]
|
|
25
|
+
y[i, j+1, k] >= y[i, j, k]
|
|
26
|
+
z[i, j, k+1] >= z[i, j, k]
|
|
27
|
+
```
|
|
28
|
+
→ On the `Pgrid` view of `P`, neighbor queries become a simple stencil look-up :
|
|
29
|
+
```text
|
|
30
|
+
neighborhood[i, j, k] = {Pgrid[i±di, j±dj, k±dk] | (di, dj, dk) ≤ R},
|
|
31
|
+
````
|
|
32
|
+
where `R` is a radius cutoff to determine, allowing local operations in linear time.
|
|
33
|
+
→ Standard operations (convolution, clustering, …) can then be applied
|
|
34
|
+
directly on the `Pgrid` view instead of relying on complex graph convolutions
|
|
29
35
|
or other point-cloud techniques.
|
|
30
36
|
|
|
31
|
-
`
|
|
37
|
+
`P` can be a NumPy, PyTorch or CuPy array of any dimension (N, D).
|
|
32
38
|
To allow natural padding when the grid has more cells than points,
|
|
33
39
|
NaNs and Infs are supported in a consistent manner:
|
|
34
40
|
- nans → random position
|
|
35
41
|
- (+-) infs → border of the grid
|
|
36
|
-
|
|
37
|
-
deal with void/special grid cells.
|
|
42
|
+
|
|
43
|
+
This allow to gridsort prime or variable number of points N, as long as one is ready to deal with void/special grid cells.
|
|
38
44
|
|
|
39
45
|
Expected runtime for sorting 1 million points: CPU → < 10s, GPU → < 500 ms
|
|
40
46
|
|
|
@@ -54,20 +60,20 @@ import gridpoints as grid
|
|
|
54
60
|
import numpy as np
|
|
55
61
|
|
|
56
62
|
# Raw point cloud (numpy, pytorch or cupy)
|
|
57
|
-
|
|
63
|
+
A = np.random.rand(1_000_000, 3)
|
|
58
64
|
|
|
59
65
|
# Sorted view: place the points inside the grid
|
|
60
|
-
order = grid.argsort(
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
order = grid.argsort(A, gridshape=(100, 100, 100))
|
|
67
|
+
Bflat = A[order]
|
|
68
|
+
Bgrid = Bflat.reshape(100, 100, 100, 3)
|
|
63
69
|
|
|
64
70
|
# Rest of your pipeline, working with grids
|
|
65
|
-
|
|
71
|
+
Cgrid = apply_something(Bgrid)
|
|
66
72
|
|
|
67
73
|
# Back to the original points indexing
|
|
68
|
-
|
|
74
|
+
Cflat = Cgrid.reshape(-1, 3)
|
|
69
75
|
orderinv = grid.invert_permutation(order)
|
|
70
|
-
|
|
76
|
+
C = Cflat[orderinv] # matches the initial points order
|
|
71
77
|
```
|
|
72
78
|
|
|
73
79
|
<img src="https://raw.githubusercontent.com/Neighborhood-Grid/CubeNet/main/ballexemple.png">
|
|
@@ -85,6 +91,6 @@ As an example, empirical results in 2-D show that `R = 5` is enough for ~99 % of
|
|
|
85
91
|
The typical use-case of `Gridpoints` is to allow fast local operations on arbitrary point clouds using stencil kernels:
|
|
86
92
|
|
|
87
93
|
```text
|
|
88
|
-
output(i, j, k) = f(
|
|
94
|
+
output(i, j, k) = f( Pgrid[i±di, j±dj, k±dk] | di, dj, dk in local window )
|
|
89
95
|
```
|
|
90
96
|
To go beyond standard (slow) python loops, this can be accelerated with native grid convolution operations of standard libraries whenever possible, or with `pystencils` or `taichi` compilers for complex/non linear grid kernels.
|
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
## ❒ Gridpoints — Multi dimensional sort for point clouds
|
|
2
2
|
|
|
3
|
-
`Gridpoints` maps unstructured **point clouds** to structured grids through a **bijective transformation**: one point, one cell, no overlap, fully invertible. It replaces and enhances the squarenet project with a
|
|
4
|
-
|
|
5
|
-
Take raw point cloud `
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
`Gridpoints` maps unstructured **point clouds** to structured grids through a **bijective transformation**: one point, one cell, no overlap, fully invertible. It replaces and enhances the squarenet project with a more powerfull sorting algorithm.
|
|
4
|
+
|
|
5
|
+
What it does: Take raw point cloud `P(N, D)` and find a grid shape and an index permutation `order` such that Pgrid = P[order].reshape(*gridshape, D)
|
|
6
|
+
is sorted along every axis of the grid. E.g. in 3D, for Pgrid = (x, y, z):
|
|
7
|
+
```text
|
|
8
|
+
x[i+1, j, k] >= x[i, j, k]
|
|
9
|
+
y[i, j+1, k] >= y[i, j, k]
|
|
10
|
+
z[i, j, k+1] >= z[i, j, k]
|
|
11
|
+
```
|
|
12
|
+
→ On the `Pgrid` view of `P`, neighbor queries become a simple stencil look-up :
|
|
13
|
+
```text
|
|
14
|
+
neighborhood[i, j, k] = {Pgrid[i±di, j±dj, k±dk] | (di, dj, dk) ≤ R},
|
|
15
|
+
````
|
|
16
|
+
where `R` is a radius cutoff to determine, allowing local operations in linear time.
|
|
17
|
+
→ Standard operations (convolution, clustering, …) can then be applied
|
|
18
|
+
directly on the `Pgrid` view instead of relying on complex graph convolutions
|
|
13
19
|
or other point-cloud techniques.
|
|
14
20
|
|
|
15
|
-
`
|
|
21
|
+
`P` can be a NumPy, PyTorch or CuPy array of any dimension (N, D).
|
|
16
22
|
To allow natural padding when the grid has more cells than points,
|
|
17
23
|
NaNs and Infs are supported in a consistent manner:
|
|
18
24
|
- nans → random position
|
|
19
25
|
- (+-) infs → border of the grid
|
|
20
|
-
|
|
21
|
-
deal with void/special grid cells.
|
|
26
|
+
|
|
27
|
+
This allow to gridsort prime or variable number of points N, as long as one is ready to deal with void/special grid cells.
|
|
22
28
|
|
|
23
29
|
Expected runtime for sorting 1 million points: CPU → < 10s, GPU → < 500 ms
|
|
24
30
|
|
|
@@ -38,20 +44,20 @@ import gridpoints as grid
|
|
|
38
44
|
import numpy as np
|
|
39
45
|
|
|
40
46
|
# Raw point cloud (numpy, pytorch or cupy)
|
|
41
|
-
|
|
47
|
+
A = np.random.rand(1_000_000, 3)
|
|
42
48
|
|
|
43
49
|
# Sorted view: place the points inside the grid
|
|
44
|
-
order = grid.argsort(
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
order = grid.argsort(A, gridshape=(100, 100, 100))
|
|
51
|
+
Bflat = A[order]
|
|
52
|
+
Bgrid = Bflat.reshape(100, 100, 100, 3)
|
|
47
53
|
|
|
48
54
|
# Rest of your pipeline, working with grids
|
|
49
|
-
|
|
55
|
+
Cgrid = apply_something(Bgrid)
|
|
50
56
|
|
|
51
57
|
# Back to the original points indexing
|
|
52
|
-
|
|
58
|
+
Cflat = Cgrid.reshape(-1, 3)
|
|
53
59
|
orderinv = grid.invert_permutation(order)
|
|
54
|
-
|
|
60
|
+
C = Cflat[orderinv] # matches the initial points order
|
|
55
61
|
```
|
|
56
62
|
|
|
57
63
|
<img src="https://raw.githubusercontent.com/Neighborhood-Grid/CubeNet/main/ballexemple.png">
|
|
@@ -69,6 +75,6 @@ As an example, empirical results in 2-D show that `R = 5` is enough for ~99 % of
|
|
|
69
75
|
The typical use-case of `Gridpoints` is to allow fast local operations on arbitrary point clouds using stencil kernels:
|
|
70
76
|
|
|
71
77
|
```text
|
|
72
|
-
output(i, j, k) = f(
|
|
78
|
+
output(i, j, k) = f( Pgrid[i±di, j±dj, k±dk] | di, dj, dk in local window )
|
|
73
79
|
```
|
|
74
|
-
To go beyond standard (slow) python loops, this can be accelerated with native grid convolution operations of standard libraries whenever possible, or with `pystencils` or `taichi` compilers for complex/non linear grid kernels.
|
|
80
|
+
To go beyond standard (slow) python loops, this can be accelerated with native grid convolution operations of standard libraries whenever possible, or with `pystencils` or `taichi` compilers for complex/non linear grid kernels.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "gridpoints"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.4"
|
|
8
8
|
description = "fast multidimensional sorting tool for point clouds using the monotonic lagrangian grid "
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -108,14 +108,14 @@ def print_zoom(Ygrid, center, side=1):
|
|
|
108
108
|
else:
|
|
109
109
|
i, j, k = center
|
|
110
110
|
print("axis 0:")
|
|
111
|
-
for ii in range(i-
|
|
111
|
+
for ii in range(i-side, i+side+1):
|
|
112
112
|
print(_format_point(Ygrid[ii, j, k]), end=" ")
|
|
113
113
|
print()
|
|
114
114
|
print("axis 1:")
|
|
115
|
-
for jj in range(j-
|
|
115
|
+
for jj in range(j-side, j+side+1):
|
|
116
116
|
print(_format_point(Ygrid[i, jj, k]), end=" ")
|
|
117
117
|
print()
|
|
118
118
|
print("axis 2:")
|
|
119
|
-
for kk in range(k-
|
|
119
|
+
for kk in range(k-side, k+side+1):
|
|
120
120
|
print(_format_point(Ygrid[i, j, kk]), end=" ")
|
|
121
121
|
print()
|
|
@@ -10,7 +10,7 @@ like arange, copy, shuffle etc.
|
|
|
10
10
|
_FLOAT = 'float32'
|
|
11
11
|
_INT = 'int32'
|
|
12
12
|
|
|
13
|
-
EPS = 10**(-10)
|
|
13
|
+
EPS = 10**(-5) if (_FLOAT == 'float32') else 10**(-10)
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def get_dtype(dtp, xp):
|
|
@@ -47,8 +47,7 @@ def inplace_sort(X, axis):
|
|
|
47
47
|
if backend_name == 'torch':
|
|
48
48
|
X.copy_(X.sort(dim=axis)[0])
|
|
49
49
|
if backend_name == "cupy":
|
|
50
|
-
X[...] = xp.ascontiguousarray(X)
|
|
51
|
-
X.sort(axis=axis)
|
|
50
|
+
X[...] = xp.sort(xp.ascontiguousarray(X), axis=axis)
|
|
52
51
|
else:
|
|
53
52
|
X.sort(axis=axis)
|
|
54
53
|
|
|
@@ -101,8 +100,8 @@ def nan_to_num(arr):
|
|
|
101
100
|
finite = xp.isfinite(x)
|
|
102
101
|
vals = x[finite]
|
|
103
102
|
|
|
104
|
-
out[xp.isposinf(x), d] =
|
|
105
|
-
out[xp.isneginf(x), d] =
|
|
103
|
+
out[xp.isposinf(x), d] = vals.max() + 1
|
|
104
|
+
out[xp.isneginf(x), d] = vals.min() - 1
|
|
106
105
|
|
|
107
106
|
nan = xp.isnan(x)
|
|
108
107
|
n = nan.sum().item() if backend == 'torch' else int(nan.sum())
|
|
@@ -165,4 +164,4 @@ def transpose(X, axes):
|
|
|
165
164
|
_, name = get_backend(X)
|
|
166
165
|
if name == "torch":
|
|
167
166
|
return X.permute(*axes)
|
|
168
|
-
return X.transpose(axes)
|
|
167
|
+
return X.transpose(axes)
|
|
@@ -18,7 +18,7 @@ from .kdtree import kdtree_order
|
|
|
18
18
|
# Sorting API
|
|
19
19
|
# ============================================
|
|
20
20
|
|
|
21
|
-
def argsort(X, gridshape, level=2, init="kdtree", n_iter=
|
|
21
|
+
def argsort(X, gridshape, level=2, init="kdtree", n_iter=40, verbose = 2):
|
|
22
22
|
"""Compute a multi-directional monotonic sorted ordering of a point cloud.
|
|
23
23
|
|
|
24
24
|
Parameters
|
|
@@ -40,7 +40,7 @@ def argsort(X, gridshape, level=2, init="kdtree", n_iter=50, verbose = 2):
|
|
|
40
40
|
init : {'kdtree', 'shuffle'} or None, default="kdtree"
|
|
41
41
|
Initialization method for the permutation order. Try init = None
|
|
42
42
|
if the point cloud is already nearly sorted.
|
|
43
|
-
n_iter : int, default=
|
|
43
|
+
n_iter : int, default=40
|
|
44
44
|
Maximum number of optimization iterations.
|
|
45
45
|
verbose : int, default 2
|
|
46
46
|
0 = silent, 1 = log progress, 2 = 1 + warn if convergence failed
|
|
@@ -50,9 +50,6 @@ def argsort(X, gridshape, level=2, init="kdtree", n_iter=50, verbose = 2):
|
|
|
50
50
|
order : ndarray of shape (N,)
|
|
51
51
|
Permutation indices such that `X[order].reshape(*shape, D)` forms a
|
|
52
52
|
monotonically sorted grid.
|
|
53
|
-
converged : bool
|
|
54
|
-
`True` if the algorithm converged within `n_iter` iterations, `False` otherwise.
|
|
55
|
-
If not converged, the fonction will also raise a convergence warning
|
|
56
53
|
"""
|
|
57
54
|
N, D = X.shape
|
|
58
55
|
assert math.prod(gridshape) == N
|
|
@@ -65,9 +62,8 @@ def argsort(X, gridshape, level=2, init="kdtree", n_iter=50, verbose = 2):
|
|
|
65
62
|
order = kdtree_order(X, gridshape)
|
|
66
63
|
if verbose >=1:
|
|
67
64
|
print("done")
|
|
68
|
-
converged = True
|
|
69
65
|
if level == 1:
|
|
70
|
-
return order
|
|
66
|
+
return order
|
|
71
67
|
else:
|
|
72
68
|
order = arange(len(X), 'int', reference_array=X)
|
|
73
69
|
if init == "shuffle":
|
|
@@ -77,7 +73,7 @@ def argsort(X, gridshape, level=2, init="kdtree", n_iter=50, verbose = 2):
|
|
|
77
73
|
order = order[ordernew]
|
|
78
74
|
|
|
79
75
|
if not converged:
|
|
80
|
-
while level >= 2:
|
|
76
|
+
while level >= 2 and not converged:
|
|
81
77
|
level = level - 1
|
|
82
78
|
ordernew, converged = _mlg_step(
|
|
83
79
|
X[order], gridshape, level=level, n_iter=n_iter, verbose = verbose
|
|
@@ -85,19 +81,19 @@ def argsort(X, gridshape, level=2, init="kdtree", n_iter=50, verbose = 2):
|
|
|
85
81
|
order = order[ordernew]
|
|
86
82
|
if not converged and verbose >=2:
|
|
87
83
|
warnings.warn(
|
|
88
|
-
f"Algorithm failed to converge after {n_iter} iterations
|
|
89
|
-
"Consider checking if the grid structure is already suitable" \
|
|
90
|
-
"for the given task, which is higly probable, or increase the" \
|
|
84
|
+
f"Algorithm failed to converge after {n_iter} iterations.\n " \
|
|
85
|
+
"Consider checking if the grid structure is already suitable \n" \
|
|
86
|
+
"for the given task, which is higly probable, or increase the \n" \
|
|
91
87
|
"`n_iter` parameter if strict convergence is required.",
|
|
92
88
|
category=ConvergenceWarning,
|
|
93
|
-
stacklevel=2
|
|
89
|
+
stacklevel=2
|
|
94
90
|
)
|
|
95
91
|
if verbose:
|
|
96
92
|
print("done")
|
|
97
|
-
return order
|
|
93
|
+
return order
|
|
98
94
|
|
|
99
95
|
|
|
100
|
-
def sort(X, gridshape, level=2, init="kdtree", inplace=False, n_iter=
|
|
96
|
+
def sort(X, gridshape, level=2, init="kdtree", inplace=False, n_iter=40, verbose = 2):
|
|
101
97
|
"""Sort a point cloud `X` using the monotonic Lagrangian algorithm.
|
|
102
98
|
|
|
103
99
|
Parameters
|
|
@@ -121,7 +117,7 @@ def sort(X, gridshape, level=2, init="kdtree", inplace=False, n_iter=50, verbose
|
|
|
121
117
|
if the point cloud is already nearly sorted.
|
|
122
118
|
inplace : bool, default=False
|
|
123
119
|
If True, modify the point cloud `X` in place.
|
|
124
|
-
n_iter : int, default=
|
|
120
|
+
n_iter : int, default=40
|
|
125
121
|
Maximum number of optimization iterations.
|
|
126
122
|
verbose : int, default 2
|
|
127
123
|
0 = silent, 1 = log progress, 2 = 1 + warn if convergence failed
|
|
@@ -132,7 +128,7 @@ def sort(X, gridshape, level=2, init="kdtree", inplace=False, n_iter=50, verbose
|
|
|
132
128
|
The sorted point cloud such that `X_sorted.reshape(*shape, D)` forms a
|
|
133
129
|
monotonically sorted grid. Returns `None` if `inplace=True`.
|
|
134
130
|
"""
|
|
135
|
-
order
|
|
131
|
+
order = argsort(X, gridshape, level=level, init = init, n_iter=n_iter,verbose = verbose)
|
|
136
132
|
|
|
137
133
|
if inplace:
|
|
138
134
|
X[:] = X[order]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gridpoints
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: fast multidimensional sorting tool for point clouds using the monotonic lagrangian grid
|
|
5
5
|
Author: Armand de Cacqueray
|
|
6
6
|
License: MIT
|
|
@@ -16,25 +16,31 @@ Dynamic: license-file
|
|
|
16
16
|
|
|
17
17
|
## ❒ Gridpoints — Multi dimensional sort for point clouds
|
|
18
18
|
|
|
19
|
-
`Gridpoints` maps unstructured **point clouds** to structured grids through a **bijective transformation**: one point, one cell, no overlap, fully invertible. It replaces and enhances the squarenet project with a
|
|
19
|
+
`Gridpoints` maps unstructured **point clouds** to structured grids through a **bijective transformation**: one point, one cell, no overlap, fully invertible. It replaces and enhances the squarenet project with a more powerfull sorting algorithm.
|
|
20
20
|
|
|
21
|
-
Take raw point cloud `
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
What it does: Take raw point cloud `P(N, D)` and find a grid shape and an index permutation `order` such that Pgrid = P[order].reshape(*gridshape, D)
|
|
22
|
+
is sorted along every axis of the grid. E.g. in 3D, for Pgrid = (x, y, z):
|
|
23
|
+
```text
|
|
24
|
+
x[i+1, j, k] >= x[i, j, k]
|
|
25
|
+
y[i, j+1, k] >= y[i, j, k]
|
|
26
|
+
z[i, j, k+1] >= z[i, j, k]
|
|
27
|
+
```
|
|
28
|
+
→ On the `Pgrid` view of `P`, neighbor queries become a simple stencil look-up :
|
|
29
|
+
```text
|
|
30
|
+
neighborhood[i, j, k] = {Pgrid[i±di, j±dj, k±dk] | (di, dj, dk) ≤ R},
|
|
31
|
+
````
|
|
32
|
+
where `R` is a radius cutoff to determine, allowing local operations in linear time.
|
|
33
|
+
→ Standard operations (convolution, clustering, …) can then be applied
|
|
34
|
+
directly on the `Pgrid` view instead of relying on complex graph convolutions
|
|
29
35
|
or other point-cloud techniques.
|
|
30
36
|
|
|
31
|
-
`
|
|
37
|
+
`P` can be a NumPy, PyTorch or CuPy array of any dimension (N, D).
|
|
32
38
|
To allow natural padding when the grid has more cells than points,
|
|
33
39
|
NaNs and Infs are supported in a consistent manner:
|
|
34
40
|
- nans → random position
|
|
35
41
|
- (+-) infs → border of the grid
|
|
36
|
-
|
|
37
|
-
deal with void/special grid cells.
|
|
42
|
+
|
|
43
|
+
This allow to gridsort prime or variable number of points N, as long as one is ready to deal with void/special grid cells.
|
|
38
44
|
|
|
39
45
|
Expected runtime for sorting 1 million points: CPU → < 10s, GPU → < 500 ms
|
|
40
46
|
|
|
@@ -54,20 +60,20 @@ import gridpoints as grid
|
|
|
54
60
|
import numpy as np
|
|
55
61
|
|
|
56
62
|
# Raw point cloud (numpy, pytorch or cupy)
|
|
57
|
-
|
|
63
|
+
A = np.random.rand(1_000_000, 3)
|
|
58
64
|
|
|
59
65
|
# Sorted view: place the points inside the grid
|
|
60
|
-
order = grid.argsort(
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
order = grid.argsort(A, gridshape=(100, 100, 100))
|
|
67
|
+
Bflat = A[order]
|
|
68
|
+
Bgrid = Bflat.reshape(100, 100, 100, 3)
|
|
63
69
|
|
|
64
70
|
# Rest of your pipeline, working with grids
|
|
65
|
-
|
|
71
|
+
Cgrid = apply_something(Bgrid)
|
|
66
72
|
|
|
67
73
|
# Back to the original points indexing
|
|
68
|
-
|
|
74
|
+
Cflat = Cgrid.reshape(-1, 3)
|
|
69
75
|
orderinv = grid.invert_permutation(order)
|
|
70
|
-
|
|
76
|
+
C = Cflat[orderinv] # matches the initial points order
|
|
71
77
|
```
|
|
72
78
|
|
|
73
79
|
<img src="https://raw.githubusercontent.com/Neighborhood-Grid/CubeNet/main/ballexemple.png">
|
|
@@ -85,6 +91,6 @@ As an example, empirical results in 2-D show that `R = 5` is enough for ~99 % of
|
|
|
85
91
|
The typical use-case of `Gridpoints` is to allow fast local operations on arbitrary point clouds using stencil kernels:
|
|
86
92
|
|
|
87
93
|
```text
|
|
88
|
-
output(i, j, k) = f(
|
|
94
|
+
output(i, j, k) = f( Pgrid[i±di, j±dj, k±dk] | di, dj, dk in local window )
|
|
89
95
|
```
|
|
90
96
|
To go beyond standard (slow) python loops, this can be accelerated with native grid convolution operations of standard libraries whenever possible, or with `pystencils` or `taichi` compilers for complex/non linear grid kernels.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|