├── .gitignore
├── Examples
├── DarcyFlow
│ ├── driver.py
│ ├── triangles.txt
│ └── vertices.txt
├── HodgeDecomposition
│ ├── driver.py
│ ├── mesh_example.elements
│ ├── mesh_example.vertices
│ └── mesh_example.xml
├── MakeMesh
│ ├── ExpectedOutput
│ │ ├── square_8.elements
│ │ ├── square_8.vertices
│ │ └── square_8.xml
│ ├── make_mesh.py
│ ├── s.txt
│ ├── square_8.elements
│ ├── square_8.vertices
│ ├── square_8.xml
│ └── v.txt
├── Ranking
│ ├── data.txt
│ └── driver.py
├── ResonantCavity
│ ├── driver.py
│ ├── triangles.txt
│ └── vertices.txt
└── RipsComplex
│ ├── 300pts.mtx
│ └── driver.py
├── LICENSE.txt
├── README.md
├── pydec
└── pydec
│ ├── __init__.py
│ ├── dec
│ ├── __init__.py
│ ├── abstract_simplicial_complex.py
│ ├── cochain.py
│ ├── cube_array.py
│ ├── info.py
│ ├── regular_cube_complex.py
│ ├── rips_complex.py
│ ├── simplex_array.py
│ ├── simplicial_complex.py
│ └── tests
│ │ ├── meshes
│ │ ├── README.txt
│ │ ├── cube.elements
│ │ ├── cube.vertices
│ │ ├── cube.xml
│ │ ├── sphere3.elements
│ │ ├── sphere3.vertices
│ │ ├── sphere3.xml
│ │ ├── torus_tet.elements
│ │ ├── torus_tet.vertices
│ │ └── torus_tet.xml
│ │ ├── test_abstract_simplicial_complex.py
│ │ ├── test_cochain.py
│ │ ├── test_cube_array.py
│ │ ├── test_meshes.py
│ │ ├── test_rips_complex.py
│ │ ├── test_simplex_array.py
│ │ └── test_simplicial_complex.py
│ ├── fem
│ ├── __init__.py
│ ├── info.py
│ ├── innerproduct.py
│ └── tests
│ │ └── test_innerproduct.py
│ ├── io
│ ├── __init__.py
│ ├── arrayio.py
│ ├── complex_io.py
│ ├── info.py
│ ├── meshio.py
│ ├── misc.py
│ └── tests
│ │ ├── test_arrayio.py
│ │ └── test_misc.py
│ ├── math
│ ├── __init__.py
│ ├── circumcenter.py
│ ├── combinatorial.py
│ ├── info.py
│ ├── kd_tree.py
│ ├── parity.py
│ ├── tests
│ │ ├── test_circumcenter.py
│ │ ├── test_combinatorial.py
│ │ ├── test_graph.py
│ │ ├── test_kd_tree.py
│ │ ├── test_parity.py
│ │ └── test_volume.py
│ └── volume.py
│ ├── mesh
│ ├── __init__.py
│ ├── __init__.py~
│ ├── base_mesh.py
│ ├── generation.py
│ ├── info.py
│ ├── ncube.py
│ ├── regular_cube.py
│ ├── simplex.py
│ ├── subdivision.py
│ └── tests
│ │ ├── test_ncube.py
│ │ ├── test_simplex.py
│ │ └── test_subdivision.py
│ ├── testing
│ ├── __init__.py
│ └── __init__.py~
│ ├── util
│ ├── __init__.py
│ ├── info.py
│ ├── tests
│ │ └── placeholder_tests.py
│ └── util.py
│ ├── version.py
│ └── vis
│ ├── __init__.py
│ ├── draw.py
│ ├── info.py
│ └── tests
│ └── placeholder_tests.py
└── pyproject.toml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Git ignores for PyDEC.
2 | # Ported from original .svnignore
3 |
4 | *.pyc
5 | *.bak
6 | *.so
7 | *.swp
8 | dist
9 | build
10 | *.egg-info
11 |
--------------------------------------------------------------------------------
/Examples/DarcyFlow/driver.py:
--------------------------------------------------------------------------------
1 | """
2 | Darcy flow in a triangle mesh of a planar domain, with constant
3 | velocity prescribed on boundary.
4 |
5 | Reference :
6 |
7 | Numerical method for Darcy flow derived using Discrete Exterior Calculus
8 | A. N. Hirani, K. B. Nakshatrala, J. H. Chaudhry
9 | See arXiv:0810.3434v3 [math.NA] on http://arxiv.org/abs/0810.3434
10 |
11 | """
12 | from numpy import zeros, sort, asarray, loadtxt, array, dot, \
13 | concatenate, sign, vstack, argmax, nonzero
14 | from numpy.linalg import norm, det
15 | from scipy.sparse import bmat
16 | from scipy.sparse.linalg import spsolve
17 | from matplotlib.pylab import figure, gca, triplot, show
18 | from pydec import simplicial_complex, simplex_quivers, signed_volume
19 |
20 | velocity = array([1.,0])
21 | # Read the mesh
22 | vertices = loadtxt('vertices.txt')
23 | triangles = loadtxt('triangles.txt', dtype='int') - 1
24 | # Make a simplicial complex from it
25 | sc = simplicial_complex((vertices,triangles))
26 | # Nk is number of k-simplices
27 | N1 = sc[1].num_simplices
28 | N2 = sc[2].num_simplices
29 | # Permeability is k > 0 and viscosity is mu > 0
30 | k = 1; mu = 1
31 | # The matrix for the full linear system for Darcy in 2D, not taking into
32 | # account the boundary conditions, is :
33 | # [-(mu/k)star1 d1^T ]
34 | # [ d1 Z ]
35 | # where Z is a zero matrix of size N2 by N2.
36 | # The block sizes are
37 | # N1 X N1 N1 X N2
38 | # N2 X N1 N2 X N2
39 |
40 | d1 = sc[1].d; star1 = sc[1].star
41 | A = bmat([[(-mu/k)*sc[1].star, sc[1].d.T],
42 | [sc[1].d, None]], format='csr')
43 | b = zeros(N1 + N2) # RHS vector
44 | all_fluxes = zeros(N1)
45 | # Find boundary and internal edges
46 | boundary_edges = sc.boundary(); boundary_edges.sort()
47 | boundary_indices = list(sort([sc[1].simplex_to_index[e]
48 | for e in boundary_edges]))
49 | num_boundary_edges = len(boundary_indices)
50 | internal_edges = set(sc[1].simplex_to_index.keys()) - set(boundary_edges)
51 | internal_indices = list(sort([sc[1].simplex_to_index[e]
52 | for e in internal_edges]))
53 | num_internal_edges = sc[1].num_simplices - num_boundary_edges
54 | # Assume triangles oriented the same way so can look at any triangle
55 | s = sign(det(vertices[triangles[0,1:]] - vertices[triangles[0,0]]))
56 | for i, e in enumerate(boundary_edges):
57 | evector = (-1)**e.parity * (vertices[e[1]] - vertices[e[0]])
58 | normal = array([-evector[1], evector[0]])
59 | all_fluxes[boundary_indices[i]] = -s * (1/norm(evector)**2) * \
60 | dot(velocity, normal) * \
61 | abs(det(vstack((normal, evector))))
62 | pressures = zeros(N2)
63 | # Adjust RHS for known fluxes and pressures
64 | b = b - A * concatenate((all_fluxes,pressures))
65 | # Remove entries of b corresponding to boundary fluxes and known pressure
66 | # Pressure at the right most triangle circumcenter is assumed known
67 | pressure_indices = list(range(N1, N1+N2))
68 | pressure_indices.remove(N1 + argmax(sc[2].circumcenter[:,0]))
69 | entries_to_keep = concatenate((internal_indices, pressure_indices))
70 | b = b[entries_to_keep]
71 | # Remove corresponding rows and columns of A
72 | A = A[entries_to_keep][:,entries_to_keep]
73 | u = spsolve(A,b)
74 | fluxes = u[0:len(internal_indices)]
75 | pressures[array(pressure_indices)-N1] = u[len(internal_indices):]
76 | # Plot the pressures
77 | figure(); ax = gca();
78 | ax.set_xlabel('x', fontsize=20)
79 | ax.set_ylabel('Pressure', fontsize=20)
80 | ax.plot(sc[2].circumcenter[:,0], pressures, 'ro', markersize=8, mec='r')
81 | # Draw a line of slope -1 through the known presure point
82 | xmax = max(sc[2].circumcenter[:,0])
83 | xmin = min(sc[2].circumcenter[:,0])
84 | ax.plot([xmin, xmax], [xmax - xmin, 0], 'k', linewidth=2)
85 | ax.legend(['DEC', 'Analytical'], numpoints=1)
86 | # Plot the triangles
87 | figure(); ax = gca()
88 | ax.triplot(vertices[:,0], vertices[:,1], triangles)
89 | # Insert the computed fluxes into vector of all fluxes
90 | all_fluxes[internal_indices] = fluxes
91 | # Whitney interpolate flux and sample at barycenters. Then
92 | # rotate 90 degrees in the sense opposite to triangle orientation
93 | v_bases,v_arrows = simplex_quivers(sc, all_fluxes)
94 | v_arrows = -s * vstack((-v_arrows[:,1], v_arrows[:,0])).T
95 | # Plot the resulting vector field at the barycenters
96 | ax.quiver(v_bases[:,0],v_bases[:,1],v_arrows[:,0],v_arrows[:,1],
97 | units='dots', width=1, scale=1./30)
98 | ax.axis('equal')
99 | ax.set_title('Flux interpolated using Whitney map \n' \
100 | ' and visualized as velocity at barycenters\n')
101 |
102 | show()
103 |
104 |
--------------------------------------------------------------------------------
/Examples/DarcyFlow/triangles.txt:
--------------------------------------------------------------------------------
1 | 14 2 61
2 | 58 6 93
3 | 93 7 98
4 | 115 9 149
5 | 56 13 72
6 | 44 1 62
7 | 5 6 58
8 | 7 8 98
9 | 57 46 140
10 | 24 3 60
11 | 34 4 59
12 | 98 8 115
13 | 61 15 75
14 | 114 19 151
15 | 55 23 73
16 | 15 16 75
17 | 13 14 72
18 | 2 15 61
19 | 95 17 132
20 | 1 5 62
21 | 17 18 132
22 | 56 49 129
23 | 18 19 114
24 | 23 24 73
25 | 19 20 151
26 | 60 25 76
27 | 113 29 152
28 | 54 33 74
29 | 3 25 60
30 | 25 26 76
31 | 136 45 176
32 | 96 27 130
33 | 27 28 130
34 | 33 34 74
35 | 4 35 59
36 | 59 35 77
37 | 28 29 113
38 | 29 30 152
39 | 6 7 93
40 | 9 10 149
41 | 35 36 77
42 | 94 37 131
43 | 37 38 131
44 | 112 39 157
45 | 57 43 71
46 | 38 39 112
47 | 54 47 128
48 | 39 40 157
49 | 55 48 127
50 | 147 78 191
51 | 146 45 179
52 | 124 50 143
53 | 42 43 57
54 | 12 13 56
55 | 22 23 55
56 | 158 53 180
57 | 32 33 54
58 | 126 51 141
59 | 133 56 159
60 | 102 52 181
61 | 59 47 74
62 | 103 40 170
63 | 60 48 73
64 | 152 30 169
65 | 61 49 72
66 | 151 20 168
67 | 43 44 71
68 | 149 10 164
69 | 58 46 71
70 | 104 53 123
71 | 77 36 94
72 | 36 37 94
73 | 76 26 96
74 | 26 27 96
75 | 75 16 95
76 | 16 17 95
77 | 46 57 71
78 | 5 58 62
79 | 41 42 97
80 | 42 57 97
81 | 180 53 182
82 | 10 11 164
83 | 134 54 163
84 | 30 31 169
85 | 135 55 162
86 | 20 21 168
87 | 31 32 134
88 | 122 63 172
89 | 21 22 135
90 | 185 51 190
91 | 11 12 133
92 | 186 50 187
93 | 97 57 183
94 | 120 86 129
95 | 62 58 71
96 | 44 62 71
97 | 49 56 72
98 | 14 61 72
99 | 48 55 73
100 | 24 60 73
101 | 47 54 74
102 | 34 59 74
103 | 49 61 75
104 | 120 69 143
105 | 48 60 76
106 | 119 68 141
107 | 47 59 77
108 | 125 52 142
109 | 121 67 142
110 | 121 88 128
111 | 119 87 127
112 | 105 66 177
113 | 140 85 183
114 | 91 65 108
115 | 147 51 173
116 | 107 65 156
117 | 106 80 148
118 | 106 63 155
119 | 145 50 171
120 | 92 66 109
121 | 137 45 178
122 | 46 58 93
123 | 153 64 184
124 | 114 69 132
125 | 146 79 189
126 | 113 68 130
127 | 148 80 181
128 | 112 67 131
129 | 123 53 158
130 | 110 64 167
131 | 129 86 159
132 | 108 65 165
133 | 142 52 144
134 | 109 66 166
135 | 127 87 162
136 | 8 9 115
137 | 93 70 116
138 | 47 77 94
139 | 94 67 121
140 | 49 75 95
141 | 95 69 120
142 | 48 76 96
143 | 96 68 119
144 | 155 63 161
145 | 116 85 140
146 | 115 89 123
147 | 70 93 98
148 | 105 79 145
149 | 137 81 150
150 | 154 81 182
151 | 122 85 161
152 | 107 78 147
153 | 145 79 179
154 | 146 101 191
155 | 128 88 163
156 | 148 52 174
157 | 40 41 170
158 | 150 81 184
159 | 89 104 123
160 | 138 101 189
161 | 143 50 186
162 | 156 65 188
163 | 100 80 155
164 | 141 51 185
165 | 102 78 156
166 | 134 91 169
167 | 126 82 173
168 | 135 92 168
169 | 104 89 167
170 | 133 90 164
171 | 110 90 175
172 | 111 86 186
173 | 112 83 125
174 | 103 83 157
175 | 113 82 126
176 | 108 82 152
177 | 114 84 124
178 | 109 84 151
179 | 110 89 149
180 | 70 98 115
181 | 116 70 158
182 | 46 93 116
183 | 65 91 117
184 | 117 88 144
185 | 66 92 118
186 | 118 87 185
187 | 87 119 141
188 | 48 96 119
189 | 86 120 143
190 | 49 95 120
191 | 52 102 144
192 | 47 94 121
193 | 41 97 170
194 | 170 97 172
195 | 70 115 123
196 | 161 85 180
197 | 124 84 171
198 | 69 114 124
199 | 125 83 174
200 | 67 112 125
201 | 165 107 173
202 | 68 113 126
203 | 118 92 162
204 | 48 119 127
205 | 117 91 163
206 | 47 121 128
207 | 111 90 159
208 | 49 120 129
209 | 68 96 130
210 | 28 113 130
211 | 67 94 131
212 | 38 112 131
213 | 69 95 132
214 | 18 114 132
215 | 12 56 133
216 | 86 111 159
217 | 32 54 134
218 | 88 117 163
219 | 22 55 135
220 | 87 118 162
221 | 160 106 174
222 | 78 102 136
223 | 80 100 137
224 | 147 101 190
225 | 66 118 138
226 | 145 99 187
227 | 46 116 140
228 | 122 97 183
229 | 68 126 141
230 | 138 118 185
231 | 88 121 142
232 | 67 125 142
233 | 69 124 143
234 | 139 111 186
235 | 144 102 188
236 | 88 142 144
237 | 150 99 179
238 | 184 139 187
239 | 177 138 189
240 | 176 146 191
241 | 51 126 173
242 | 52 125 174
243 | 136 102 181
244 | 90 110 164
245 | 89 115 149
246 | 45 137 150
247 | 99 145 179
248 | 92 109 168
249 | 84 114 151
250 | 91 108 169
251 | 82 113 152
252 | 64 139 184
253 | 53 104 154
254 | 137 100 182
255 | 81 137 182
256 | 80 106 155
257 | 65 117 188
258 | 78 107 156
259 | 40 103 157
260 | 83 112 157
261 | 85 116 158
262 | 70 123 158
263 | 56 129 159
264 | 90 133 159
265 | 83 103 160
266 | 63 106 160
267 | 63 122 161
268 | 100 155 161
269 | 55 127 162
270 | 92 135 162
271 | 54 128 163
272 | 91 134 163
273 | 11 133 164
274 | 110 149 164
275 | 65 107 165
276 | 82 108 165
277 | 66 105 166
278 | 84 109 166
279 | 89 110 167
280 | 21 135 168
281 | 109 151 168
282 | 31 134 169
283 | 108 152 169
284 | 160 103 172
285 | 97 122 172
286 | 50 124 171
287 | 105 145 171
288 | 63 160 172
289 | 103 170 172
290 | 107 147 173
291 | 82 165 173
292 | 106 148 174
293 | 83 160 174
294 | 64 110 175
295 | 90 111 175
296 | 78 136 176
297 | 45 146 176
298 | 79 105 177
299 | 66 138 177
300 | 45 136 178
301 | 80 137 178
302 | 79 146 179
303 | 45 150 179
304 | 85 158 180
305 | 100 161 180
306 | 52 148 181
307 | 53 154 182
308 | 100 180 182
309 | 85 122 183
310 | 57 140 183
311 | 99 150 184
312 | 81 153 184
313 | 101 138 190
314 | 87 141 185
315 | 50 145 187
316 | 86 143 186
317 | 99 184 187
318 | 139 186 187
319 | 117 144 188
320 | 102 156 188
321 | 101 146 189
322 | 79 177 189
323 | 51 147 190
324 | 138 185 190
325 | 101 147 191
326 | 78 176 191
327 | 104 167 153
328 | 64 153 167
329 | 104 153 154
330 | 81 154 153
331 | 105 171 166
332 | 84 166 171
333 | 111 139 175
334 | 64 175 139
335 | 136 181 178
336 | 80 178 181
337 |
--------------------------------------------------------------------------------
/Examples/DarcyFlow/vertices.txt:
--------------------------------------------------------------------------------
1 | -1.5707963267949e+00 -1.5707963267949e+00
2 | 1.5707963267949e+00 -1.5707963267949e+00
3 | 1.5707963267949e+00 1.5707963267949e+00
4 | -1.5707963267949e+00 1.5707963267949e+00
5 | -1.2851969946504e+00 -1.5707963267949e+00
6 | -9.9959766250584e-01 -1.5707963267949e+00
7 | -7.1399833036132e-01 -1.5707963267949e+00
8 | -4.2839899821679e-01 -1.5707963267949e+00
9 | -1.4279966607226e-01 -1.5707963267949e+00
10 | 1.4279966607226e-01 -1.5707963267949e+00
11 | 4.2839899821679e-01 -1.5707963267949e+00
12 | 7.1399833036132e-01 -1.5707963267949e+00
13 | 9.9959766250584e-01 -1.5707963267949e+00
14 | 1.2851969946504e+00 -1.5707963267949e+00
15 | 1.5707963267949e+00 -1.2851969946504e+00
16 | 1.5707963267949e+00 -9.9959766250584e-01
17 | 1.5707963267949e+00 -7.1399833036132e-01
18 | 1.5707963267949e+00 -4.2839899821679e-01
19 | 1.5707963267949e+00 -1.4279966607226e-01
20 | 1.5707963267949e+00 1.4279966607226e-01
21 | 1.5707963267949e+00 4.2839899821679e-01
22 | 1.5707963267949e+00 7.1399833036132e-01
23 | 1.5707963267949e+00 9.9959766250584e-01
24 | 1.5707963267949e+00 1.2851969946504e+00
25 | 1.2851969946504e+00 1.5707963267949e+00
26 | 9.9959766250584e-01 1.5707963267949e+00
27 | 7.1399833036132e-01 1.5707963267949e+00
28 | 4.2839899821679e-01 1.5707963267949e+00
29 | 1.4279966607226e-01 1.5707963267949e+00
30 | -1.4279966607226e-01 1.5707963267949e+00
31 | -4.2839899821679e-01 1.5707963267949e+00
32 | -7.1399833036132e-01 1.5707963267949e+00
33 | -9.9959766250584e-01 1.5707963267949e+00
34 | -1.2851969946504e+00 1.5707963267949e+00
35 | -1.5707963267949e+00 1.2851969946504e+00
36 | -1.5707963267949e+00 9.9959766250584e-01
37 | -1.5707963267949e+00 7.1399833036132e-01
38 | -1.5707963267949e+00 4.2839899821679e-01
39 | -1.5707963267949e+00 1.4279966607226e-01
40 | -1.5707963267949e+00 -1.4279966607226e-01
41 | -1.5707963267949e+00 -4.2839899821679e-01
42 | -1.5707963267949e+00 -7.1399833036132e-01
43 | -1.5707963267949e+00 -9.9959766250584e-01
44 | -1.5707963267949e+00 -1.2851969946504e+00
45 | 5.3804639787558e-04 6.5183191051434e-03
46 | -1.0776794790591e+00 -1.0913692420012e+00
47 | -1.1452799446275e+00 1.1350488018016e+00
48 | 1.1288013808513e+00 1.1513638355768e+00
49 | 1.1466005352741e+00 -1.1355299080426e+00
50 | 7.3561463731961e-01 -4.2610818545374e-01
51 | 4.0533138140781e-01 7.7426773191769e-01
52 | -7.0351375053933e-01 3.6828977312604e-01
53 | -3.4503986557309e-01 -7.5568660423878e-01
54 | -8.6931157270623e-01 1.3054994964146e+00
55 | 1.2996023488063e+00 8.7563266501509e-01
56 | 8.7655397132341e-01 -1.3072898280179e+00
57 | -1.2884800976119e+00 -8.7330025735635e-01
58 | -1.1553827795023e+00 -1.3468677926918e+00
59 | -1.3472183841835e+00 1.3459179093054e+00
60 | 1.3452105621022e+00 1.3480514538732e+00
61 | 1.3472309863375e+00 -1.3459297401208e+00
62 | -1.3830470173502e+00 -1.3863039747969e+00
63 | -8.9338040816334e-01 -2.7704048583697e-01
64 | 2.0030779903131e-01 -8.1546617954308e-01
65 | -2.5618109804159e-01 8.9045110933802e-01
66 | 8.4397225139735e-01 2.5791481747652e-01
67 | -1.1620981548862e+00 6.0090156891149e-01
68 | 5.9546651652341e-01 1.1714125655215e+00
69 | 1.1569439790688e+00 -6.0362902721501e-01
70 | -5.7329430432987e-01 -1.1436293272383e+00
71 | -1.3422299236802e+00 -1.1634595615637e+00
72 | 1.1352898433573e+00 -1.3907703308471e+00
73 | 1.3886684168254e+00 1.1379042510810e+00
74 | -1.1345398206219e+00 1.3905969289676e+00
75 | 1.3934384260542e+00 -1.1282582125054e+00
76 | 1.1249540725348e+00 1.3952048056568e+00
77 | -1.3936838668720e+00 1.1287105737469e+00
78 | -7.2971324784282e-02 4.8290942597957e-01
79 | 4.8303871141493e-01 5.5671689883874e-02
80 | -5.1204108584259e-01 -8.6950408078312e-02
81 | -6.3617798218521e-02 -4.9947678512246e-01
82 | 1.1087789550446e-01 1.1013095509110e+00
83 | -1.1475391353087e+00 1.1842225101262e-01
84 | 1.0787484939799e+00 -1.1820396499226e-01
85 | -8.1103760230864e-01 -7.1296242514887e-01
86 | 7.8488698039661e-01 -8.6803380620987e-01
87 | 8.3888499858433e-01 7.9284914248399e-01
88 | -7.6777548575808e-01 8.5834281480697e-01
89 | -9.4186756616889e-02 -1.0732982433562e+00
90 | 4.4648336310743e-01 -1.1052039127239e+00
91 | -4.0472848068083e-01 1.1118376268635e+00
92 | 1.0868356943348e+00 4.1236793769586e-01
93 | -8.4868562931569e-01 -1.2964649357778e+00
94 | -1.3155622150808e+00 8.6183861270090e-01
95 | 1.3138748078062e+00 -8.6097342967242e-01
96 | 8.5645123682317e-01 1.3187213471944e+00
97 | -1.2856156290154e+00 -5.4959353200835e-01
98 | -5.7221815504058e-01 -1.3737191446926e+00
99 | 3.2535324995758e-01 -3.2579718679623e-01
100 | -5.0333367474960e-01 -3.6347339515017e-01
101 | 3.5797861410776e-01 3.9809165351547e-01
102 | -3.8551187476661e-01 4.6100603648072e-01
103 | -1.2711802581594e+00 -1.0000691071555e-01
104 | -1.4916219339835e-01 -8.4917526937607e-01
105 | 7.0879631622836e-01 2.7762577486890e-02
106 | -7.8143245887169e-01 -7.9306847636431e-02
107 | -4.0887835892638e-02 7.4492869380039e-01
108 | -1.4231631825255e-01 1.1229180905733e+00
109 | 1.0989475565219e+00 1.4299265622408e-01
110 | 1.7911024144192e-01 -1.0739023097382e+00
111 | 5.5805062860837e-01 -8.9904625041283e-01
112 | -1.3185353865589e+00 3.3677568740156e-01
113 | 3.1382099040920e-01 1.3053446361759e+00
114 | 1.2957405858663e+00 -3.1851095516215e-01
115 | -2.9908492148240e-01 -1.2934005027819e+00
116 | -8.1631360406680e-01 -9.9826725239983e-01
117 | -5.1889724786546e-01 8.8812006858756e-01
118 | 8.4619599658673e-01 5.3961034688476e-01
119 | 8.4338196070757e-01 1.0442559995589e+00
120 | 1.0326144117100e+00 -8.5791694348752e-01
121 | -1.0284433703759e+00 8.5200067771441e-01
122 | -9.8970112664877e-01 -4.9955230874907e-01
123 | -3.3891973340525e-01 -9.9777496794293e-01
124 | 9.9930883150201e-01 -3.7946356921232e-01
125 | -1.0193457951990e+00 3.6501881811241e-01
126 | 3.6866919802380e-01 1.0221791806509e+00
127 | 1.0291134608145e+00 9.0517367170623e-01
128 | -8.9096349218361e-01 1.0427249570090e+00
129 | 8.9979737544087e-01 -1.0454520936666e+00
130 | 5.8546741888905e-01 1.3826378805380e+00
131 | -1.3864478370074e+00 5.9137761127274e-01
132 | 1.3798656356145e+00 -5.8848540136276e-01
133 | 5.7825033622185e-01 -1.3299260225939e+00
134 | -5.6047260668609e-01 1.3324026960160e+00
135 | 1.3226379805174e+00 5.6639371481152e-01
136 | -1.9941015178329e-01 2.3440942141747e-01
137 | -2.2485031326665e-01 -2.4201001145397e-01
138 | 6.0565290259905e-01 4.1709145296514e-01
139 | 4.1152164831339e-01 -7.2492826661725e-01
140 | -1.0140125908169e+00 -8.6864324505095e-01
141 | 6.1348976261336e-01 9.1374865890708e-01
142 | -8.8388615809932e-01 6.1819099499553e-01
143 | 8.9281176927168e-01 -6.3615945011891e-01
144 | -6.1257291900199e-01 6.5324449758212e-01
145 | 5.5499889655039e-01 -2.0410217781047e-01
146 | 2.5629152941002e-01 1.6935564629834e-01
147 | 1.9708991541486e-01 6.0315945470044e-01
148 | -6.7414815032483e-01 9.9244963794996e-02
149 | 1.4276326616128e-02 -1.3181470524272e+00
150 | 9.4250124027350e-02 -2.8878255420785e-01
151 | 1.3290653153621e+00 -1.9403605963142e-03
152 | 1.9518445453304e-04 1.3372771081816e+00
153 | 1.0921949708857e-02 -7.1395371505472e-01
154 | -1.7120603621447e-01 -6.7631827441326e-01
155 | -6.9140580522655e-01 -2.5084042303208e-01
156 | -2.3491136641041e-01 6.6567057098775e-01
157 | -1.3768011979473e+00 6.5231759542199e-02
158 | -5.6977021936028e-01 -8.7100172948954e-01
159 | 6.9213166891737e-01 -1.0896693995242e+00
160 | -1.0205564702726e+00 -8.2673698725921e-02
161 | -7.3824314067636e-01 -4.5279849834181e-01
162 | 1.0696909325818e+00 6.8256929519853e-01
163 | -6.6773489038672e-01 1.0903717810997e+00
164 | 3.0019686255583e-01 -1.3279699207036e+00
165 | -3.0723897610392e-02 9.4392944898231e-01
166 | 9.1231396979261e-01 2.2644983851790e-02
167 | 2.6578794517677e-02 -9.0165310357735e-01
168 | 1.3322087165368e+00 2.8223160000091e-01
169 | -2.7954605609710e-01 1.3418343107573e+00
170 | -1.3614990341977e+00 -3.0071878062308e-01
171 | 8.3328083578243e-01 -1.7720703726077e-01
172 | -1.1354284111098e+00 -3.0045288091936e-01
173 | 1.6775172805174e-01 8.6482625978645e-01
174 | -8.9265099959202e-01 1.3088275963760e-01
175 | 3.6244612280932e-01 -9.1781783675219e-01
176 | 3.7914182416686e-02 2.6125913657675e-01
177 | 6.1427708027494e-01 1.9747953059724e-01
178 | -2.8009627044658e-01 2.4031932383405e-02
179 | 2.8691853512781e-01 -9.7503848307650e-02
180 | -5.4358940487803e-01 -6.1400087528032e-01
181 | -4.5567507759896e-01 1.8447846598670e-01
182 | -3.0609395665921e-01 -5.2704258734315e-01
183 | -1.0692413820390e+00 -7.0814087337837e-01
184 | 2.0718847093717e-01 -5.4929085970956e-01
185 | 6.2648362797879e-01 6.7034361443357e-01
186 | 6.4273164967885e-01 -6.7370737758345e-01
187 | 4.8001435514921e-01 -4.8412468057422e-01
188 | -3.9822069273538e-01 7.1505183038128e-01
189 | 4.6946030401648e-01 2.4376975056702e-01
190 | 4.4011049134214e-01 5.7169449713601e-01
191 | 1.5283194952654e-01 3.7657023237795e-01
192 |
--------------------------------------------------------------------------------
/Examples/HodgeDecomposition/driver.py:
--------------------------------------------------------------------------------
1 | """
2 | Compute a harmonic 1-cochain basis for a square with 4 holes.
3 |
4 | """
5 | from numpy import asarray, eye, outer, inner, dot, vstack
6 | from numpy.random import seed, rand
7 | from numpy.linalg import norm
8 | from scipy.sparse.linalg import cg
9 | from pydec import d, delta, simplicial_complex, read_mesh
10 |
11 | def hodge_decomposition(omega):
12 | """
13 | For a given p-cochain \omega there is a unique decomposition
14 |
15 | \omega = d(\alpha) + \delta(\beta) (+) h
16 |
17 | for p-1 cochain \alpha, p+1 cochain \beta, and harmonic p-cochain h.
18 |
19 | This function returns (non-unique) representatives \beta, \gamma, and h
20 | which satisfy the equation above.
21 |
22 | Example:
23 | #decompose a random 1-cochain
24 | sc = SimplicialComplex(...)
25 | omega = sc.get_cochain(1)
26 | omega.[:] = rand(*omega.shape)
27 | (alpha,beta,h) = hodge_decomposition(omega)
28 |
29 | """
30 | sc = omega.complex
31 | p = omega.k
32 | alpha = sc.get_cochain(p - 1)
33 | beta = sc.get_cochain(p + 1)
34 |
35 | # Solve for alpha
36 | A = delta(d(sc.get_cochain_basis(p - 1))).v
37 | b = delta(omega).v
38 | #alpha.v = cg( A, b, tol=1e-8 )[0]
39 | alpha.v = cg( A, b, rtol=1e-8 )[0]
40 | # TODO: check if rtol should be more or less stringent
41 |
42 | # Solve for beta
43 | A = d(delta(sc.get_cochain_basis(p + 1))).v
44 | b = d(omega).v
45 | #beta.v = cg( A, b, tol=1e-8 )[0]
46 | beta.v = cg( A, b, rtol=1e-8 )[0]
47 | # TODO: check if rtol should be more or less stringent
48 |
49 | # Solve for h
50 | h = omega - d(alpha) - delta(beta)
51 |
52 | return (alpha,beta,h)
53 |
54 |
55 | def ortho(A):
56 | """Separates the harmonic forms stored in the rows of A using a heuristic
57 | """
58 | A = asarray(A)
59 |
60 | for i in range(A.shape[0]):
61 | j = abs(A[i]).argmax()
62 |
63 | v = A[:,j].copy()
64 | if A[i,j] > 0:
65 | v[i] += norm(v)
66 | else:
67 | v[i] -= norm(v)
68 | Q = eye(A.shape[0]) - 2 * outer(v,v) / inner(v,v)
69 |
70 | A = dot(Q,A)
71 |
72 | return A
73 |
74 | seed(1) # make results consistent
75 |
76 | # Read in mesh data from file
77 | mesh = read_mesh('mesh_example.xml')
78 |
79 | vertices = mesh.vertices
80 | triangles = mesh.elements
81 |
82 | # remove some triangle from the mesh
83 | triangles = triangles[list(set(range(len(triangles))) - set([30,320,21,198])),:]
84 |
85 | sc = simplicial_complex((vertices,triangles))
86 |
87 | H = [] # harmonic forms
88 |
89 | # decompose 4 random 1-cochains
90 | for i in range(4):
91 | omega = sc.get_cochain(1)
92 | omega.v[:] = rand(*omega.v.shape)
93 |
94 | (beta,gamma,h) = hodge_decomposition(omega)
95 |
96 | h = h.v
97 | for v in H:
98 | h -= inner(v,h) * v
99 | h /= norm(h)
100 |
101 | H.append(h)
102 |
103 | H = ortho(vstack(H))
104 |
105 | # plot the results
106 | from pylab import figure, title, quiver, axis, show
107 | from pydec import triplot, simplex_quivers
108 |
109 | for n,h in enumerate(H):
110 | figure()
111 | title('Harmonic 1-cochain #%d' % n)
112 | triplot(vertices,triangles)
113 |
114 | bases,dirs = simplex_quivers(sc,h)
115 | quiver(bases[:,0],bases[:,1],dirs[:,0],dirs[:,1])
116 | axis('equal')
117 |
118 | show()
119 |
120 |
--------------------------------------------------------------------------------
/Examples/HodgeDecomposition/mesh_example.elements:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hirani/pydec/930bb8167978a7b980fc547c8d9237de3e690292/Examples/HodgeDecomposition/mesh_example.elements
--------------------------------------------------------------------------------
/Examples/HodgeDecomposition/mesh_example.vertices:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hirani/pydec/930bb8167978a7b980fc547c8d9237de3e690292/Examples/HodgeDecomposition/mesh_example.vertices
--------------------------------------------------------------------------------
/Examples/HodgeDecomposition/mesh_example.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Examples/MakeMesh/ExpectedOutput/square_8.elements:
--------------------------------------------------------------------------------
1 | 4
2 | dims=8,3
3 | format=basic
4 | version=1.0
5 | dtype=int32
6 | 0 2 1
7 | 0 3 2
8 | 1 2 4
9 | 2 3 5
10 | 2 5 4
11 | 3 6 5
12 | 4 5 7
13 | 5 6 7
14 |
--------------------------------------------------------------------------------
/Examples/MakeMesh/ExpectedOutput/square_8.vertices:
--------------------------------------------------------------------------------
1 | 4
2 | dims=8,2
3 | format=basic
4 | version=1.0
5 | dtype=float64
6 | -0.5 -0.5
7 | -0.5 0.5
8 | -0.03125 0.25
9 | 0 -0.5
10 | 0 0.5
11 | 0.03125 0.25
12 | 0.5 -0.5
13 | 0.5 0.5
14 |
--------------------------------------------------------------------------------
/Examples/MakeMesh/ExpectedOutput/square_8.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Examples/MakeMesh/make_mesh.py:
--------------------------------------------------------------------------------
1 | """
2 | Reads ascii vertex and element files, writes a pydec mesh and displays it
3 | """
4 |
5 | import numpy
6 | from pydec import SimplicialMesh, write_mesh, read_mesh
7 | from matplotlib.pylab import triplot, show
8 |
9 | vertices = numpy.loadtxt("v.txt")
10 | elements = numpy.loadtxt("s.txt",dtype='int32') - 1
11 | mymesh = SimplicialMesh(vertices=vertices,indices=elements)
12 | write_mesh("square_8.xml",mymesh,format='basic')
13 | rmesh = read_mesh("square_8.xml")
14 | triplot(rmesh.vertices[:,0], rmesh.vertices[:,1], rmesh.indices)
15 |
16 | show()
17 |
18 |
--------------------------------------------------------------------------------
/Examples/MakeMesh/s.txt:
--------------------------------------------------------------------------------
1 | 1 3 2
2 | 1 4 3
3 | 2 3 5
4 | 3 4 6
5 | 3 6 5
6 | 4 7 6
7 | 5 6 8
8 | 6 7 8
9 |
--------------------------------------------------------------------------------
/Examples/MakeMesh/square_8.elements:
--------------------------------------------------------------------------------
1 | 4
2 | dims=8,3
3 | dtype=int32
4 | format=basic
5 | version=1.0
6 | 0 2 1
7 | 0 3 2
8 | 1 2 4
9 | 2 3 5
10 | 2 5 4
11 | 3 6 5
12 | 4 5 7
13 | 5 6 7
14 |
--------------------------------------------------------------------------------
/Examples/MakeMesh/square_8.vertices:
--------------------------------------------------------------------------------
1 | 4
2 | dims=8,2
3 | dtype=float64
4 | format=basic
5 | version=1.0
6 | -0.5 -0.5
7 | -0.5 0.5
8 | -0.03125 0.25
9 | 0 -0.5
10 | 0 0.5
11 | 0.03125 0.25
12 | 0.5 -0.5
13 | 0.5 0.5
14 |
--------------------------------------------------------------------------------
/Examples/MakeMesh/square_8.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Examples/MakeMesh/v.txt:
--------------------------------------------------------------------------------
1 | -5.0000000000000000e-01 -5.0000000000000000e-01
2 | -5.0000000000000000e-01 5.0000000000000000e-01
3 | -3.1250000000000000e-02 2.5000000000000000e-01
4 | 0.0000000000000000e+00 -5.0000000000000000e-01
5 | 0.0000000000000000e+00 5.0000000000000000e-01
6 | 3.1250000000000000e-02 2.5000000000000000e-01
7 | 5.0000000000000000e-01 -5.0000000000000000e-01
8 | 5.0000000000000000e-01 5.0000000000000000e-01
9 |
--------------------------------------------------------------------------------
/Examples/Ranking/data.txt:
--------------------------------------------------------------------------------
1 | 8 1 -9
2 | 5 10 8
3 | 9 3 -23
4 | 6 9 13
5 | 2 9 23
6 | 8 7 3
7 | 1 10 9
8 | 6 5 11
9 | 2 8 14
10 | 0 1 3
11 | 3 4 -4
12 | 7 6 -1
13 | 1 4 1
14 | 4 2 20
15 | 10 2 -3
16 | 0 5 -9
17 | 7 10 4
18 | 9 0 -11
19 | 4 7 10
20 | 3 0 2
21 | 5 8 3
22 | 0 2 -23
23 | 5 4 14
24 | 7 1 -39
25 | 10 0 -2
26 | 8 3 10
27 | 4 6 -7
28 | 7 2 -27
29 | 1 5 1
30 | 3 10 17
31 | 9 8 -16
32 | 6 0 24
33 | 4 8 -14
34 | 5 7 16
35 | 1 6 18
36 | 10 4 -23
37 | 0 8 -15
38 | 6 2 -22
39 | 7 3 -13
40 | 9 5 -9
41 | 3 1 15
42 | 2 5 27
43 | 3 6 5
44 | 4 0 5
45 | 4 9 30
46 | 5 3 2
47 | 7 0 -24
48 | 1 2 15
49 | 10 6 -47
50 | 9 7 10
51 | 10 8 -6
52 | 2 3 17
53 | 9 10 -1
54 | 1 9 25
55 | 6 8 38
56 |
--------------------------------------------------------------------------------
/Examples/Ranking/driver.py:
--------------------------------------------------------------------------------
1 | """
2 | Least squares ranking on graphs.
3 |
4 | Reference :
5 |
6 | Least Squares Ranking on Graphs, Hodge Laplacians, Time Optimality,
7 | and Iterative Methods
8 | A. N. Hirani, K. Kalyanaraman, S. Watts
9 | See arXiv:1011.1716v1 [cs.NA] on http://arxiv.org/abs/1011.1716
10 |
11 | """
12 | from numpy import loadtxt
13 | from pydec import abstract_simplicial_complex
14 | from scipy.sparse.linalg import lsqr
15 |
16 | # Load graph and edge values
17 | data = loadtxt('data.txt').astype(int)
18 | edges = data[:,:2]
19 |
20 | # Create abstract simplicial complex from edges
21 | asc = abstract_simplicial_complex([edges])
22 |
23 | omega = data[:,-1] # pairwise comparisons
24 | B1 = asc.chain_complex()[1] # boundary matrix
25 | alpha = lsqr(B1.T, omega)[0] # solve least squares problem
26 |
27 | # Set the minimum to 0
28 | alpha = alpha - alpha.min()
29 |
30 | print(alpha)
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Examples/ResonantCavity/driver.py:
--------------------------------------------------------------------------------
1 | """
2 | Solve the resonant cavity problem with Whitney forms.
3 |
4 | References:
5 | Douglas N. Arnold and Richard S. Falk and Ragnar Winther
6 | "Finite element exterior calculus: from Hodge theory to numerical
7 | stability"
8 | Bull. Amer. Math. Soc. (N.S.), vol. 47, No. 2, pp. 281--354
9 | DOI : 10.1090/S0273-0979-10-01278-4
10 |
11 | """
12 | from pydec import simplicial_complex, d, delta, whitney_innerproduct, \
13 | simplex_quivers
14 | from numpy import loadtxt, real, zeros
15 | from scipy.linalg import eig
16 | from matplotlib.pylab import quiver, figure, triplot, show
17 |
18 | # Read in mesh data from files and construct complex
19 | vertices = loadtxt('vertices.txt', dtype=float)
20 | triangles = loadtxt('triangles.txt', dtype=int)
21 | sc = simplicial_complex((vertices,triangles))
22 |
23 | # Construct stiffness and mass matrices
24 | K = sc[1].d.T * whitney_innerproduct(sc,2) * sc[1].d
25 | M = whitney_innerproduct(sc,1)
26 |
27 | # Eliminate Boundaries from matrices
28 | boundary_edges = sc.boundary()
29 | non_boundary_edges = set(sc[1].simplex_to_index.keys()) - set(boundary_edges)
30 | non_boundary_indices = [sc[1].simplex_to_index[e] for e in non_boundary_edges]
31 |
32 | # Eliminate boundary conditions
33 | K = K[non_boundary_indices,:][:,non_boundary_indices]
34 | M = M[non_boundary_indices,:][:,non_boundary_indices]
35 |
36 | # Compute eigenvalues and eigenvectors
37 | # (could use sparse eigenvalue solver instead)
38 | eigenvalues, eigenvectors = eig(K.todense(), M.todense())
39 |
40 | # Plot eigenvalues
41 | NUM_EIGS = 50 # Number of eigenvalues to plot
42 | values = sorted([x for x in real(eigenvalues) if x > 1e-10])[0:NUM_EIGS]
43 | ax = figure().gca()
44 | ax.set_title('First ' + str(len(values)) + ' Eigenvalues\n\n')
45 | # ax.hold(True)
46 | ax.plot(values,'ko')
47 |
48 | # Plot the eigenvector 1-cochain as a vector field
49 | N = 2 # Which non-zero eigenvector to plot?
50 | non_zero_values = real(eigenvectors[:,list(eigenvalues).index(values[N])])
51 | all_values = zeros((sc[1].num_simplices,))
52 | all_values[non_boundary_indices] = non_zero_values
53 | bases, arrows = simplex_quivers(sc,all_values)
54 | ax = figure().gca()
55 | ax.set_title('Mode #' + str(N+1))
56 | ax.quiver(bases[:,0],bases[:,1],arrows[:,0],arrows[:,1])
57 | ax.triplot(sc.vertices[:,0], sc.vertices[:,1], sc.simplices)
58 | ax.axis('equal')
59 |
60 | show()
61 |
62 |
--------------------------------------------------------------------------------
/Examples/ResonantCavity/triangles.txt:
--------------------------------------------------------------------------------
1 | 13 1 60
2 | 57 5 92
3 | 92 6 97
4 | 114 8 148
5 | 55 12 71
6 | 43 0 61
7 | 4 5 57
8 | 6 7 97
9 | 56 45 139
10 | 23 2 59
11 | 33 3 58
12 | 97 7 114
13 | 60 14 74
14 | 113 18 150
15 | 54 22 72
16 | 14 15 74
17 | 12 13 71
18 | 1 14 60
19 | 94 16 131
20 | 0 4 61
21 | 16 17 131
22 | 55 48 128
23 | 17 18 113
24 | 22 23 72
25 | 18 19 150
26 | 59 24 75
27 | 112 28 151
28 | 53 32 73
29 | 2 24 59
30 | 24 25 75
31 | 135 44 175
32 | 95 26 129
33 | 26 27 129
34 | 32 33 73
35 | 3 34 58
36 | 58 34 76
37 | 27 28 112
38 | 28 29 151
39 | 5 6 92
40 | 8 9 148
41 | 34 35 76
42 | 93 36 130
43 | 36 37 130
44 | 111 38 156
45 | 56 42 70
46 | 37 38 111
47 | 53 46 127
48 | 38 39 156
49 | 54 47 126
50 | 146 77 190
51 | 145 44 178
52 | 123 49 142
53 | 41 42 56
54 | 11 12 55
55 | 21 22 54
56 | 157 52 179
57 | 31 32 53
58 | 125 50 140
59 | 132 55 158
60 | 101 51 180
61 | 58 46 73
62 | 102 39 169
63 | 59 47 72
64 | 151 29 168
65 | 60 48 71
66 | 150 19 167
67 | 42 43 70
68 | 148 9 163
69 | 57 45 70
70 | 103 52 122
71 | 76 35 93
72 | 35 36 93
73 | 75 25 95
74 | 25 26 95
75 | 74 15 94
76 | 15 16 94
77 | 45 56 70
78 | 4 57 61
79 | 40 41 96
80 | 41 56 96
81 | 179 52 181
82 | 9 10 163
83 | 133 53 162
84 | 29 30 168
85 | 134 54 161
86 | 19 20 167
87 | 30 31 133
88 | 121 62 171
89 | 20 21 134
90 | 184 50 189
91 | 10 11 132
92 | 185 49 186
93 | 96 56 182
94 | 119 85 128
95 | 61 57 70
96 | 43 61 70
97 | 48 55 71
98 | 13 60 71
99 | 47 54 72
100 | 23 59 72
101 | 46 53 73
102 | 33 58 73
103 | 48 60 74
104 | 119 68 142
105 | 47 59 75
106 | 118 67 140
107 | 46 58 76
108 | 124 51 141
109 | 120 66 141
110 | 120 87 127
111 | 118 86 126
112 | 104 65 176
113 | 139 84 182
114 | 90 64 107
115 | 103 63 152
116 | 103 80 153
117 | 146 50 172
118 | 106 64 155
119 | 105 79 147
120 | 105 62 154
121 | 144 49 170
122 | 91 65 108
123 | 136 44 177
124 | 45 57 92
125 | 152 63 183
126 | 113 68 131
127 | 145 78 188
128 | 112 67 129
129 | 147 79 180
130 | 111 66 130
131 | 122 52 157
132 | 109 63 166
133 | 128 85 158
134 | 110 63 174
135 | 107 64 164
136 | 141 51 143
137 | 108 65 165
138 | 126 86 161
139 | 7 8 114
140 | 92 69 115
141 | 46 76 93
142 | 93 66 120
143 | 48 74 94
144 | 94 68 119
145 | 47 75 95
146 | 95 67 118
147 | 154 62 160
148 | 115 84 139
149 | 114 88 122
150 | 69 92 97
151 | 104 78 144
152 | 136 80 149
153 | 153 80 181
154 | 121 84 160
155 | 106 77 146
156 | 144 78 178
157 | 145 100 190
158 | 127 87 162
159 | 147 51 173
160 | 39 40 169
161 | 149 80 183
162 | 88 103 122
163 | 137 100 188
164 | 142 49 185
165 | 155 64 187
166 | 99 79 154
167 | 140 50 184
168 | 101 77 155
169 | 133 90 168
170 | 125 81 172
171 | 134 91 167
172 | 104 83 165
173 | 103 88 166
174 | 132 89 163
175 | 109 89 174
176 | 110 85 185
177 | 111 82 124
178 | 102 82 156
179 | 112 81 125
180 | 107 81 151
181 | 113 83 123
182 | 108 83 150
183 | 109 88 148
184 | 69 97 114
185 | 115 69 157
186 | 45 92 115
187 | 64 90 116
188 | 116 87 143
189 | 65 91 117
190 | 117 86 184
191 | 86 118 140
192 | 47 95 118
193 | 85 119 142
194 | 48 94 119
195 | 51 101 143
196 | 46 93 120
197 | 40 96 169
198 | 169 96 171
199 | 69 114 122
200 | 160 84 179
201 | 123 83 170
202 | 68 113 123
203 | 124 82 173
204 | 66 111 124
205 | 164 106 172
206 | 67 112 125
207 | 117 91 161
208 | 47 118 126
209 | 116 90 162
210 | 46 120 127
211 | 110 89 158
212 | 48 119 128
213 | 67 95 129
214 | 27 112 129
215 | 66 93 130
216 | 37 111 130
217 | 68 94 131
218 | 17 113 131
219 | 11 55 132
220 | 85 110 158
221 | 31 53 133
222 | 87 116 162
223 | 21 54 134
224 | 86 117 161
225 | 159 105 173
226 | 77 101 135
227 | 79 99 136
228 | 135 79 177
229 | 146 100 189
230 | 65 117 137
231 | 144 98 186
232 | 63 110 138
233 | 45 115 139
234 | 121 96 182
235 | 67 125 140
236 | 137 117 184
237 | 87 120 141
238 | 66 124 141
239 | 68 123 142
240 | 138 110 185
241 | 143 101 187
242 | 87 141 143
243 | 149 98 178
244 | 83 104 170
245 | 183 138 186
246 | 176 137 188
247 | 175 145 190
248 | 50 125 172
249 | 51 124 173
250 | 135 101 180
251 | 89 109 163
252 | 88 114 148
253 | 44 136 149
254 | 98 144 178
255 | 91 108 167
256 | 83 113 150
257 | 90 107 168
258 | 81 112 151
259 | 80 103 152
260 | 63 138 183
261 | 52 103 153
262 | 136 99 181
263 | 80 136 181
264 | 79 105 154
265 | 64 116 187
266 | 77 106 155
267 | 39 102 156
268 | 82 111 156
269 | 84 115 157
270 | 69 122 157
271 | 55 128 158
272 | 89 132 158
273 | 82 102 159
274 | 62 105 159
275 | 62 121 160
276 | 99 154 160
277 | 54 126 161
278 | 91 134 161
279 | 53 127 162
280 | 90 133 162
281 | 10 132 163
282 | 109 148 163
283 | 64 106 164
284 | 81 107 164
285 | 65 104 165
286 | 83 108 165
287 | 63 103 166
288 | 88 109 166
289 | 20 134 167
290 | 108 150 167
291 | 30 133 168
292 | 107 151 168
293 | 159 102 171
294 | 96 121 171
295 | 49 123 170
296 | 104 144 170
297 | 62 159 171
298 | 102 169 171
299 | 106 146 172
300 | 81 164 172
301 | 105 147 173
302 | 82 159 173
303 | 63 109 174
304 | 89 110 174
305 | 77 135 175
306 | 44 145 175
307 | 78 104 176
308 | 65 137 176
309 | 44 135 177
310 | 79 136 177
311 | 78 145 178
312 | 44 149 178
313 | 84 157 179
314 | 99 160 179
315 | 79 135 180
316 | 51 147 180
317 | 52 153 181
318 | 99 179 181
319 | 84 121 182
320 | 56 139 182
321 | 98 149 183
322 | 80 152 183
323 | 100 137 189
324 | 86 140 184
325 | 49 144 186
326 | 85 142 185
327 | 98 183 186
328 | 138 185 186
329 | 116 143 187
330 | 101 155 187
331 | 100 145 188
332 | 78 176 188
333 | 50 146 189
334 | 137 184 189
335 | 100 146 190
336 | 77 175 190
337 |
--------------------------------------------------------------------------------
/Examples/ResonantCavity/vertices.txt:
--------------------------------------------------------------------------------
1 | -1.570796326794896558e+00 -1.570796326794896558e+00
2 | 1.570796326794896558e+00 -1.570796326794896558e+00
3 | 1.570796326794896558e+00 1.570796326794896558e+00
4 | -1.570796326794896558e+00 1.570796326794896558e+00
5 | -1.285196994650369851e+00 -1.570796326794896558e+00
6 | -9.995976625058432541e-01 -1.570796326794896558e+00
7 | -7.139983303613166576e-01 -1.570796326794896558e+00
8 | -4.283989982167899502e-01 -1.570796326794896558e+00
9 | -1.427996660722634648e-01 -1.570796326794896558e+00
10 | 1.427996660722632427e-01 -1.570796326794896558e+00
11 | 4.283989982167899502e-01 -1.570796326794896558e+00
12 | 7.139983303613166576e-01 -1.570796326794896558e+00
13 | 9.995976625058435872e-01 -1.570796326794896558e+00
14 | 1.285196994650369628e+00 -1.570796326794896558e+00
15 | 1.570796326794896558e+00 -1.285196994650369851e+00
16 | 1.570796326794896558e+00 -9.995976625058432541e-01
17 | 1.570796326794896558e+00 -7.139983303613166576e-01
18 | 1.570796326794896558e+00 -4.283989982167899502e-01
19 | 1.570796326794896558e+00 -1.427996660722634648e-01
20 | 1.570796326794896558e+00 1.427996660722632427e-01
21 | 1.570796326794896558e+00 4.283989982167899502e-01
22 | 1.570796326794896558e+00 7.139983303613166576e-01
23 | 1.570796326794896558e+00 9.995976625058435872e-01
24 | 1.570796326794896558e+00 1.285196994650369628e+00
25 | 1.285196994650369851e+00 1.570796326794896558e+00
26 | 9.995976625058432541e-01 1.570796326794896558e+00
27 | 7.139983303613166576e-01 1.570796326794896558e+00
28 | 4.283989982167899502e-01 1.570796326794896558e+00
29 | 1.427996660722634648e-01 1.570796326794896558e+00
30 | -1.427996660722632427e-01 1.570796326794896558e+00
31 | -4.283989982167899502e-01 1.570796326794896558e+00
32 | -7.139983303613166576e-01 1.570796326794896558e+00
33 | -9.995976625058435872e-01 1.570796326794896558e+00
34 | -1.285196994650369628e+00 1.570796326794896558e+00
35 | -1.570796326794896558e+00 1.285196994650369851e+00
36 | -1.570796326794896558e+00 9.995976625058432541e-01
37 | -1.570796326794896558e+00 7.139983303613166576e-01
38 | -1.570796326794896558e+00 4.283989982167899502e-01
39 | -1.570796326794896558e+00 1.427996660722634648e-01
40 | -1.570796326794896558e+00 -1.427996660722632427e-01
41 | -1.570796326794896558e+00 -4.283989982167899502e-01
42 | -1.570796326794896558e+00 -7.139983303613166576e-01
43 | -1.570796326794896558e+00 -9.995976625058435872e-01
44 | -1.570796326794896558e+00 -1.285196994650369628e+00
45 | -8.118308301341890755e-04 -6.946406800360100699e-03
46 | -1.079464795312983894e+00 -1.095331959600446936e+00
47 | -1.143748872826308327e+00 1.133254571778189668e+00
48 | 1.127614593932668496e+00 1.148381122526771492e+00
49 | 1.144285033912920024e+00 -1.130915891023488884e+00
50 | 7.357865231893168101e-01 -4.289864633395406024e-01
51 | 4.041089675494913824e-01 7.769433312058171559e-01
52 | -7.142047671915092710e-01 3.787341092915585961e-01
53 | -3.399026174739918083e-01 -7.424764569616427723e-01
54 | -8.762809630236517711e-01 1.306998250935197836e+00
55 | 1.300106105379469579e+00 8.804999000266701126e-01
56 | 8.779301438435366256e-01 -1.304931102019043498e+00
57 | -1.280891357699912358e+00 -8.726140820585561730e-01
58 | -1.156707483041327755e+00 -1.349024496214798141e+00
59 | -1.348909553989847021e+00 1.344912154558517869e+00
60 | 1.343240203435927205e+00 1.350192932444230998e+00
61 | 1.349152250826217925e+00 -1.343968008281884785e+00
62 | -1.385165849888463363e+00 -1.388462326958713744e+00
63 | -8.949936541793692690e-01 -2.693956984583510406e-01
64 | 2.182046839117837145e-01 -8.309172954475544381e-01
65 | -2.590700813975242989e-01 8.916946180842272307e-01
66 | 8.651504643045050402e-01 2.630803266597084855e-01
67 | -1.162715319641933087e+00 6.049718915956517895e-01
68 | 5.977979147142942207e-01 1.168569278122220778e+00
69 | 1.152287647627852296e+00 -6.035768929150923112e-01
70 | -5.746639954175203346e-01 -1.138627169569143449e+00
71 | -1.341171936232554485e+00 -1.165476525506575545e+00
72 | 1.131483515490267822e+00 -1.384089847281359198e+00
73 | 1.382649951335525706e+00 1.132793994849376151e+00
74 | -1.130908793000449553e+00 1.385368717228757873e+00
75 | 1.391459068517064690e+00 -1.123254887438755123e+00
76 | 1.122264488081204936e+00 1.393320365029125707e+00
77 | -1.391555148461683489e+00 1.124507269349577232e+00
78 | -7.867642154878339011e-02 4.760328062416400718e-01
79 | 5.063447973622641207e-01 5.469011918833763947e-02
80 | -4.764695915969595630e-01 -4.425882889383756652e-02
81 | -5.475151191886327984e-02 -5.374352004131099925e-01
82 | 1.111192734186332021e-01 1.105197718117541861e+00
83 | -1.151754533673709391e+00 1.212529602180132532e-01
84 | 1.037947314758432160e+00 -9.140303202481689371e-02
85 | -8.305666036877497049e-01 -7.154601364648558448e-01
86 | 7.750410662792711625e-01 -8.638174500501123454e-01
87 | 8.457913823498808270e-01 7.947256541522200735e-01
88 | -7.744381381382123841e-01 8.664302886858505914e-01
89 | -7.173521807634170022e-02 -1.078186171326531495e+00
90 | 4.293938204417704352e-01 -1.123355563999682172e+00
91 | -4.104280589158635917e-01 1.117253337337019925e+00
92 | 1.095445815160047909e+00 4.195021452219105940e-01
93 | -8.465807574902163291e-01 -1.300719077349441255e+00
94 | -1.323173608167877324e+00 8.601366910999208582e-01
95 | 1.321094960146869113e+00 -8.581302970925125395e-01
96 | 8.557970588816530277e-01 1.326548709524030922e+00
97 | -1.289589345049155567e+00 -5.469077705791017818e-01
98 | -5.731587577825721924e-01 -1.375447114608264965e+00
99 | 3.386366698904786365e-01 -3.247349753462075439e-01
100 | -4.963518133193140502e-01 -3.512834159223075514e-01
101 | 3.582006697596371581e-01 4.005403106751903586e-01
102 | -4.005321025198656515e-01 4.782892403398507075e-01
103 | -1.272932605434254238e+00 -1.067781918096204069e-01
104 | -7.777737058860240138e-02 -8.091607210002192963e-01
105 | 7.740386515092932962e-01 1.251165494393278489e-02
106 | -7.741043207917920332e-01 -5.754480039758358423e-02
107 | -4.112742414631703064e-02 7.454390876737546634e-01
108 | -1.471466165756354083e-01 1.126797522744982905e+00
109 | 1.102054948155894332e+00 1.633117987057628173e-01
110 | 1.856425026528311373e-01 -1.091686434298984043e+00
111 | 5.005326936266334403e-01 -8.920263197014767220e-01
112 | -1.320753821087682800e+00 3.316370558007615266e-01
113 | 3.181933618232986594e-01 1.310504916503889561e+00
114 | 1.290330486715353109e+00 -3.169309223358688365e-01
115 | -2.996719215334580633e-01 -1.293326595148597713e+00
116 | -8.229667354267152790e-01 -1.000329917638195676e+00
117 | -5.257007857730678912e-01 8.952745244270579050e-01
118 | 8.564714893654569172e-01 5.416935938897989855e-01
119 | 8.474480084595580331e-01 1.043993363310063316e+00
120 | 1.032085059709853203e+00 -8.555345610406391854e-01
121 | -1.032507087477268604e+00 8.574296151987419456e-01
122 | -9.996153983970895718e-01 -4.979738094093106859e-01
123 | -3.238897950099914325e-01 -9.891504276236792181e-01
124 | 9.905560240340900435e-01 -3.809340450867254035e-01
125 | -1.021957220710640657e+00 3.680380755391006176e-01
126 | 3.686454498770332933e-01 1.025033325919344485e+00
127 | 1.040600278467370687e+00 9.110508890512022395e-01
128 | -9.012111815120485980e-01 1.052969274543630096e+00
129 | 9.026083742791806142e-01 -1.049628441761922826e+00
130 | 5.825910940447160957e-01 1.389622491030319207e+00
131 | -1.389639363149263174e+00 5.877031100165404087e-01
132 | 1.381759525121651899e+00 -5.837037669695999131e-01
133 | 5.714884261033180701e-01 -1.333949772499766206e+00
134 | -5.653492641872377433e-01 1.335550502279319929e+00
135 | 1.325720070736770895e+00 5.700002661992716879e-01
136 | -2.391481735203405123e-01 1.952861799889144545e-01
137 | -2.103844881262482425e-01 -2.539648046309649354e-01
138 | 6.129851827728696190e-01 4.141666034461549684e-01
139 | 4.170202228338600325e-01 -6.812198246005148894e-01
140 | -1.021654729472128764e+00 -8.785434433926505582e-01
141 | 6.158237183350249166e-01 9.135910390225854272e-01
142 | -8.878347415880960547e-01 6.241394948021178335e-01
143 | 8.892151823379701447e-01 -6.315335222431240902e-01
144 | -6.192744263507394820e-01 6.629755445239696732e-01
145 | 5.688086109850934990e-01 -2.108602297255143532e-01
146 | 2.592474248068475928e-01 1.757590014092840214e-01
147 | 2.004605551698408761e-01 6.048391687100110881e-01
148 | -6.725248929220655203e-01 1.317406341385681245e-01
149 | 1.887171919033387921e-02 -1.324443422624759670e+00
150 | 1.004182174517405796e-01 -2.942334434708706037e-01
151 | 1.318846274909837302e+00 7.853235795651544726e-03
152 | -7.618182087533545985e-04 1.339165984675086962e+00
153 | 7.954082399164523476e-02 -6.813216188826870523e-01
154 | -1.959018464440268059e-01 -6.536318669812564153e-01
155 | -6.786628998492165721e-01 -2.333174008152207324e-01
156 | -2.383972903482288186e-01 6.655294065888675004e-01
157 | -1.377511458731576877e+00 6.898280872116133167e-02
158 | -5.754095779438416214e-01 -8.666920666692533581e-01
159 | 6.776233929013263380e-01 -1.094831463901755564e+00
160 | -1.022435846417170113e+00 -7.835578783073143816e-02
161 | -7.437421190356069411e-01 -4.462629950531853962e-01
162 | 1.078719464169996201e+00 6.866214782943838024e-01
163 | -6.763766542265797765e-01 1.097196394253467044e+00
164 | 2.968248391006591547e-01 -1.336604252910319479e+00
165 | -3.466617800858074611e-02 9.501744032654959593e-01
166 | 9.477201880627261765e-01 8.759786802255559168e-02
167 | 6.450909818861770562e-02 -9.537813157904500017e-01
168 | 1.332051412109630073e+00 2.890755370379113898e-01
169 | -2.831388362355011235e-01 1.344585892540345773e+00
170 | -1.369860871055989637e+00 -3.057590242851561668e-01
171 | 8.241143581341067170e-01 -2.190461348709431544e-01
172 | -1.142619713152329686e+00 -3.015160067305550085e-01
173 | 1.674894010286318569e-01 8.696606880391198890e-01
174 | -8.933337837408118487e-01 1.446337995733145421e-01
175 | 3.352288506456694295e-01 -9.856082238489359826e-01
176 | 1.851168345165559587e-02 2.459132102286308297e-01
177 | 6.495645313329179160e-01 1.990576613322769806e-01
178 | -2.321909466726455040e-01 -2.590072635196215972e-02
179 | 2.967312672754408021e-01 -1.003026312376032458e-01
180 | -5.509344531927041766e-01 -6.081640256126219501e-01
181 | -5.011404788959320511e-01 2.299896569386187528e-01
182 | -3.090728008939458982e-01 -5.243872676944120181e-01
183 | -1.086090033624601547e+00 -7.033651963489994108e-01
184 | 2.285396798128788431e-01 -5.462696334745843485e-01
185 | 6.303740711075592751e-01 6.695691493345162781e-01
186 | 6.369574154476645989e-01 -6.616592398285131571e-01
187 | 4.899358334054156328e-01 -4.750861959879610352e-01
188 | -4.093390038330306235e-01 7.216665354929093779e-01
189 | 4.786893678929649565e-01 2.491681422396633816e-01
190 | 4.418192101172460085e-01 5.738052115311009782e-01
191 | 1.517312689973358275e-01 3.818449573710228639e-01
192 |
--------------------------------------------------------------------------------
/Examples/RipsComplex/300pts.mtx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hirani/pydec/930bb8167978a7b980fc547c8d9237de3e690292/Examples/RipsComplex/300pts.mtx
--------------------------------------------------------------------------------
/Examples/RipsComplex/driver.py:
--------------------------------------------------------------------------------
1 | """
2 | Detection of holes in coverage in an idealized abstraction of a sensor
3 | network. Hodge decomposition of a random cochain is used to compute a
4 | harmonic cochain.
5 |
6 | """
7 | #from scipy import rand
8 | from numpy.random import rand
9 | from scipy.linalg import norm
10 | from scipy.sparse.linalg import cg
11 |
12 | from pydec import kd_tree, flatten, triplot, read_array
13 | from pydec.dec.rips_complex import rips_complex
14 |
15 |
16 | pts = read_array('300pts.mtx') # 300 random points in 2D
17 | rc = rips_complex( pts, 0.15 )
18 |
19 | simplices = rc.simplices
20 |
21 | cmplx = rc.chain_complex() # boundary operators [ b0, b1, b2 ]
22 | b1 = cmplx[1].astype(float) # edge boundary operator
23 | b2 = cmplx[2].astype(float) # face boundary operator
24 |
25 | x = rand(b1.shape[1]) # random 1-chain
26 | # Decompose x using discrete Hodge decomposition
27 | alpha = cg( b1 * b1.T, b1 * x, rtol=1e-8)[0] # TODO: Was tol before June 2024. Is this change OK
28 | beta = cg( b2.T * b2, b2.T * x, rtol=1e-8)[0]
29 | h = x - (b1.T * alpha) - (b2 * beta) # harmonic component of x
30 | h /= abs(h).max() # normalize h
31 |
32 |
33 | #print 'norm( h )',norm(h)
34 | #print 'norm(b1 * h)', norm(b1 * h) #should be small
35 | #print 'norm(b2.T * h)', norm(b2.T * h) #should be small
36 |
37 |
38 | # plot the results
39 | from pylab import figure, title, plot, axis, xlim, ylim, show
40 | from pydec import triplot, lineplot
41 |
42 | # Nodes of the Rips complex
43 | figure()
44 | plot(pts[:,0],pts[:,1],'ko')
45 | axis('off')
46 | title('Nodes of the Complex')
47 |
48 | # Rips complex (2d triangle mesh)
49 | figure()
50 | title('The Rips Complex')
51 | triplot(pts,simplices[2])
52 |
53 | # Harmonic 1-chain
54 | figure()
55 | title('Harmonic 1-chain of the Rips complex')
56 | lineplot(pts,simplices[1],linewidths=(15*abs(h)).clip(1,15) )
57 |
58 | # fiddle with the figures
59 | for i in range(1,4):
60 | figure(i)
61 | axis('off')
62 | axis('equal')
63 | xlim(-0.1,1.1)
64 | ylim(-0.1,1.1)
65 |
66 | show()
67 |
68 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008, PyDEC Developers
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are
6 | met:
7 |
8 | * Redistributions of source code must retain the above copyright
9 | notice, this list of conditions and the following disclaimer.
10 |
11 | * Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 |
16 | * Neither the name of the PyDEC Developers nor the names of any
17 | contributors may be used to endorse or promote products derived
18 | from this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## **PyDEC: A Python Library for Discretizations of Exterior Calculus.**
2 |
3 | PyDEC is a Python library implementing Discrete Exterior Calculus (DEC) and lowest order finite element exterior calculus (FEEC) i.e., Whitney forms. The main functionality implemented:
4 | - simplicial complexes of dimension n embeded in dimension N >= n
5 | - abstract simplicial complexes (no embedding needed)
6 | - cubical complexes in all dimensions
7 | - boundary operators for all the above type of complexes
8 | - discrete exterior derivative (i.e., coboundary operator)
9 | - DEC discrete Hodge star (i.e., primal-dual diagonal mass matrix)
10 | - FEEC mass matrix for Whitney forms
11 |
12 | The code and companion paper include examples for numerically solving PDEs and computing cohomology: ACM Transactions on Mathematical Software, Vol. 39, No. 1, pp. 3:1-3:41, 2012, [DOI: 10.1145/2382585.2382588](http://dx.doi.org/10.1145/2382585.2382588).
13 |
14 | Installation:
15 | - `cd` to the folder where you cloned PyDEC
16 | - `pip install .`
17 |
18 | Note about installation:
19 | - There is another package called `pydec` which has nothing to do with this package. If you simply do `pip install pydec` then you will get that other package. PyDEC has existed since about 2008, but we were too slow in grabbing `pydec` name on pip :-(
20 | - So for now, please install by first cloning or downloading the source and then using the installation instructions above.
21 |
22 |
--------------------------------------------------------------------------------
/pydec/pydec/__init__.py:
--------------------------------------------------------------------------------
1 | """PyDEC: Software and Algorithms for Discrete Exterior Calculus
2 | """
3 |
4 | from .version import version as __version__
5 |
6 | from .dec import *
7 | from .fem import *
8 | from .math import *
9 | from .io import *
10 | from .mesh import *
11 | from .util import *
12 | from .vis import *
13 |
14 | __all__ = list(filter(lambda s:not s.startswith('_'),dir()))
15 | #__all__ += ['test', '__version__']
16 | __all__ += ['__version__']
17 |
18 | # TODO: replace testing framework with pytest (?) since Tester of nose/numpy is deprecated
19 | #from pydec.testing import Tester
20 | #test = Tester().test
21 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/__init__.py:
--------------------------------------------------------------------------------
1 | "DEC data structures and algorithms"
2 |
3 | from .info import __doc__
4 |
5 | from .rips_complex import *
6 | from .cochain import *
7 | from .simplicial_complex import *
8 | from .regular_cube_complex import *
9 | from .abstract_simplicial_complex import *
10 |
11 | __all__ = list(filter(lambda s:not s.startswith('_'), dir()))
12 |
13 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/abstract_simplicial_complex.py:
--------------------------------------------------------------------------------
1 | from numpy import zeros, ones, arange, array, asarray, hstack, vstack, empty, lexsort, atleast_2d
2 | from numpy import all as alltrue #temporary fix. Change above to np.*
3 | from scipy import sparse
4 |
5 | from .simplex_array import simplex_array_parity, simplex_array_boundary, simplex_array_searchsorted
6 |
7 | __all__ = ['abstract_simplicial_complex']
8 |
9 | class abstract_simplicial_complex:
10 | def __init__(self, simplices):
11 | """Construct an abstract simplicial complex
12 |
13 | Parameters
14 | ----------
15 | simplices : list of arrays
16 | Maximal simplices of each dimension
17 | TODO
18 |
19 | Examples
20 | --------
21 | >>> from pydec.dec import abstract_simplicial_complex
22 | >>> from numpy import array
23 | >>> simplices = [array([[4]]), array([[0,3]])]
24 | >>> asc = abstract_simplicial_complex(simplices)
25 |
26 | TODO
27 |
28 | >>> print rc.simplices[0]
29 | >>> print rc.simplices[1]
30 |
31 | Notes
32 | -----
33 |
34 | TODO explain input handling
35 |
36 | """
37 |
38 | # convert array-like objects to arrays
39 | simplices = [atleast_2d(s) for s in simplices]
40 |
41 | # find top simplex dimension
42 | D = max([s.shape[1] for s in simplices]) - 1
43 |
44 | # convert simplices list to canonical simplex_array list representation
45 | old_simplices = simplices
46 | simplices = [None] * (D + 1)
47 | for s in old_simplices:
48 | simplices[s.shape[1] - 1] = s
49 |
50 |
51 | # top most simplex array
52 | s = simplices[-1].copy()
53 |
54 | parity = simplex_array_parity(s)
55 | s.sort()
56 |
57 | chain_complex = [None] * (D + 1)
58 |
59 | for d in range(D - 1, -1, -1):
60 | s,B = simplex_array_boundary(s,parity)
61 |
62 | if simplices[d] is not None:
63 | old_s = s
64 |
65 | # sort columns to ensure user-defined faces are in canonical format
66 | simplices[d].sort()
67 |
68 | # merge user-defined faces with boundary faces
69 | s = vstack((s,simplices[d]))
70 |
71 | # sort rows to bring equivalent elements together
72 | s = s[lexsort(s.T[::-1])]
73 |
74 | # find unique simplices
75 | mask = ~hstack((array([False]),alltrue(s[1:] == s[:-1],axis=1)))
76 | s = s[mask]
77 |
78 | # indices of the boundary faces in the full face array
79 | remap = simplex_array_searchsorted(s, old_s)
80 |
81 | # remap indices of boundary operator
82 | B = B.tocoo(copy=False)
83 | B = sparse.coo_matrix((B.data, (remap[B.row], B.col)), (s.shape[0], B.shape[1]))
84 | B = B.tocsr()
85 |
86 | # faces are already in canonical format, so parity is even
87 | parity = zeros(s.shape[0],dtype=s.dtype)
88 |
89 | simplices[d] = s
90 | chain_complex[d+1] = B
91 |
92 | # compute 0-simplices and boundary operator
93 | simplices[0] = arange(simplices[0].max() + 1).reshape(-1,1)
94 | chain_complex[0] = sparse.csr_matrix( (1,len(s)), dtype='uint8')
95 |
96 | # store the cochain complex
97 | Bn = chain_complex[-1]
98 | cochain_complex = [ B.T for B in chain_complex[1:] ]
99 | cochain_complex += [ sparse.csc_matrix( (1, Bn.shape[1]), dtype=Bn.dtype) ]
100 |
101 | # store the data members
102 | self.simplices = simplices
103 | self._chain_complex = chain_complex
104 | self._cochain_complex = cochain_complex
105 |
106 | def complex_dimension(self):
107 | return len(self.cochain_complex()) - 1
108 |
109 | def complex(self):
110 | return self.simplices
111 |
112 | def chain_complex(self):
113 | return self._chain_complex
114 |
115 | def cochain_complex(self):
116 | return self._cochain_complex
117 |
118 |
119 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/cochain.py:
--------------------------------------------------------------------------------
1 | __all__ = ['cochain','Cochain','d','star','delta','laplace_beltrami','laplace_derham']
2 |
3 | from scipy import sparse
4 | from pydec.mesh import Simplex
5 |
6 | class cochain:
7 | """
8 | Represents a cochain associated with a simplical complex
9 |
10 | The v member of the cochain is left uninitialized. This allows functions like
11 | d(.) and star(.) to operate on single cochains, or groups of cochains together.
12 | The values associated with each cochain are stored in the columns of v. This is
13 | especially useful when v is the identity, and thus represents a basis for all cochains.
14 | Applying operations to this cochain basis allows one to automatically compose the
15 | associated matrix operators.
16 |
17 | Use the get_cochain() and get_cochain_basis() members of the SimplicialComplex class to
18 | safely avoid issues with v.
19 | """
20 |
21 | def __init__(self,complex,dimension,is_primal):
22 | self.complex = complex
23 | self.k = dimension
24 | self.n = complex.complex_dimension()
25 | self.is_primal = is_primal
26 | self.v = None
27 | def __add__(self,other):
28 | assert(self.k == other.k and self.complex == other.complex)
29 | f = cochain(self.complex,self.k,self.is_primal)
30 | f.v = self.v + other.v
31 | return f
32 | def __sub__(self,other):
33 | assert(self.k == other.k and self.complex == other.complex)
34 | f = cochain(self.complex,self.k,self.is_primal)
35 | f.v = self.v - other.v
36 | return f
37 | def __getitem__(self,key):
38 | if isinstance(key,Simplex):
39 | data = self.complex[len(key) - 1]
40 | index = data.simplex_to_index[key]
41 | value = self.v.__getitem__(index)
42 | if key.parity == data.simplex_parity[index]:
43 | return value
44 | else:
45 | return -value
46 | else:
47 | return self.v.__getitem__(key)
48 | def __setitem__(self,key,value):
49 | if isinstance(key,Simplex):
50 | data = self.complex[len(key) - 1]
51 | index = data.simplex_to_index[key]
52 | if key.parity == data.simplex_parity[index]:
53 | self.v.__setitem__(index,value)
54 | else:
55 | self.v.__setitem__(index,-value)
56 | else:
57 | self.v.__setitem__(key,value)
58 |
59 | def __str__(self):
60 | return 'cochain(k='+str(self.k) + ',n=' + str(self.n) + ',is_primal=' + str(self.is_primal) + '\n' + str(self.v) + ')'
61 |
62 |
63 | def d(f):
64 | """
65 | Implements the discrete exterior derivative d(.)
66 |
67 | Accepts a cochain and returns the discrete d applied to the cochain
68 | """
69 | if f.is_primal:
70 | df = cochain(f.complex, f.k + 1, f.is_primal)
71 | if f.k == -1:
72 | df.v = sparse.csr_matrix((f.complex[0].num_simplices,1)) * f.v
73 | elif f.k < -1 or f.k > f.n + 1:
74 | df.v = sparse.csr_matrix((1,1)) * f.v
75 | else:
76 | df.v = f.complex[f.k].d * f.v
77 | return df
78 | else:
79 | df = cochain(f.complex,f.k + 1,f.is_primal)
80 | if f.k == -1:
81 | df.v = sparse.csr_matrix((f.complex[f.n].num_simplices,1)) * f.v
82 | elif f.k < -1 or f.k > f.n + 1:
83 | df.v = sparse.csr_matrix((1,1)) * f.v
84 | else:
85 | df.v = f.complex[f.n - f.k].boundary * f.v
86 | df.v *= (-1) ** f.k
87 | return df
88 |
89 | def star(f):
90 | """
91 | Implements the discrete Hodge star *(.)
92 |
93 | Accepts a cochain and returns the Hodge star applied to the cochain
94 | """
95 | if f.k == -1 or f.k == f.n + 1:
96 | starf = cochain(f.complex, f.n - f.k, not f.is_primal)
97 | starf.v = f.v
98 | return starf
99 | elif f.is_primal:
100 | starf = cochain(f.complex, f.n - f.k, not f.is_primal)
101 | starf.v = f.complex[f.k].star * f.v
102 | return starf
103 | else:
104 | starf = cochain(f.complex, f.n - f.k, not f.is_primal)
105 | starf.v = f.complex[f.n - f.k].star_inv * f.v
106 | return starf
107 |
108 | def delta(f):
109 | """
110 | Implements the discrete codifferental \delta(.)
111 |
112 | Accepts a cochain and returns the codifferental of the cochain
113 | """
114 | sdsf = star(d(star(f)))
115 | sdsf.v *= (-1)**(f.n*(f.k-1)+1)
116 | return sdsf
117 |
118 | def laplace_derham(f):
119 | """
120 | Implements the discrete Laplace-de Rham \del(.)
121 |
122 | Accepts a cochain and returns the Laplace-de Rham of the cochain
123 |
124 | """
125 | return d(delta(f)) + delta(d(f))
126 |
127 | def laplace_beltrami(f):
128 | """
129 | Implements the discrete Laplace-Beltrami \del(.) = \delta d
130 |
131 | Accepts a cochain and returns the Laplace-Beltrami of the cochain
132 |
133 | In the case of 0-forms, the second term of the Laplace-de Rham d(\delta(.)) is 0
134 | so the Laplace-Beltrami and Laplace-de Rham will be the same.
135 | """
136 | return delta(d(f))
137 |
138 |
139 |
140 | #for backwards compatibility
141 | Cochain = cochain
142 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/cube_array.py:
--------------------------------------------------------------------------------
1 | from numpy import vstack, hstack, ones, arange, empty, array, \
2 | lexsort, ravel, hsplit, empty, ascontiguousarray, ndim
3 | from numpy import all as alltrue #temporary fix. Change above to np.*
4 |
5 | from scipy.sparse import csr_matrix
6 |
7 | __all__ = ['cube_array_search', 'cube_array_boundary']
8 |
9 | def cube_array_search(k_face_array,k_faces):
10 | """
11 | Find the row indices (of s) corresponding to the
12 | cubes stored in the rows of cube array v.
13 | It is assumed that the rows of s are sorted in
14 | lexicographical order.
15 |
16 | Example:
17 |
18 | k_face_array = array([[0,0,0],[0,0,1],[0,1,0],[1,0,1]])
19 | k_faces = array([[0,1,0],[0,0,1]])
20 | cube_array_searchsorted(k_face_array,k_faces)
21 |
22 | Returns:
23 |
24 | array([2,1])
25 |
26 | """
27 |
28 | if ndim(k_face_array) != 2 or ndim(k_faces) != 2:
29 | raise ValueError('expected rank 2 arrays')
30 |
31 | if k_face_array.shape[1] != k_faces.shape[1]:
32 | raise ValueError('number of columns must agree')
33 |
34 | # a dense array used to lookup k_face_array row indices
35 | lookup_grid_dimensions = k_face_array.max(axis=0) + 1
36 |
37 | lookup_grid = empty(lookup_grid_dimensions,dtype=k_faces.dtype)
38 | lookup_grid[:] = -1
39 | lookup_grid[hsplit(k_face_array,k_face_array.shape[1])] = arange(k_face_array.shape[0],dtype=k_faces.dtype).reshape((-1,1))
40 | row_indices = lookup_grid[hsplit(k_faces,k_faces.shape[1])].reshape((-1))
41 |
42 | return row_indices
43 |
44 |
45 | def cube_array_boundary(cubes,dim):
46 | """
47 | Compute the faces and boundary operator for a regular grid of N-cubes
48 | """
49 | cube_dim = dim
50 | top_dim = cubes.shape[1] - cube_dim
51 | num_cubes = cubes.shape[0]
52 | num_faces = 2*num_cubes*cube_dim
53 |
54 | faces = empty((num_faces,cubes.shape[1]+1),dtype='int32')
55 |
56 | # Use simplex orientation to determine sign of boundary faces
57 | for i in range(cube_dim):
58 | # Faces originating at cube origin
59 | rows = faces[(2*i+0)*num_cubes:(2*i+1)*num_cubes]
60 | rows[:,:top_dim+i ] = cubes[:,:top_dim+i ]
61 | rows[:, top_dim+i:-2] = cubes[:, top_dim+i+1:]
62 | rows[:,-2] = arange(num_cubes)
63 | rows[:,-1] = (-1)**(i+1)
64 |
65 | # Faces originating at other corners of cube
66 | rows = faces[(2*i+1)*num_cubes:(2*i+2)*num_cubes]
67 | rows[:,:top_dim+i ] = cubes[:,:top_dim+i ]
68 | rows[:, top_dim+i:-2] = cubes[:, top_dim+i+1:]
69 | rows[:,-2] = arange(num_cubes)
70 | rows[:,-1] = (-1)**(i+2)
71 | rows[arange(rows.shape[0]),cubes[:,top_dim+i]] += 1
72 |
73 | #sort rows
74 | faces = faces[lexsort([faces[:,i] for i in reversed(range(faces.shape[1]-2))])]
75 |
76 | #find unique faces
77 | face_mask = -hstack((array([False]),alltrue(faces[1:,:-2] == faces[:-1,:-2],axis=1)))
78 |
79 | unique_faces = faces[face_mask,:-2].copy()
80 |
81 | #compute CSR representation for boundary operator
82 | indptr = hstack((arange(num_faces)[face_mask],array([num_faces])))
83 | indices = ascontiguousarray(faces[:,-2])
84 | data = ascontiguousarray(faces[:,-1].astype('int8'))
85 |
86 | shape = (len(unique_faces),num_cubes)
87 | boundary_operator = csr_matrix((data,indices,indptr), shape )
88 |
89 | return unique_faces,boundary_operator
90 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/info.py:
--------------------------------------------------------------------------------
1 | """
2 | DEC data structures
3 | =============
4 |
5 | Docs should follow this format:
6 |
7 |
8 | Scipy 2D sparse matrix module.
9 |
10 | Original code by Travis Oliphant.
11 | Modified and extended by Ed Schofield and Robert Cimrman.
12 |
13 | There are four available sparse matrix types:
14 | (1) csc_matrix: Compressed Sparse Column format
15 | (2) csr_matrix: Compressed Sparse Row format
16 | (3) lil_matrix: List of Lists format
17 | (4) dok_matrix: Dictionary of Keys format
18 |
19 | To construct a matrix efficiently, use either lil_matrix (recommended) or
20 | dok_matrix. The lil_matrix class supports basic slicing and fancy
21 | indexing with a similar syntax to NumPy arrays.
22 |
23 | To perform manipulations such as multiplication or inversion, first
24 | convert the matrix to either CSC or CSR format. The lil_matrix format is
25 | row-based, so conversion to CSR is efficient, whereas conversion to CSC
26 | is less so.
27 |
28 | Example:
29 | Construct a 10x1000 lil_matrix and add some values to it:
30 | >>> from scipy import sparse, linsolve
31 | >>> from numpy import linalg
32 | >>> from numpy.random import rand
33 | >>> A = sparse.lil_matrix((1000, 1000))
34 | >>> A[0, :100] = rand(100)
35 | >>> A[1, 100:200] = A[0, :100]
36 | >>> A.setdiag(rand(1000))
37 |
38 | Now convert it to CSR format and solve (A A^T) x = b for x:
39 | >>> A = A.tocsr()
40 | >>> b = rand(1000)
41 | >>> x = linsolve.spsolve(A * A.T, b)
42 |
43 | Convert it to a dense matrix and solve, and check that the result
44 | is the same:
45 | >>> A_ = A.todense()
46 | >>> x_ = linalg.solve(A_ * A_.T, b)
47 | >>> err = linalg.norm(x-x_)
48 |
49 | Now we can print the error norm with:
50 | print "Norm error =", err
51 | It should be small :)
52 |
53 | """
54 |
55 | postpone_import = 1
56 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/regular_cube_complex.py:
--------------------------------------------------------------------------------
1 | __all__ = ['regular_cube_complex']
2 |
3 | from numpy import ones, ndim
4 | import scipy
5 |
6 | from pydec.mesh import regular_cube_mesh
7 | from .cube_array import cube_array_boundary
8 |
9 | class regular_cube_complex(list):
10 | """
11 | Represents the complex for a regular_cube_mesh
12 | """
13 | class complex_data:
14 | pass
15 |
16 | def __init__(self,mesh):
17 | if not isinstance(mesh,regular_cube_mesh):
18 | raise ValueError('expected a regular_cube_mesh')
19 |
20 | self.mesh = mesh
21 |
22 | self.__construct_hierarchy()
23 |
24 | self.vertices = self[0].cube_array.astype(float)
25 |
26 | #self.__test()
27 |
28 | def __repr__(self):
29 | output = ""
30 | output += "regular_cube_complex:\n"
31 | output += " Shape: " + str(self.mesh.bitmap.shape) + "\n"
32 | output += " Complex:\n"
33 | for i in reversed(range(len(self))):
34 | output += " %10d: %2d-D cubes\n" % (self[i].cube_array.shape[0],i)
35 | return output
36 |
37 | def __test(self):
38 | #test boundary operator
39 | for prev,next in zip(self[:-1],self[1:]):
40 | assert((prev.boundary*next.boundary).nnz == 0)
41 |
42 | def chain_complex(self):
43 | return [lvl.boundary for lvl in self]
44 |
45 | def cochain_complex(self):
46 | return [lvl.boundary.T.tocsr() for lvl in self[1:]] + \
47 | [scipy.sparse.csr_matrix((1,self[-1].cube_array.shape[0]),dtype='int8')]
48 |
49 | def complex_dimension(self):
50 | return self.mesh.dimension()
51 |
52 | def embedding_dimension(self):
53 | return self.mesh.dimension()
54 |
55 | def __construct_hierarchy(self):
56 | for i in range(self.complex_dimension() + 1):
57 | self.append(self.complex_data())
58 |
59 | self[-1].cube_array = self.mesh.cube_array()
60 |
61 | for i in reversed(range(self.complex_dimension())):
62 | faces,boundary = cube_array_boundary(self[i+1].cube_array,i+1)
63 | self[i ].cube_array = faces
64 | self[i+1].boundary = boundary
65 |
66 | self[0].boundary = scipy.sparse.csr_matrix((1,self[0].cube_array.shape[0]),dtype='int8')
67 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/rips_complex.py:
--------------------------------------------------------------------------------
1 | from numpy import ones, arange, array, asarray, hstack, empty, lexsort
2 | from scipy.sparse import csr_matrix, csc_matrix
3 |
4 | from pydec.mesh.simplex import simplex
5 | from pydec.math import kd_tree
6 | from pydec.util import flatten
7 |
8 | from .simplex_array import simplex_array_searchsorted
9 |
10 | __all__ = ['rips_complex']
11 |
12 | class rips_complex:
13 | def __init__(self, vertices, delta):
14 | """Construct a Rips complex
15 |
16 | Construct a Rips for an array of vertices and a radius delta.
17 |
18 | Parameters
19 | ----------
20 | vertices : array_like
21 | An N-by-D array of vertex coordinates where N is the
22 | number of vertices and D is the dimension of the space
23 | delta : float
24 | Radius used to determine the connectivity of the Rips complex.
25 | Vertices which are separated by no more than distance delta
26 | are connected by an edge in the 1-skeleton of the Rips complex.
27 |
28 | Examples
29 | --------
30 | >>> from pydec.dec import rips_complex
31 | >>> from numpy import array
32 | >>> vertices = array([[0,0],[2,0],[2,2],[0,2],[1,1]], dtype='float')
33 | >>> delta = 2.1
34 | >>> rc = rips_complex(vertices, delta)
35 | >>> print rc.simplices[0]
36 | [[0]
37 | [1]
38 | [2]
39 | [3]
40 | [4]]
41 | >>> print rc.simplices[1]
42 | [[0 1]
43 | [0 3]
44 | [0 4]
45 | [1 2]
46 | [1 4]
47 | [2 3]
48 | [2 4]
49 | [3 4]]
50 | >>> print rc.simplices[2]
51 | [[0 1 4]
52 | [0 3 4]
53 | [1 2 4]
54 | [2 3 4]]
55 |
56 | """
57 |
58 | vertices = asarray(vertices)
59 |
60 | # construct kD-Tree for spatial queries
61 | tree = kd_tree(vertices)
62 |
63 | # for each vertex, compute all vertices within distance r
64 | L = [tree.in_sphere(v, delta) for v in vertices]
65 |
66 | # convert list of list structure into array of edges
67 | i = arange(len(vertices)).repeat( [len(x) for x in L] )
68 | j = array( flatten(L) )
69 | edges = hstack((i.reshape(-1,1),j.reshape(-1,1)))
70 |
71 | # compute simplices of the Rips complex from edges (1-skeleton of Rips complex)
72 | simplices = rips_simplices(vertices.shape[0], edges, vertices.shape[1])
73 |
74 | # compute boundary operators of the Rips complex
75 | chain_complex = rips_chain_complex(simplices)
76 |
77 | # store the cochain complex
78 | Bn = chain_complex[-1]
79 | cochain_complex = [ B.T for B in chain_complex[1:] ]
80 | cochain_complex += [ csr_matrix( (1, Bn.shape[1]), dtype=Bn.dtype) ]
81 |
82 | # store the data members
83 | self.vertices = vertices
84 | self.simplices = simplices
85 | self._chain_complex = chain_complex
86 | self._cochain_complex = cochain_complex
87 |
88 | def complex_dimension(self):
89 | return len(self.cochain_complex()) - 1
90 |
91 | def embedding_dimension(self):
92 | return self.vertices.shape[1]
93 |
94 | def complex(self):
95 | return self.simplices
96 |
97 | def chain_complex(self):
98 | return self._chain_complex
99 |
100 | def cochain_complex(self):
101 | return self._cochain_complex
102 |
103 |
104 | def rips_chain_complex(simplices):
105 | """Construct the boundary operators for the Rips complex
106 |
107 | Constructs the boundary operators for the Rips complex for
108 | a given a list of simplex arrays.
109 |
110 | Parameters
111 | ----------
112 | simplices : list of arrays
113 | List of length D, where simplices[i] is the simplex
114 | array representing the i-dimensional simplices.
115 |
116 | Returns
117 | -------
118 | Bs : list of sparse matrices
119 | List of length D + 1 where Bs[i] is the boundary operator
120 | for the i-dimensional simplices.
121 |
122 | Examples
123 | --------
124 | TODO
125 |
126 | """
127 | Bs = []
128 |
129 | dtype = 'float32'
130 |
131 | simplices = [asarray(x) for x in simplices]
132 |
133 | B0 = csc_matrix( (1, len(simplices[0]) ), dtype=dtype )
134 | Bs.append( B0 )
135 |
136 | if len(simplices) == 1:
137 | B1 = csc_matrix( (len(simplices[0]), 1), dtype=dtype )
138 | Bs.append(B1)
139 | return Bs
140 |
141 | B1 = empty( 2*len(simplices[1]), dtype=dtype )
142 | B1[0::2] = -1
143 | B1[1::2] = 1
144 | B1 = csc_matrix( ( B1, simplices[1].ravel(), arange(0, 2*(len(simplices[1]) + 1), 2)), \
145 | shape=(len(simplices[0]), len(simplices[1])) )
146 | Bs.append( B1 )
147 |
148 | for f,s in zip(simplices[1:-1],simplices[2:]):
149 | k = f.shape[1]
150 |
151 | faces = empty(( len(s), (k+1), k),dtype=s.dtype)
152 | for i in range(k+1):
153 | faces[:,i,:i] = s[:, : i ]
154 | faces[:,i,i:] = s[:,i+1: ]
155 |
156 | indptr = arange(0, (k+1)*(len(s) + 1), k+1)
157 | indices = simplex_array_searchsorted(f, faces.reshape(-1,k) )
158 | data = empty( faces.shape[:-1], dtype=dtype )
159 | for i in range(k+1):
160 | data[:,i] = (-1)**i
161 | data = data.ravel()
162 |
163 | Bs.append( csc_matrix( (data,indices,indptr), shape=(len(f),len(s)) ) )
164 |
165 | return Bs
166 |
167 |
168 |
169 | def rips_simplices(num_vertices, edges, k):
170 | """Compute simplices of the Rips complex
171 |
172 | Returns a list of simplex arrays representing
173 | the 0 to k-dimensional simplices of the Rips complex.
174 |
175 | Parameters
176 | ----------
177 | num_verticles : integer
178 | Number of vertices/points/nodes in the Rips complex
179 | edges : array_like
180 | An N-by-2 array containing the edges of the Rips complex
181 | k : integer
182 | Maximum simplex dimension
183 |
184 | Returns
185 | -------
186 | simplices : list of arrays
187 | List of length k+1, where simplices[i] is the simplex
188 | array representing the i-dimensional simplices.
189 |
190 | Examples
191 | --------
192 | >>> from numpy import array
193 | >>> edges = array([[0,1],[0,2],[1,0],[1,2],[2,0],[2,1]])
194 | >>> simplices = rips_simplices(3, edges, 2)
195 | >>> print simplices[0]
196 | [[0]
197 | [1]
198 | [2]]
199 | >>> print simplices[1]
200 | [[0 1]
201 | [0 2]
202 | [1 2]]
203 | >>> print simplices[2]
204 | [[0 1 2]]
205 |
206 | """
207 |
208 | edges = asarray(edges, dtype='int32')
209 |
210 | simplices = []
211 |
212 | if len(edges.shape) != 2 and edges.shape[1] != 2:
213 | raise ValueError('expected N by 2 array for argument edges')
214 |
215 | # node simplices
216 | simplices.append( arange(num_vertices, dtype=edges.dtype).reshape(-1,1) )
217 |
218 | # no work to do
219 | if k == 0: return simplices
220 |
221 | edges = edges[edges[:,0] < edges[:,1]] # orient edges
222 | if edges.shape[0] != 0:
223 | edges = edges[lexsort( edges.T[::-1] )] # sort edges
224 | simplices.append( edges )
225 |
226 | if k == 1 or edges.shape[0] == 0: return simplices
227 |
228 | # E[i,j] == 1 iff (i,j) is an edge and i < j
229 | E = csr_matrix( (ones(len(edges), dtype='int8'), edges.T), shape=(num_vertices,num_vertices))
230 |
231 | k_faces = edges
232 |
233 | for n in range(1,k):
234 | if k_faces.shape[0] == 0:
235 | break
236 |
237 | indptr = arange(0, (n+1) * (len(k_faces)+1), (n+1) )
238 | indices = k_faces.ravel()
239 | data = ones(len(indices), dtype='int8')
240 |
241 | F = csr_matrix((data, indices, indptr), shape=(len(k_faces), num_vertices))
242 |
243 | # FE[i,j] == n+1 if all vertices in face i are adjacent to vertex j
244 | FE = F*E
245 | FE.data[FE.data != n+1] = 0
246 | FE.eliminate_zeros()
247 | FE.sort_indices()
248 |
249 | row = FE.tocoo(copy=False).row
250 | k_faces = hstack( (k_faces[row],FE.indices.reshape(-1,1)) )
251 |
252 | if len(k_faces) == 0:
253 | return simplices
254 |
255 | simplices.append( k_faces )
256 |
257 | return simplices
258 |
259 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/simplex_array.py:
--------------------------------------------------------------------------------
1 | __all__ = ['simplex_array_searchsorted','simplex_array_boundary','simplex_array_parity']
2 |
3 |
4 | from numpy import ravel, zeros, ones, arange, empty, array, lexsort, \
5 | hstack, vstack, ndim, bincount, cumsum, ascontiguousarray, zeros_like, \
6 | concatenate, asarray
7 | from numpy import all as alltrue #temporary fix. Change above to np.*
8 | from scipy.sparse import csr_matrix
9 |
10 | def simplex_array_searchsorted(s, v):
11 | """Find the row indices (of s) corresponding to the simplices stored
12 | in the rows of simplex array v. The rows of s must be stored in
13 | lexicographical order.
14 |
15 | Example
16 | -------
17 |
18 | >>> from numpy import array
19 | >>> s = array([[0,1],[0,2],[1,2],[1,3]])
20 | >>> v = array([[1,2],[0,2]])
21 | >>> simplex_array_searchsorted(s,v)
22 | array([2, 1])
23 |
24 | """
25 |
26 | s = asarray(s)
27 | v = asarray(v)
28 |
29 | if ndim(s) != 2 or ndim(v) != 2:
30 | raise ValueError('expected rank 2 arrays')
31 |
32 | if s.shape[1] != v.shape[1]:
33 | raise ValueError('number of columns must agree')
34 |
35 | # compute row indices by sorting both arrays together
36 | Ns = s.shape[0]
37 | Nv = v.shape[0]
38 |
39 | perm = lexsort(vstack((s,v))[:,::-1].T)
40 |
41 | flags = concatenate( (ones(Ns,dtype=int),zeros(Nv,dtype=int)) )
42 | indices = empty(Ns+Nv, dtype=int)
43 | indices[perm] = cumsum(flags[perm])
44 | indices = indices[Ns:].copy()
45 | indices -= 1
46 |
47 | return indices
48 |
49 |
50 |
51 |
52 | def simplex_array_parity(s):
53 | """Compute the relative parity of an array of simplices
54 | """
55 | s = s.copy()
56 |
57 | M,N = s.shape
58 |
59 | # number of transpositions used to sort the
60 | # indices of each simplex (row of s)
61 | trans = zeros_like(s[:,0])
62 | seq = arange(M)
63 |
64 | for i in range(N-1):
65 | pos = s.argmin(axis=1)
66 | s[seq,pos] = s[:,0]
67 | pos.clip(0,1,pos)
68 | trans += pos
69 | s = s[:,1:]
70 |
71 | trans %= 2 #compute parity
72 |
73 | return trans
74 |
75 |
76 |
77 |
78 | def simplex_array_boundary(s,parity):
79 | """
80 | Compute the boundary faces and boundary operator of an
81 | array of simplices with given simplex parities
82 |
83 | E.g.
84 |
85 | For a mesh with two triangles [0,1,2] and [1,3,2], the second
86 | triangle has opposite parity relative to sorted order.
87 |
88 | simplex_array_boundary(array([[0,1,2],[1,2,3]]),array([0,1]))
89 |
90 | """
91 | #TODO handle edge case as special case
92 |
93 | num_simplices = s.shape[0]
94 | faces_per_simplex = s.shape[1]
95 | num_faces = num_simplices * faces_per_simplex
96 |
97 | orientations = 1 - 2*parity
98 |
99 | #faces[:,:-2] are the indices of the faces
100 | #faces[:,-2] is the index of the simplex whose boundary produced the face
101 | #faces[:,-1] is the orientation of the face in the boundary of the simplex
102 | faces = empty((num_faces,s.shape[1]+1),dtype=s.dtype)
103 | for i in range(faces_per_simplex):
104 | rows = faces[num_simplices*i:num_simplices*(i+1)]
105 |
106 | rows[:, : i] = s[:, :i]
107 | rows[:,i :-2] = s[:,i+1: ]
108 | rows[:, -2 ] = arange(num_simplices)
109 | rows[:, -1 ] = ((-1)**i)*orientations
110 |
111 | #sort rows
112 | faces = faces[lexsort( faces[:,:-2].T[::-1] )]
113 |
114 | #find unique faces
115 | face_mask = ~hstack((array([False]), alltrue(faces[1:,:-2] == faces[:-1,:-2], axis=1)))
116 |
117 | unique_faces = faces[face_mask,:-2]
118 |
119 | #compute CSR representation for boundary operator
120 | csr_indptr = hstack((arange(num_faces)[face_mask],array([num_faces])))
121 | csr_indices = ascontiguousarray(faces[:,-2])
122 | csr_data = faces[:,-1].astype('int8')
123 |
124 | shape = (len(unique_faces),num_simplices)
125 | boundary_operator = csr_matrix((csr_data,csr_indices,csr_indptr), shape)
126 |
127 | return unique_faces,boundary_operator
128 |
129 |
130 |
131 |
132 |
133 | ####################################
134 | ## Fast C implementations
135 | ####################################
136 | #
137 | #
138 | #import scipy
139 | #
140 | #def simplex_array_searchsorted(s,v):
141 | # """
142 | # Find the row indices (of s) corresponding to the
143 | # simplices stored in the rows of simplex array v.
144 | # It is assumed that the rows of s are sorted in
145 | # lexicographical order.
146 | #
147 | # Example:
148 | #
149 | # s = array([[0,1],[0,2],[1,2],[1,3]])
150 | # v = array([[1,2],[0,2]])
151 | # simplex_array_searchsorted(s,v)
152 | #
153 | # Returns:
154 | #
155 | # array([2,1])
156 | #
157 | # """
158 | #
159 | # if ndim(s) != 2 or ndim(v) != 2:
160 | # raise ValueError,'expected rank 2 arrays'
161 | #
162 | # if s.shape[1] != v.shape[1]:
163 | # raise ValueError,'number of columns must agree'
164 | #
165 | # s_row = s.shape[0]
166 | # v_row = v.shape[0]
167 | # s_col = s.shape[1]
168 | # s_max = int(s[:,0].max())
169 | #
170 | # first_index = cumsum(hstack((array([0]),bincount(s[:,0]))))
171 | # indices = empty(v.shape[0],dtype=s.dtype)
172 | #
173 | # code = """
174 | # #line 45 "simplex_array.py"
175 | #
176 | # for(int i = 0; i < v_row; i++){
177 | #
178 | # int v_i0 = v(i,0);
179 | #
180 | # if (v(i,0) > s_max)
181 | # py::fail(PyExc_ValueError, "index exceeds expected range");
182 | #
183 | # int row_start = first_index(v_i0);
184 | # int row_end = first_index(v_i0+1);
185 | #
186 | # int row_index = -1;
187 | # for(int k = row_start; k < row_end; k++){
188 | # bool mismatch = false;
189 | # for(int j = 1; j < s_col; j++){
190 | # if(v(i,j) != s(k,j)){
191 | # mismatch = true;
192 | # break;
193 | # }
194 | # }
195 | # if(!mismatch){
196 | # row_index = k;
197 | # break;
198 | # }
199 | # }
200 | # if (row_index == -1)
201 | # py::fail(PyExc_ValueError, "simplex not found");
202 | #
203 | # indices(i) = row_index;
204 | # }
205 | # """
206 | #
207 | # err = scipy.weave.inline(code,
208 | # ['s','v','first_index', 'indices', 's_row', 'v_row', 's_col','s_max'],
209 | # type_converters = scipy.weave.converters.blitz,
210 | # compiler = 'gcc')
211 | #
212 | # return indices
213 | #
214 | #
215 | #
216 | #def simplex_array_parity(s):
217 | # """
218 | # Compute the relative parity of an array of simplices
219 | # """
220 | # perms = s.argsort()
221 | #
222 | #
223 | # n_rows,n_cols = perms.shape
224 | #
225 | # parity = zeros(n_rows,dtype=perms.dtype)
226 | # seen = zeros(n_cols,dtype=perms.dtype)
227 | #
228 | # code = """
229 | # #line 26 "relaxation.py"
230 | #
231 | # for(int i = 0; i < n_rows; i++){
232 | # int num_cycles = 0;
233 | # for(int j = 0; j < n_cols; j++){
234 | #
235 | # if(seen(j) == 1) continue;
236 | #
237 | # int k = j;
238 | #
239 | # num_cycles++;
240 | # while ( true ){
241 | # seen(k) = 1;
242 | # k = perms(i,k);
243 | # if (j == k) break;
244 | # }
245 | # }
246 | # for(int j = 0; j < n_cols; j++){ seen(j) = 0; } //reset seen
247 | # parity(i) = (n_cols - num_cycles) % 2;
248 | # }
249 | # """
250 | #
251 | # from time import clock
252 | #
253 | #
254 | # # compiler keyword only needed on windows with MSVC installed
255 | # err = scipy.weave.inline(code,
256 | # ['perms', 'parity', 'seen', 'n_rows', 'n_cols' ],
257 | # type_converters = scipy.weave.converters.blitz,
258 | # compiler = 'gcc')
259 | #
260 | # return parity
261 |
262 |
263 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/tests/meshes/README.txt:
--------------------------------------------------------------------------------
1 | These meshes are used to test the correctness of simplicial_complex
2 |
3 | sphere3.xml
4 | simplicial_mesh< 2D manifold, 3D embedding, 66 vertices, 128 elements >
5 |
6 | torus_tet.xml
7 | simplicial_mesh< 3D manifold, 3D embedding, 204 vertices, 592 elements >
8 |
9 | cube.xml
10 | simplicial_mesh< 2D manifold, 3D embedding, 8 vertices, 12 elements >
11 |
12 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/tests/meshes/cube.elements:
--------------------------------------------------------------------------------
1 | 6
2 | format=binary
3 | dtype=int32
4 | rank=2
5 | dims=12,3
6 | version=1.0
7 | type=ndarray
8 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/tests/meshes/cube.vertices:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hirani/pydec/930bb8167978a7b980fc547c8d9237de3e690292/pydec/pydec/dec/tests/meshes/cube.vertices
--------------------------------------------------------------------------------
/pydec/pydec/dec/tests/meshes/cube.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/pydec/pydec/dec/tests/meshes/sphere3.elements:
--------------------------------------------------------------------------------
1 | 6
2 | format=binary
3 | dtype=int32
4 | rank=2
5 | dims=128,3
6 | version=1.0
7 | type=ndarray
8 |
9 |
10 |
11 |
12 |
13 |
14 | ! ! " ! " # ! ! $ # $ ! # % $ &