lsdo-function-spaces 1.0.0__py3-none-any.whl

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.
Files changed (40) hide show
  1. lsdo_function_spaces/__init__.py +64 -0
  2. lsdo_function_spaces/core/__init__.py +0 -0
  3. lsdo_function_spaces/core/function.py +1322 -0
  4. lsdo_function_spaces/core/function_set.py +1081 -0
  5. lsdo_function_spaces/core/function_set_space.py +379 -0
  6. lsdo_function_spaces/core/function_space.py +482 -0
  7. lsdo_function_spaces/core/operations/__init__.py +0 -0
  8. lsdo_function_spaces/core/operations/basic_ops.py +85 -0
  9. lsdo_function_spaces/core/operations/operations.py +5 -0
  10. lsdo_function_spaces/core/optimization.py +183 -0
  11. lsdo_function_spaces/core/spaces/__init__.py +0 -0
  12. lsdo_function_spaces/core/spaces/b_spline_space.py +418 -0
  13. lsdo_function_spaces/core/spaces/conditional_space.py +65 -0
  14. lsdo_function_spaces/core/spaces/constant_space.py +57 -0
  15. lsdo_function_spaces/core/spaces/idw_space.py +271 -0
  16. lsdo_function_spaces/core/spaces/non_cython_bsplines/__init__.py +0 -0
  17. lsdo_function_spaces/core/spaces/non_cython_bsplines/b_spline_csdl_custom_ops.py +420 -0
  18. lsdo_function_spaces/core/spaces/non_cython_bsplines/b_spline_patch_projection.py +1022 -0
  19. lsdo_function_spaces/core/spaces/non_cython_bsplines/b_spline_patch_projection_non_differentiable.py +186 -0
  20. lsdo_function_spaces/core/spaces/non_cython_bsplines/b_spline_patch_projection_optimized.py +594 -0
  21. lsdo_function_spaces/core/spaces/non_cython_bsplines/b_spline_space_new.py +6 -0
  22. lsdo_function_spaces/core/spaces/non_cython_bsplines/compute_basis_matrix_jax.py +172 -0
  23. lsdo_function_spaces/core/spaces/non_cython_bsplines/compute_basis_matrix_jax_factory.py +382 -0
  24. lsdo_function_spaces/core/spaces/non_cython_bsplines/compute_basis_matrix_jax_stencil.py +451 -0
  25. lsdo_function_spaces/core/spaces/non_cython_bsplines/compute_basis_matrix_numpy.py +249 -0
  26. lsdo_function_spaces/core/spaces/non_cython_bsplines/compute_basis_matrix_numpy_factory.py +391 -0
  27. lsdo_function_spaces/core/spaces/operation_space.py +64 -0
  28. lsdo_function_spaces/core/spaces/polynomial_space.py +79 -0
  29. lsdo_function_spaces/core/spaces/rbf_space.py +136 -0
  30. lsdo_function_spaces/core/spaces/tri_space.py +256 -0
  31. lsdo_function_spaces/utils/__init__.py +0 -0
  32. lsdo_function_spaces/utils/file_io.py +484 -0
  33. lsdo_function_spaces/utils/internal_utilities.py +11 -0
  34. lsdo_function_spaces/utils/plotting_functions.py +357 -0
  35. lsdo_function_spaces/utils/utility_functions.py +148 -0
  36. lsdo_function_spaces-1.0.0.dist-info/METADATA +189 -0
  37. lsdo_function_spaces-1.0.0.dist-info/RECORD +40 -0
  38. lsdo_function_spaces-1.0.0.dist-info/WHEEL +5 -0
  39. lsdo_function_spaces-1.0.0.dist-info/licenses/LICENSE.txt +165 -0
  40. lsdo_function_spaces-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,57 @@
