fuse-element 0.1.dev0__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.
- fuse/__init__.py +10 -0
- fuse/cells.py +850 -0
- fuse/dof.py +363 -0
- fuse/groups.py +388 -0
- fuse/serialisation.py +121 -0
- fuse/spaces/__init__.py +0 -0
- fuse/spaces/element_sobolev_spaces.py +80 -0
- fuse/spaces/interpolation_spaces.py +138 -0
- fuse/spaces/polynomial_spaces.py +203 -0
- fuse/traces.py +196 -0
- fuse/triples.py +470 -0
- fuse/utils.py +64 -0
- fuse_element-0.1.dev0.dist-info/LICENSE +165 -0
- fuse_element-0.1.dev0.dist-info/METADATA +17 -0
- fuse_element-0.1.dev0.dist-info/RECORD +17 -0
- fuse_element-0.1.dev0.dist-info/WHEEL +5 -0
- fuse_element-0.1.dev0.dist-info/top_level.txt +1 -0
fuse/groups.py
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import fuse.cells as cells
|
|
2
|
+
from sympy.combinatorics import PermutationGroup, Permutation
|
|
3
|
+
from sympy.combinatorics.named_groups import SymmetricGroup, DihedralGroup, CyclicGroup, AlternatingGroup
|
|
4
|
+
from sympy.matrices.expressions import PermutationMatrix
|
|
5
|
+
import numpy as np
|
|
6
|
+
import sympy as sp
|
|
7
|
+
import math
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def perm_matrix_to_perm_array(p_mat):
|
|
11
|
+
summed = np.sum(p_mat, axis=0)
|
|
12
|
+
assert np.all(summed == np.ones_like(summed))
|
|
13
|
+
res = []
|
|
14
|
+
for row in p_mat:
|
|
15
|
+
indices = list(row).index(1)
|
|
16
|
+
res += [indices]
|
|
17
|
+
return res
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class GroupMemberRep(object):
|
|
21
|
+
|
|
22
|
+
def __init__(self, perm, M, group):
|
|
23
|
+
self.perm = perm
|
|
24
|
+
self.transform_matrix = M
|
|
25
|
+
self.group = group
|
|
26
|
+
|
|
27
|
+
def __call__(self, x):
|
|
28
|
+
if isinstance(x, cells.Point):
|
|
29
|
+
return x.orient(self)
|
|
30
|
+
if isinstance(x, sp.Expr):
|
|
31
|
+
x_ones = sp.r_[sp.array(x), sp.ones(1)]
|
|
32
|
+
else:
|
|
33
|
+
x_ones = np.r_[np.array(x), np.ones(1)]
|
|
34
|
+
|
|
35
|
+
sum = np.matmul(x_ones, self.transform_matrix)
|
|
36
|
+
if len(sum.shape) > 1:
|
|
37
|
+
return tuple(map(tuple, sum))
|
|
38
|
+
return tuple(sum)
|
|
39
|
+
|
|
40
|
+
def permute(self, lst):
|
|
41
|
+
n = len(lst)
|
|
42
|
+
if n > self.perm.size:
|
|
43
|
+
temp_perm = Permutation(self.perm, size=n)
|
|
44
|
+
return temp_perm(lst)
|
|
45
|
+
return self.perm(lst)
|
|
46
|
+
|
|
47
|
+
def compute_perm(self, base_val=None):
|
|
48
|
+
if base_val:
|
|
49
|
+
val_list = [x + base_val for x in self.perm.array_form]
|
|
50
|
+
else:
|
|
51
|
+
val_list = self.perm.array_form
|
|
52
|
+
val = self.numeric_rep()
|
|
53
|
+
return val, val_list
|
|
54
|
+
|
|
55
|
+
def numeric_rep(self):
|
|
56
|
+
identity = self.group.identity.perm.array_form
|
|
57
|
+
m_array = self.perm.array_form
|
|
58
|
+
val = 0
|
|
59
|
+
for i in range(len(identity)):
|
|
60
|
+
loc = m_array.index(identity[i])
|
|
61
|
+
m_array.remove(identity[i])
|
|
62
|
+
val += loc * math.factorial(len(identity) - i - 1)
|
|
63
|
+
return val
|
|
64
|
+
|
|
65
|
+
def __eq__(self, x):
|
|
66
|
+
assert isinstance(x, GroupMemberRep)
|
|
67
|
+
return self.perm == x.perm and self.group.cell.dim() == x.group.cell.dim()
|
|
68
|
+
|
|
69
|
+
def __hash__(self):
|
|
70
|
+
return hash((self.perm, self.group))
|
|
71
|
+
|
|
72
|
+
def __mul__(self, x):
|
|
73
|
+
assert isinstance(x, GroupMemberRep)
|
|
74
|
+
return self.group.get_member(self.perm * x.perm)
|
|
75
|
+
|
|
76
|
+
def __invert__(self):
|
|
77
|
+
return self.group.get_member(~self.perm)
|
|
78
|
+
|
|
79
|
+
def __repr__(self):
|
|
80
|
+
string = "g"
|
|
81
|
+
string += str(self.perm.array_form)
|
|
82
|
+
return string
|
|
83
|
+
|
|
84
|
+
def matrix_form(self):
|
|
85
|
+
return np.array(PermutationMatrix(self.perm).as_explicit()).astype(np.float64)
|
|
86
|
+
|
|
87
|
+
def lin_combination_form(self):
|
|
88
|
+
if self.group.cell.dimension == 0:
|
|
89
|
+
return [1]
|
|
90
|
+
bvs = self.group.cell.basis_vectors()
|
|
91
|
+
M = np.array(bvs).T
|
|
92
|
+
trans_bvs = np.array([self(bvs[i]) for i in range(len(bvs))]).T
|
|
93
|
+
return np.linalg.solve(M, trans_bvs)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class PermutationSetRepresentation():
|
|
97
|
+
"""
|
|
98
|
+
A representation of a set of permutations (can be a full group) on a cell.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
[permutations]: the list of permutations in the set
|
|
102
|
+
cell (optional): the cell the group is representing the operations on
|
|
103
|
+
|
|
104
|
+
"""
|
|
105
|
+
def __init__(self, perm_list, cell=None):
|
|
106
|
+
assert len(perm_list) > 0
|
|
107
|
+
self.perm_list = perm_list
|
|
108
|
+
|
|
109
|
+
if not any([p.is_Identity for p in self.perm_list]):
|
|
110
|
+
p = self.perm_list[0]
|
|
111
|
+
self.perm_list.append(Permutation([i for i in range(0, p.size)]))
|
|
112
|
+
|
|
113
|
+
if cell is not None:
|
|
114
|
+
self.cell = cell
|
|
115
|
+
vertices = cell.vertices(return_coords=True)
|
|
116
|
+
self._members = []
|
|
117
|
+
counter = 0
|
|
118
|
+
|
|
119
|
+
for p in self.perm_list:
|
|
120
|
+
if len(vertices) > p.size:
|
|
121
|
+
temp_perm = Permutation(p, size=len(vertices))
|
|
122
|
+
reordered = temp_perm(vertices)
|
|
123
|
+
else:
|
|
124
|
+
reordered = p(vertices)
|
|
125
|
+
A = np.c_[np.array(vertices, dtype=float), np.ones(len(vertices))]
|
|
126
|
+
b = np.array(reordered, dtype=float)
|
|
127
|
+
|
|
128
|
+
M, _, _, _ = np.linalg.lstsq(A, b, rcond=None)
|
|
129
|
+
p_rep = GroupMemberRep(p, M, self)
|
|
130
|
+
if p.is_Identity:
|
|
131
|
+
self.identity = p_rep
|
|
132
|
+
self._members.append(p_rep)
|
|
133
|
+
counter += 1
|
|
134
|
+
|
|
135
|
+
def add_cell(self, cell):
|
|
136
|
+
return PermutationSetRepresentation(self.perm_list, cell=cell)
|
|
137
|
+
|
|
138
|
+
def members(self, perm=False):
|
|
139
|
+
if self.cell is None:
|
|
140
|
+
raise ValueError("Group does not have a domain - members have not been calculated")
|
|
141
|
+
if perm:
|
|
142
|
+
return [m.perm for m in self._members]
|
|
143
|
+
return self._members
|
|
144
|
+
|
|
145
|
+
def transform_between_perms(self, perm1, perm2):
|
|
146
|
+
member_perms = self.members(perm=True)
|
|
147
|
+
perm1 = Permutation.from_sequence(perm1)
|
|
148
|
+
perm2 = Permutation.from_sequence(perm2)
|
|
149
|
+
assert perm1 in member_perms
|
|
150
|
+
assert perm2 in member_perms
|
|
151
|
+
return self.get_member(~Permutation(perm1)) * self.get_member(Permutation(perm2))
|
|
152
|
+
|
|
153
|
+
def get_member(self, perm):
|
|
154
|
+
if not isinstance(perm, Permutation):
|
|
155
|
+
perm = Permutation.from_sequence(perm)
|
|
156
|
+
for m in self.members():
|
|
157
|
+
if m.perm == perm:
|
|
158
|
+
return m
|
|
159
|
+
raise ValueError("Permutation not a member of group")
|
|
160
|
+
|
|
161
|
+
def compute_num_reps(self, base_val=0):
|
|
162
|
+
""" Compute the numerical represention of each member as compared to the identity.
|
|
163
|
+
Where the numerical rep is:
|
|
164
|
+
|
|
165
|
+
M.index(id[0]) = a; M.remove(id[0])
|
|
166
|
+
M.index(id[1]) = b; M.remove(id[1])
|
|
167
|
+
M.index(id[2]) = c; M.remove(id[2])
|
|
168
|
+
|
|
169
|
+
o = (a * 2!) + (b * 1!) + (c * 0!)
|
|
170
|
+
"""
|
|
171
|
+
members = self.members()
|
|
172
|
+
res = {}
|
|
173
|
+
for m in members:
|
|
174
|
+
val, perm = m.compute_perm(base_val)
|
|
175
|
+
res[val] = perm
|
|
176
|
+
return res
|
|
177
|
+
|
|
178
|
+
def size(self):
|
|
179
|
+
return len(self.perm_list)
|
|
180
|
+
|
|
181
|
+
def __mul__(self, other_group):
|
|
182
|
+
# convert to set to remove duplicates
|
|
183
|
+
return PermutationSetRepresentation(list(set(self.perm_list + other_group.perm_list)))
|
|
184
|
+
|
|
185
|
+
def __repr__(self):
|
|
186
|
+
return "GS" + str(self.size())
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class GroupRepresentation(PermutationSetRepresentation):
|
|
190
|
+
"""
|
|
191
|
+
A representation of a group by its matrix operations.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
base_group: the sympy group that is being represented
|
|
195
|
+
cell (optional): the cell the group is representing the operations on
|
|
196
|
+
|
|
197
|
+
"""
|
|
198
|
+
|
|
199
|
+
def __init__(self, base_group, cell=None):
|
|
200
|
+
assert isinstance(base_group, PermutationGroup)
|
|
201
|
+
self.base_group = base_group
|
|
202
|
+
self.generators = []
|
|
203
|
+
if cell is not None:
|
|
204
|
+
self.cell = cell
|
|
205
|
+
vertices = cell.vertices(return_coords=True)
|
|
206
|
+
|
|
207
|
+
self._members = []
|
|
208
|
+
counter = 0
|
|
209
|
+
for g in self.base_group.elements:
|
|
210
|
+
if len(vertices) > g.size:
|
|
211
|
+
temp_perm = Permutation(g, size=len(vertices))
|
|
212
|
+
reordered = temp_perm(vertices)
|
|
213
|
+
else:
|
|
214
|
+
reordered = g(vertices)
|
|
215
|
+
A = np.c_[np.array(vertices, dtype=float), np.ones(len(vertices))]
|
|
216
|
+
b = np.array(reordered, dtype=float)
|
|
217
|
+
|
|
218
|
+
M, _, _, _ = np.linalg.lstsq(A, b, rcond=None)
|
|
219
|
+
p_rep = GroupMemberRep(g, M, self)
|
|
220
|
+
self._members.append(p_rep)
|
|
221
|
+
if g.is_Identity:
|
|
222
|
+
self.identity = p_rep
|
|
223
|
+
counter += 1
|
|
224
|
+
|
|
225
|
+
# this order produces simpler generator lists
|
|
226
|
+
# self.generators.reverse()
|
|
227
|
+
|
|
228
|
+
# temp_group_elems = self.base_group.elements
|
|
229
|
+
|
|
230
|
+
# temp_group_elems.remove(self.base_group.identity)
|
|
231
|
+
|
|
232
|
+
# remaining_members = self.compute_reps(self.base_group.identity,
|
|
233
|
+
# None, temp_group_elems)
|
|
234
|
+
# assert (len(remaining_members) == 0)
|
|
235
|
+
else:
|
|
236
|
+
self.cell = None
|
|
237
|
+
|
|
238
|
+
def conjugacy_class(self, g):
|
|
239
|
+
conj_class = set()
|
|
240
|
+
for x in self.members():
|
|
241
|
+
res = ~x * g * x
|
|
242
|
+
conj_class.add(res)
|
|
243
|
+
return conj_class
|
|
244
|
+
|
|
245
|
+
def add_cell(self, cell):
|
|
246
|
+
return GroupRepresentation(self.base_group, cell=cell)
|
|
247
|
+
|
|
248
|
+
def size(self):
|
|
249
|
+
if hasattr(self, "_members"):
|
|
250
|
+
assert len(self._members) == self.base_group.order()
|
|
251
|
+
return self.base_group.order()
|
|
252
|
+
|
|
253
|
+
def members(self, perm=False):
|
|
254
|
+
if self.cell is None:
|
|
255
|
+
raise ValueError("Group does not have a domain - members have not been calculated")
|
|
256
|
+
if perm:
|
|
257
|
+
return [m.perm for m in self._members]
|
|
258
|
+
return self._members
|
|
259
|
+
|
|
260
|
+
def transform_between_perms(self, perm1, perm2):
|
|
261
|
+
member_perms = self.members(perm=True)
|
|
262
|
+
perm1 = Permutation.from_sequence(perm1)
|
|
263
|
+
perm2 = Permutation.from_sequence(perm2)
|
|
264
|
+
assert perm1 in member_perms
|
|
265
|
+
assert perm2 in member_perms
|
|
266
|
+
return ~self.get_member(Permutation(perm1)) * self.get_member(Permutation(perm2))
|
|
267
|
+
|
|
268
|
+
def get_member(self, perm):
|
|
269
|
+
for m in self.members():
|
|
270
|
+
if m.perm == perm:
|
|
271
|
+
return m
|
|
272
|
+
raise ValueError("Permutation not a member of group")
|
|
273
|
+
|
|
274
|
+
# def compute_reps(self, g, path, remaining_members):
|
|
275
|
+
# # breadth first search to find generator representations of all members
|
|
276
|
+
# if len(remaining_members) == 0:
|
|
277
|
+
# return remaining_members
|
|
278
|
+
|
|
279
|
+
# next_candidates = []
|
|
280
|
+
# for generator in self.generators:
|
|
281
|
+
# new_perm = g*generator.perm
|
|
282
|
+
# if new_perm in remaining_members:
|
|
283
|
+
# if not path:
|
|
284
|
+
# new_path = generator.rep
|
|
285
|
+
# new_M = generator.transform_matrix
|
|
286
|
+
# print(new_M)
|
|
287
|
+
# assert (new_perm == generator.perm)
|
|
288
|
+
# self._members.append(generator)
|
|
289
|
+
# else:
|
|
290
|
+
# new_path = path.copy()
|
|
291
|
+
# new_path.extend(generator.rep)
|
|
292
|
+
# print(path)
|
|
293
|
+
# new_M = np.matmul(generator.transform_matrix, new_M)
|
|
294
|
+
# self._members.append(GroupMemberRep(new_perm,
|
|
295
|
+
# new_path,
|
|
296
|
+
# self))
|
|
297
|
+
# remaining_members.remove(new_perm)
|
|
298
|
+
# next_candidates.append((new_perm, new_path))
|
|
299
|
+
|
|
300
|
+
# for (new_perm, new_path) in next_candidates:
|
|
301
|
+
# remaining_members = self.compute_reps(new_perm,
|
|
302
|
+
# new_path,
|
|
303
|
+
# remaining_members)
|
|
304
|
+
# return remaining_members
|
|
305
|
+
|
|
306
|
+
def __mul__(self, other_group):
|
|
307
|
+
return GroupRepresentation(PermutationGroup(self.base_group.generators + other_group.base_group.generators))
|
|
308
|
+
|
|
309
|
+
def __truediv__(self, other_frac):
|
|
310
|
+
""" This isn't a mathematically accurate representation of
|
|
311
|
+
what it means to be a quotient group but it works on S3/S2
|
|
312
|
+
Have to compare cyclic forms as groups may not be defined on
|
|
313
|
+
the same number of elements
|
|
314
|
+
Doesn't work on D4/S2 but does on D4/C4 """
|
|
315
|
+
assert isinstance(other_frac, GroupRepresentation)
|
|
316
|
+
self_cyclic_gens = [gen.cyclic_form
|
|
317
|
+
for gen in self.base_group.generators]
|
|
318
|
+
other_cyclic_gens = [gen.cyclic_form
|
|
319
|
+
for gen in other_frac.base_group.generators]
|
|
320
|
+
if not all([c2 in self_cyclic_gens for c2 in other_cyclic_gens]):
|
|
321
|
+
raise ValueError("Invalid Quotient - mismatched cycles")
|
|
322
|
+
remaining_perms = [gen for gen in self.base_group.generators
|
|
323
|
+
if gen.cyclic_form not in other_cyclic_gens]
|
|
324
|
+
|
|
325
|
+
if len(remaining_perms) == 0:
|
|
326
|
+
raise ValueError("Invalid Quotient - no group formed")
|
|
327
|
+
|
|
328
|
+
return GroupRepresentation(PermutationGroup(remaining_perms))
|
|
329
|
+
|
|
330
|
+
def __repr__(self):
|
|
331
|
+
return "GR" + str(self.size())
|
|
332
|
+
|
|
333
|
+
# def __eq__(self, other):
|
|
334
|
+
# # TODO work on idea of group equality
|
|
335
|
+
# assert isinstance(other, GroupRepresentation)
|
|
336
|
+
# res = True
|
|
337
|
+
# for m in self.members():
|
|
338
|
+
# res = res and m in other.members()
|
|
339
|
+
# return res
|
|
340
|
+
|
|
341
|
+
def _to_dict(self):
|
|
342
|
+
return {"members": [m.perm.array_form for m in self._members]}
|
|
343
|
+
|
|
344
|
+
def dict_id(self):
|
|
345
|
+
return "Group"
|
|
346
|
+
|
|
347
|
+
def _from_dict(o_dict):
|
|
348
|
+
perm_group = PermutationGroup([Permutation(m) for m in o_dict["members"]])
|
|
349
|
+
# , o_dict["cell"]
|
|
350
|
+
return GroupRepresentation(perm_group)
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def get_sym_group(n):
|
|
354
|
+
return GroupRepresentation(SymmetricGroup(n))
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def get_cyc_group(n):
|
|
358
|
+
return GroupRepresentation(CyclicGroup(n))
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
S1 = GroupRepresentation(SymmetricGroup(1))
|
|
362
|
+
S2 = GroupRepresentation(SymmetricGroup(2))
|
|
363
|
+
S3 = GroupRepresentation(SymmetricGroup(3))
|
|
364
|
+
S4 = GroupRepresentation(SymmetricGroup(4))
|
|
365
|
+
|
|
366
|
+
D4 = GroupRepresentation(DihedralGroup(4))
|
|
367
|
+
|
|
368
|
+
C3 = GroupRepresentation(CyclicGroup(3))
|
|
369
|
+
C4 = GroupRepresentation(CyclicGroup(4))
|
|
370
|
+
|
|
371
|
+
Z2 = GroupRepresentation(CyclicGroup(2))
|
|
372
|
+
Z3 = GroupRepresentation(CyclicGroup(3))
|
|
373
|
+
Z4 = GroupRepresentation(CyclicGroup(4))
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
D2 = GroupRepresentation(DihedralGroup(2))
|
|
377
|
+
A4 = GroupRepresentation(AlternatingGroup(4))
|
|
378
|
+
A3 = GroupRepresentation(AlternatingGroup(3))
|
|
379
|
+
|
|
380
|
+
tri_C3 = PermutationSetRepresentation([Permutation([0, 1, 2]), Permutation([2, 0, 1]), Permutation([1, 0, 2])])
|
|
381
|
+
# tet_edges = PermutationSetRepresentation([Permutation([0, 1, 2, 3]), Permutation([0, 2, 3, 1]), Permutation([1, 2, 0, 3]),
|
|
382
|
+
# Permutation([0, 3, 1, 2]), Permutation([1, 3, 2, 0]), Permutation([2, 3, 0, 1])])
|
|
383
|
+
tet_edges = PermutationSetRepresentation([Permutation([0, 1, 2, 3]), Permutation([1, 2, 3, 0]), Permutation([2, 3, 0, 1]),
|
|
384
|
+
Permutation([1, 3, 0, 2]), Permutation([2, 0, 1, 3]), Permutation([3, 0, 1, 2])])
|
|
385
|
+
tet_faces = PermutationSetRepresentation([Permutation([0, 1, 2, 3]), Permutation([1, 2, 3, 0]), Permutation([1, 3, 2, 0]),
|
|
386
|
+
Permutation([3, 0, 2, 1])])
|
|
387
|
+
|
|
388
|
+
sq_edges = PermutationSetRepresentation([Permutation([0, 1, 2, 3]), Permutation([1, 2, 3, 0]), Permutation([3, 0, 1, 2]), Permutation([2, 3, 0, 1])])
|
fuse/serialisation.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from fuse import *
|
|
3
|
+
from fuse.spaces.polynomial_spaces import ConstructedPolynomialSpace
|
|
4
|
+
from fuse.spaces.element_sobolev_spaces import ElementSobolevSpace
|
|
5
|
+
from fuse.spaces.interpolation_spaces import InterpolationSpace
|
|
6
|
+
from fuse.traces import Trace
|
|
7
|
+
from fuse.triples import ImmersedDOFs
|
|
8
|
+
import sympy as sp
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ElementSerialiser():
|
|
12
|
+
"""
|
|
13
|
+
This class provides encoding and decoding to json for objects in the
|
|
14
|
+
fuse language.
|
|
15
|
+
|
|
16
|
+
Methods
|
|
17
|
+
--------
|
|
18
|
+
|
|
19
|
+
encode: obj: fuse class
|
|
20
|
+
- converts object to a json representation
|
|
21
|
+
decode: obj_str: String
|
|
22
|
+
- converts json string to obj
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self):
|
|
26
|
+
self.obj_id_counter = {}
|
|
27
|
+
self.seen_objs = {}
|
|
28
|
+
self.obj_storage = {}
|
|
29
|
+
|
|
30
|
+
self.obj_types = {"Cell": Point,
|
|
31
|
+
"Edge": Edge,
|
|
32
|
+
"Triple": ElementTriple,
|
|
33
|
+
"Group": GroupRepresentation,
|
|
34
|
+
"SobolevSpace": ElementSobolevSpace,
|
|
35
|
+
"InterpolationSpace": InterpolationSpace,
|
|
36
|
+
"PolynomialSpace": PolynomialSpace,
|
|
37
|
+
"ConstructedPolynomialSpace": ConstructedPolynomialSpace,
|
|
38
|
+
"DOF": DOF,
|
|
39
|
+
"ImmersedDOF": ImmersedDOFs,
|
|
40
|
+
"DOFGen": DOFGenerator,
|
|
41
|
+
"Delta": DeltaPairing,
|
|
42
|
+
"L2Inner": L2Pairing,
|
|
43
|
+
"PolynomialKernel": PolynomialKernel,
|
|
44
|
+
"PointKernel": PointKernel,
|
|
45
|
+
"Trace": Trace
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
def encode(self, obj):
|
|
49
|
+
base_obj = self.encode_traverse(obj)
|
|
50
|
+
self.obj_storage["encoded_obj"] = base_obj
|
|
51
|
+
return json.dumps(self.obj_storage, indent=2)
|
|
52
|
+
|
|
53
|
+
def decode(self, obj_str):
|
|
54
|
+
obj_dict = json.loads(obj_str)
|
|
55
|
+
obj = self.decode_traverse(obj_dict["encoded_obj"], obj_dict)
|
|
56
|
+
return obj
|
|
57
|
+
|
|
58
|
+
def encode_traverse(self, obj, path=[]):
|
|
59
|
+
obj_dict = {}
|
|
60
|
+
|
|
61
|
+
if isinstance(obj, list) or isinstance(obj, tuple):
|
|
62
|
+
res_array = [{} for i in range(len(obj))]
|
|
63
|
+
for i in range(len(obj)):
|
|
64
|
+
dfs_res = self.encode_traverse(obj[i], path + [i])
|
|
65
|
+
res_array[i] = dfs_res
|
|
66
|
+
return res_array
|
|
67
|
+
|
|
68
|
+
if obj in self.seen_objs.keys():
|
|
69
|
+
return self.seen_objs[obj]["id"]
|
|
70
|
+
|
|
71
|
+
if hasattr(obj, "_to_dict"):
|
|
72
|
+
for (key, val) in obj._to_dict().items():
|
|
73
|
+
obj_dict[key] = self.encode_traverse(val, path + [key])
|
|
74
|
+
obj_id = self.get_id(obj)
|
|
75
|
+
self.store_obj(obj, obj.dict_id(), obj_id, obj_dict, path)
|
|
76
|
+
return obj.dict_id() + "/" + str(obj_id)
|
|
77
|
+
|
|
78
|
+
if isinstance(obj, sp.core.containers.Tuple) or isinstance(obj, sp.Expr):
|
|
79
|
+
return "Sympy/" + sp.srepr(obj)
|
|
80
|
+
|
|
81
|
+
return obj
|
|
82
|
+
|
|
83
|
+
def get_id(self, obj):
|
|
84
|
+
obj_name = obj.dict_id()
|
|
85
|
+
if obj_name in self.obj_id_counter.keys():
|
|
86
|
+
obj_id = self.obj_id_counter[obj_name]
|
|
87
|
+
self.obj_id_counter[obj_name] += 1
|
|
88
|
+
else:
|
|
89
|
+
obj_id = 0
|
|
90
|
+
self.obj_id_counter[obj_name] = 1
|
|
91
|
+
return obj_id
|
|
92
|
+
|
|
93
|
+
def store_obj(self, obj, name, obj_id, obj_dict, path):
|
|
94
|
+
self.seen_objs[obj] = {"id": name + "/" + str(obj_id), "path": path, "dict": obj_dict}
|
|
95
|
+
if name in self.obj_storage.keys():
|
|
96
|
+
self.obj_storage[name][obj_id] = obj_dict
|
|
97
|
+
else:
|
|
98
|
+
self.obj_storage[name] = {obj_id: obj_dict}
|
|
99
|
+
|
|
100
|
+
def decode_traverse(self, obj, obj_dict):
|
|
101
|
+
|
|
102
|
+
if isinstance(obj, str):
|
|
103
|
+
split_str = obj.split("/")
|
|
104
|
+
if split_str[0] in self.obj_types.keys():
|
|
105
|
+
name, obj_id = split_str[0], split_str[1]
|
|
106
|
+
sub_dict = obj_dict[name][obj_id]
|
|
107
|
+
for (key, value) in sub_dict.items():
|
|
108
|
+
sub_dict[key] = self.decode_traverse(value, obj_dict)
|
|
109
|
+
return self.obj_types[name]._from_dict(sub_dict)
|
|
110
|
+
elif split_str[0] == "Sympy":
|
|
111
|
+
return sp.parse_expr(" ".join(split_str[1:]))
|
|
112
|
+
else:
|
|
113
|
+
return obj
|
|
114
|
+
elif isinstance(obj, list) or isinstance(obj, tuple):
|
|
115
|
+
res_array = [0 for i in range(len(obj))]
|
|
116
|
+
for i in range(len(obj)):
|
|
117
|
+
dfs_res = self.decode_traverse(obj[i], obj_dict)
|
|
118
|
+
res_array[i] = dfs_res
|
|
119
|
+
return res_array
|
|
120
|
+
|
|
121
|
+
return obj
|
fuse/spaces/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
class ElementSobolevSpace(object):
|
|
2
|
+
"""
|
|
3
|
+
Representation of a Sobolev space on a single cell
|
|
4
|
+
|
|
5
|
+
:param: *underlying_space*: The UFL representation of the Sobolev Space
|
|
6
|
+
:param: *domain*: (Optional) the cell defined over- if not originally provided it should be provided during use.
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, parents, domain=None):
|
|
11
|
+
self.domain = domain
|
|
12
|
+
self.parents = parents
|
|
13
|
+
|
|
14
|
+
def __lt__(self, other):
|
|
15
|
+
"""In common with intrinsic Python sets, < indicates "is a proper subset of"."""
|
|
16
|
+
return any([isinstance(other, p) for p in self.parents])
|
|
17
|
+
|
|
18
|
+
def _to_dict(self):
|
|
19
|
+
return {"space": str(self)}
|
|
20
|
+
|
|
21
|
+
def dict_id(self):
|
|
22
|
+
return "SobolevSpace"
|
|
23
|
+
|
|
24
|
+
def _from_dict(obj_dict):
|
|
25
|
+
space_name = obj_dict["space"]
|
|
26
|
+
if space_name == "L2":
|
|
27
|
+
return CellL2
|
|
28
|
+
elif space_name == "H1":
|
|
29
|
+
return CellH1
|
|
30
|
+
elif space_name == "HDiv":
|
|
31
|
+
return CellHDiv
|
|
32
|
+
elif space_name == "HCurl":
|
|
33
|
+
return CellHCurl
|
|
34
|
+
elif space_name == "H2":
|
|
35
|
+
return CellH2
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class CellH1(ElementSobolevSpace):
|
|
39
|
+
|
|
40
|
+
def __init__(self, cell):
|
|
41
|
+
super(CellH1, self).__init__([CellL2, CellHDiv, CellHCurl], cell)
|
|
42
|
+
|
|
43
|
+
def __repr__(self):
|
|
44
|
+
return "H1"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class CellHDiv(ElementSobolevSpace):
|
|
48
|
+
|
|
49
|
+
def __init__(self, cell):
|
|
50
|
+
super(CellHDiv, self).__init__([CellL2], cell)
|
|
51
|
+
|
|
52
|
+
def __repr__(self):
|
|
53
|
+
return "HDiv"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class CellHCurl(ElementSobolevSpace):
|
|
57
|
+
|
|
58
|
+
def __init__(self, cell):
|
|
59
|
+
super(CellHCurl, self).__init__([CellL2], cell)
|
|
60
|
+
|
|
61
|
+
def __repr__(self):
|
|
62
|
+
return "HCurl"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class CellH2(ElementSobolevSpace):
|
|
66
|
+
|
|
67
|
+
def __init__(self, cell):
|
|
68
|
+
super(CellH2, self).__init__([CellL2, CellHDiv, CellHCurl, CellH1], cell)
|
|
69
|
+
|
|
70
|
+
def __repr__(self):
|
|
71
|
+
return "H2"
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class CellL2(ElementSobolevSpace):
|
|
75
|
+
|
|
76
|
+
def __init__(self, cell):
|
|
77
|
+
super(CellL2, self).__init__([], cell)
|
|
78
|
+
|
|
79
|
+
def __repr__(self):
|
|
80
|
+
return "L2"
|