1
+ import numpy as np
2
+ import scipy.sparse as sps
3
+ from ..function_space import LinearFunctionSpace
4
+ from scipy.spatial.distance import cdist
5
+ from dataclasses import dataclass
6
+ from typing import Union
7
+
8
+ class ConstantSpace(LinearFunctionSpace):
9
+ """
10
+ Constant Function Space.
11
+
12
+ This function space represents a constant value in a parametric space.
13
+
14
+ Parameters
15
+ ----------
16
+ num_parametric_dimensions : int
17
+ The number of parametric dimensions.
18
+ """
19
+
20
+ def __init__(self, num_parametric_dimensions:int):
21
+ super().__init__(num_parametric_dimensions, (1,))
22
+
23
+
24
+ def compute_basis_matrix(self, parametric_coordinates:np.ndarray, parametric_derivative_orders: np.ndarray=None, expansion_factor:int=None) -> np.ndarray:
25
+ """
26
+ Compute the basis matrix for the given parametric coordinates.
27
+
28
+ Parameters
29
+ ----------
30
+ parametric_coordinates : np.ndarray
31
+ The parametric coordinates for which to compute the basis matrix.
32
+ parametric_derivative_orders : np.ndarray, optional
33
+ The derivative orders of the parametric coordinates. Default is None.
34
+ expansion_factor : int, optional
35
+ The expansion factor. Default is None.
36
+
37
+ Returns
38
+ -------
39
+ np.ndarray
40
+ The computed basis matrix.
41
+
42
+ Raises
43
+ ------
44
+ NotImplementedError
45
+ If parametric_derivative_orders or expansion_factor is not None.
46
+
47
+ """
48
+ if parametric_derivative_orders is not None:
49
+ raise NotImplementedError('IDWFunctionSpace does not support derivatives')
50
+ if expansion_factor is not None:
51
+ raise NotImplementedError('IDWFunctionSpace does not support expansion factors')
52
+
53
+ if len(parametric_coordinates.shape) == 1:
54
+ parametric_coordinates = parametric_coordinates.reshape(1, -1)
55
+
56
+ weights = np.ones((parametric_coordinates.shape[0], 1))
57
+ return weights
@@ -0,0 +1,271 @@
1
+ import numpy as np
2
+ import scipy.sparse as sps
3
+ from lsdo_function_spaces.core.function_space import LinearFunctionSpace
4
+ from scipy.spatial.distance import cdist
5
+ from dataclasses import dataclass
6
+ from typing import Union
7
+ import csdl_alpha as csdl
8
+
9
+ class IDWFunctionSpace(LinearFunctionSpace):
10
+ """
11
+ Inverse Distance Weighting (IDW) Function Space.
12
+
13
+ This function space represents a grid of points in a parametric space using the Inverse Distance Weighting method.
14
+ It provides methods to compute the basis matrix and the fitting map.
15
+
16
+ Parameters
17
+ ----------
18
+ num_parametric_dimensions : int
19
+ The number of parametric dimensions.
20
+ order : float
21
+ The order of the inverse distance weighting function.
22
+ conserve : bool, optional
23
+ If True, the weights will be normalized to conserve the sum of the values. Default is True.
24
+ grid_size : tuple, optional
25
+ The size of the grid in each parametric dimension. Default is (10,).
26
+ """
27
+
28
+ def __init__(self, num_parametric_dimensions:int, order:float, points:np.ndarray=None, conserve:bool=True, grid_size:Union[int, tuple]=10, n_neighbors:int=None):
29
+ """
30
+ Initialize an IDW function space.
31
+
32
+ Parameters
33
+ ----------
34
+ order : float
35
+ The order of the inverse distance weighting function.
36
+ conserve : bool, optional
37
+ If True, the weights will be normalized to conserve the sum of the values. Default is True.
38
+
39
+ """
40
+
41
+ self.order = order
42
+ self.conserve = conserve
43
+ self.grid_size = grid_size
44
+ self.points = points
45
+ self.n_neighbors = n_neighbors
46
+
47
+ if n_neighbors is not None and conserve:
48
+ raise ValueError('IDWFunctionSpace does not support n_neighbors and conserve=True simultaneously')
49
+
50
+
51
+ if self.points is None:
52
+ if isinstance(self.grid_size, int):
53
+ self.grid_size = (self.grid_size,)*num_parametric_dimensions
54
+ linspaces = [np.linspace(0, 1, n) for n in self.grid_size]
55
+ self.points = np.array(np.meshgrid(*linspaces)).T.reshape(-1, num_parametric_dimensions)
56
+
57
+ if n_neighbors is not None:
58
+ if n_neighbors > self.points.shape[0]:
59
+ raise ValueError('n_neighbors cannot be greater than the number of points')
60
+ if n_neighbors < 1:
61
+ raise ValueError('n_neighbors must be greater than 0')
62
+
63
+ super().__init__(num_parametric_dimensions, (self.points.shape[0], 1))
64
+
65
+ def stitch(self, self_face, self_coeffs, other, other_face, other_coeffs):
66
+ """
67
+ Stitch two IDW function spaces together.
68
+
69
+ Parameters
70
+ ----------
71
+ self_face : int
72
+ The face of the current function space.
73
+ other : IDWFunctionSpace
74
+ The other function space to stitch.
75
+ other_face : int
76
+ The face of the other function space.
77
+
78
+ Returns
79
+ -------
80
+ IDWFunctionSpace
81
+ The stitched function space.
82
+
83
+ """
84
+ if self_face == 1:
85
+ self_inds = np.where(self.points[:, 1] == 0)
86
+ self_free_index = 0
87
+ elif self_face == 2:
88
+ self_inds = np.where(self.points[:, 0] == 1)
89
+ self_free_index = 1
90
+ elif self_face == 3:
91
+ self_inds = np.where(self.points[:, 1] == 1)
92
+ self_free_index = 0
93
+ elif self_face == 4:
94
+ self_inds = np.where(self.points[:, 0] == 0)
95
+ self_free_index = 1
96
+ self_inds = [int(ind) for ind in self_inds[0]]
97
+
98
+ if other_face == 1:
99
+ other_inds = np.where(other.points[:, 1] == 0)
100
+ other_free_index = 0
101
+ elif other_face == 2:
102
+ other_inds = np.where(other.points[:, 0] == 1)
103
+ other_free_index = 1
104
+ elif other_face == 3:
105
+ other_inds = np.where(other.points[:, 1] == 1)
106
+ other_free_index = 0
107
+ elif other_face == 4:
108
+ other_inds = np.where(other.points[:, 0] == 0)
109
+ other_free_index = 1
110
+ other_inds = [int(ind) for ind in other_inds[0]]
111
+
112
+ other_inds_sorted = []
113
+ for i, point in enumerate(self.points[self_inds]):
114
+ for j, other_point in enumerate(other.points[other_inds]):
115
+ if np.allclose(point[self_free_index], other_point[other_free_index]):
116
+ other_inds_sorted.append(other_inds[j])
117
+ break
118
+
119
+ if len(other_inds_sorted) != len(self_inds):
120
+ raise ValueError('Could not find all corresponding points between the two faces')
121
+
122
+ for i, j in csdl.frange(vals=(self_inds, other_inds_sorted)):
123
+ self_face_coeffs = self_coeffs[i]
124
+ other_face_coeffs = other_coeffs[j]
125
+ average_coeffs = (self_face_coeffs + other_face_coeffs)/2
126
+ self_coeffs = self_coeffs.set(csdl.slice[i], average_coeffs)
127
+ other_coeffs = other_coeffs.set(csdl.slice[j], average_coeffs)
128
+
129
+ return self_coeffs, other_coeffs
130
+
131
+ def compute_basis_matrix(self, parametric_coordinates:np.ndarray, parametric_derivative_orders: np.ndarray=None, expansion_factor:int=None) -> np.ndarray:
132
+ """
133
+ Compute the basis matrix for the given parametric coordinates.
134
+
135
+ Parameters
136
+ ----------
137
+ parametric_coordinates : np.ndarray
138
+ The parametric coordinates for which to compute the basis matrix.
139
+ parametric_derivative_orders : np.ndarray, optional
140
+ The derivative orders of the parametric coordinates. Default is None.
141
+ expansion_factor : int, optional
142
+ The expansion factor. Default is None.
143
+
144
+ Returns
145
+ -------
146
+ np.ndarray
147
+ The computed basis matrix.
148
+
149
+ Raises
150
+ ------
151
+ NotImplementedError
152
+ If parametric_derivative_orders or expansion_factor is not None.
153
+
154
+ """
155
+ # if parametric_derivative_orders is not None:
156
+ # raise NotImplementedError('IDWFunctionSpace does not support derivatives')
157
+ # if expansion_factor is not None:
158
+ # raise NotImplementedError('IDWFunctionSpace does not support expansion factors')
159
+
160
+ if len(parametric_coordinates.shape) == 1:
161
+ parametric_coordinates = parametric_coordinates.reshape(1, -1)
162
+
163
+ if self.n_neighbors is None:
164
+ dist = cdist(self.points, parametric_coordinates)
165
+ with np.errstate(divide='ignore', invalid='ignore'):
166
+ weights = 1.0/dist**self.order
167
+ if self.conserve:
168
+ weights = weights.T
169
+ weights /= weights.sum(axis=0)
170
+ else:
171
+ weights /= weights.sum(axis=0)
172
+ weights = weights.T
173
+ np.nan_to_num(weights, copy=False, nan=1.)
174
+ else:
175
+ # assemble a sparse matrix with the weights of the n_neighbors closest points
176
+ from sklearn.neighbors import NearestNeighbors
177
+ nbrs = NearestNeighbors(n_neighbors=self.n_neighbors, algorithm='ball_tree').fit(self.points)
178
+ distances, indices = nbrs.kneighbors(parametric_coordinates)
179
+ with np.errstate(divide='ignore', invalid='ignore'):
180
+ weights = 1.0/distances**self.order
181
+ weights /= weights.sum(axis=1)[:, np.newaxis]
182
+ np.nan_to_num(weights, copy=False, nan=1.)
183
+ inv_indices = np.repeat(np.arange(indices.shape[0]), indices.shape[1])
184
+ weights = sps.csr_matrix((weights.ravel(), (inv_indices, indices.ravel())), shape=(parametric_coordinates.shape[0], self.points.shape[0]))
185
+
186
+ return weights
187
+
188
+ def compute_fitting_map(self, parametric_coordinates:np.ndarray, parametric_derivative_orders: np.ndarray=None) -> np.ndarray:
189
+ """
190
+ Compute the fitting map for the given parametric coordinates.
191
+
192
+ Parameters
193
+ ----------
194
+ parametric_coordinates : np.ndarray
195
+ The parametric coordinates for which to compute the fitting map.
196
+ parametric_derivative_orders : np.ndarray, optional
197
+ The derivative orders of the parametric coordinates. Default is None.
198
+
199
+ Returns
200
+ -------
201
+ np.ndarray
202
+ The computed fitting map.
203
+
204
+ Raises
205
+ ------
206
+ NotImplementedError
207
+ If parametric_derivative_orders is not None.
208
+
209
+ """
210
+ # if parametric_derivative_orders is not None:
211
+ # raise NotImplementedError('IDWFunctionSpace does not support derivatives')
212
+
213
+ parametric_coordinates = parametric_coordinates.reshape(-1, self.num_parametric_dimensions)
214
+ if self.n_neighbors is None:
215
+ dist = cdist(parametric_coordinates, self.points)
216
+ with np.errstate(divide='ignore', invalid='ignore'):
217
+ weights = 1.0/dist**self.order
218
+ if self.conserve:
219
+ weights = weights.T
220
+ weights /= weights.sum(axis=0)
221
+ else:
222
+ weights /= weights.sum(axis=0)
223
+ weights = weights.T
224
+ np.nan_to_num(weights, copy=False, nan=1.)
225
+ else:
226
+ if self.n_neighbors > parametric_coordinates.shape[0]:
227
+ n_neighbors = parametric_coordinates.shape[0]
228
+ else:
229
+ n_neighbors = self.n_neighbors
230
+ # assemble a sparse matrix with the weights of the n_neighbors closest points
231
+ from sklearn.neighbors import NearestNeighbors
232
+ nbrs = NearestNeighbors(n_neighbors=n_neighbors, algorithm='ball_tree').fit(parametric_coordinates)
233
+ distances, indices = nbrs.kneighbors(self.points)
234
+ with np.errstate(divide='ignore', invalid='ignore'):
235
+ weights = 1.0/distances**self.order
236
+ weights /= weights.sum(axis=1)[:,np.newaxis]
237
+ np.nan_to_num(weights, copy=False, nan=1.)
238
+ inv_indices = np.repeat(np.arange(indices.shape[0]), indices.shape[1])
239
+ weights = sps.csr_matrix((weights.ravel(), (inv_indices, indices.ravel())), shape=(self.points.shape[0], parametric_coordinates.shape[0]))
240
+ return weights
241
+
242
+
243
+ def test_idw_space():
244
+ import numpy as np
245
+ import csdl_alpha as csdl
246
+
247
+ rec = csdl.Recorder(inline=True)
248
+ rec.start()
249
+
250
+ space = IDWFunctionSpace(2, 2, grid_size=4)
251
+ parametric_coordinates = np.random.rand(100, 2)
252
+ data = 10*np.random.rand(100, 1)
253
+ function = space.fit_function(data, parametric_coordinates)
254
+ eval_data = function.evaluate(parametric_coordinates)
255
+
256
+ space = IDWFunctionSpace(2, 2, grid_size=4, conserve=False)
257
+ sparse_space = IDWFunctionSpace(2, 2, grid_size=4, conserve=False, n_neighbors=3)
258
+ parametric_coordinates = np.random.rand(100, 2)
259
+ data = 10*np.random.rand(100, 1)
260
+ function = space.fit_function(data, parametric_coordinates)
261
+ eval_data = function.evaluate(parametric_coordinates)
262
+ sparse_function = sparse_space.fit_function(data, parametric_coordinates)
263
+ sparse_eval_data = sparse_function.evaluate(parametric_coordinates)
264
+ print('eval_data:', eval_data.value)
265
+ print('sparse_eval_data:', sparse_eval_data.value)
266
+ # print(eval_data.value - data)
267
+
268
+ # print(function.coefficients.value)
269
+
270
+ if __name__ == '__main__':
271
+ test_idw_space()