grid-simulate 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- grid_simulate-0.1.0/.github/workflows/publish.yml +48 -0
- grid_simulate-0.1.0/.gitignore +1 -0
- grid_simulate-0.1.0/.idea/.gitignore +8 -0
- grid_simulate-0.1.0/.idea/GRiD.iml +8 -0
- grid_simulate-0.1.0/.idea/inspectionProfiles/profiles_settings.xml +6 -0
- grid_simulate-0.1.0/.idea/misc.xml +7 -0
- grid_simulate-0.1.0/.idea/modules.xml +8 -0
- grid_simulate-0.1.0/.idea/vcs.xml +6 -0
- grid_simulate-0.1.0/Cargo.lock +280 -0
- grid_simulate-0.1.0/Cargo.toml +26 -0
- grid_simulate-0.1.0/PKG-INFO +5 -0
- grid_simulate-0.1.0/README.md +42 -0
- grid_simulate-0.1.0/pyproject.toml +12 -0
- grid_simulate-0.1.0/python/test_bridge.py +158 -0
- grid_simulate-0.1.0/src/lib.rs +393 -0
- grid_simulate-0.1.0/src/main.rs +269 -0
- grid_simulate-0.1.0/src/node.rs +123 -0
- grid_simulate-0.1.0/src/rank.rs +191 -0
- grid_simulate-0.1.0/src/reconstruct.rs +230 -0
- grid_simulate-0.1.0/src/rigidity.rs +101 -0
- grid_simulate-0.1.0/src/simulation.rs +229 -0
- grid_simulate-0.1.0/src/traversal.rs +60 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
id-token: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Build wheels with maturin
|
|
19
|
+
uses: PyO3/maturin-action@v1
|
|
20
|
+
with:
|
|
21
|
+
command: build
|
|
22
|
+
args: --release --sdist
|
|
23
|
+
|
|
24
|
+
- name: Upload artifacts
|
|
25
|
+
uses: actions/upload-artifact@v4
|
|
26
|
+
with:
|
|
27
|
+
name: dist
|
|
28
|
+
path: target/wheels/
|
|
29
|
+
|
|
30
|
+
publish:
|
|
31
|
+
needs: build
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
|
|
34
|
+
permissions:
|
|
35
|
+
id-token: write
|
|
36
|
+
|
|
37
|
+
environment:
|
|
38
|
+
name: pypi
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- name: Download artifacts
|
|
42
|
+
uses: actions/download-artifact@v4
|
|
43
|
+
with:
|
|
44
|
+
name: dist
|
|
45
|
+
path: dist/
|
|
46
|
+
|
|
47
|
+
- name: Publish to PyPI
|
|
48
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/target
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="PYTHON_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager">
|
|
4
|
+
<content url="file://$MODULE_DIR$" />
|
|
5
|
+
<orderEntry type="jdk" jdkName="Python 3.13" jdkType="Python SDK" />
|
|
6
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
7
|
+
</component>
|
|
8
|
+
</module>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="Black">
|
|
4
|
+
<option name="sdkName" value="Python 3.13" />
|
|
5
|
+
</component>
|
|
6
|
+
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13" project-jdk-type="Python SDK" />
|
|
7
|
+
</project>
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# This file is automatically @generated by Cargo.
|
|
2
|
+
# It is not intended for manual editing.
|
|
3
|
+
version = 4
|
|
4
|
+
|
|
5
|
+
[[package]]
|
|
6
|
+
name = "approx"
|
|
7
|
+
version = "0.5.1"
|
|
8
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
+
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"num-traits",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[[package]]
|
|
15
|
+
name = "autocfg"
|
|
16
|
+
version = "1.5.1"
|
|
17
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
18
|
+
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
|
19
|
+
|
|
20
|
+
[[package]]
|
|
21
|
+
name = "cfg-if"
|
|
22
|
+
version = "1.0.4"
|
|
23
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
24
|
+
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
|
25
|
+
|
|
26
|
+
[[package]]
|
|
27
|
+
name = "grid"
|
|
28
|
+
version = "0.1.0"
|
|
29
|
+
dependencies = [
|
|
30
|
+
"approx",
|
|
31
|
+
"ndarray",
|
|
32
|
+
"numpy",
|
|
33
|
+
"pyo3",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[[package]]
|
|
37
|
+
name = "heck"
|
|
38
|
+
version = "0.5.0"
|
|
39
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
40
|
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|
41
|
+
|
|
42
|
+
[[package]]
|
|
43
|
+
name = "indoc"
|
|
44
|
+
version = "2.0.7"
|
|
45
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
46
|
+
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
|
|
47
|
+
dependencies = [
|
|
48
|
+
"rustversion",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
[[package]]
|
|
52
|
+
name = "libc"
|
|
53
|
+
version = "0.2.186"
|
|
54
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
55
|
+
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
|
56
|
+
|
|
57
|
+
[[package]]
|
|
58
|
+
name = "matrixmultiply"
|
|
59
|
+
version = "0.3.10"
|
|
60
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
61
|
+
checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08"
|
|
62
|
+
dependencies = [
|
|
63
|
+
"autocfg",
|
|
64
|
+
"rawpointer",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
[[package]]
|
|
68
|
+
name = "memoffset"
|
|
69
|
+
version = "0.9.1"
|
|
70
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
71
|
+
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
|
72
|
+
dependencies = [
|
|
73
|
+
"autocfg",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
[[package]]
|
|
77
|
+
name = "ndarray"
|
|
78
|
+
version = "0.16.1"
|
|
79
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
80
|
+
checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841"
|
|
81
|
+
dependencies = [
|
|
82
|
+
"matrixmultiply",
|
|
83
|
+
"num-complex",
|
|
84
|
+
"num-integer",
|
|
85
|
+
"num-traits",
|
|
86
|
+
"portable-atomic",
|
|
87
|
+
"portable-atomic-util",
|
|
88
|
+
"rawpointer",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
[[package]]
|
|
92
|
+
name = "num-complex"
|
|
93
|
+
version = "0.4.6"
|
|
94
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
95
|
+
checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495"
|
|
96
|
+
dependencies = [
|
|
97
|
+
"num-traits",
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
[[package]]
|
|
101
|
+
name = "num-integer"
|
|
102
|
+
version = "0.1.46"
|
|
103
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
104
|
+
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
|
105
|
+
dependencies = [
|
|
106
|
+
"num-traits",
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
[[package]]
|
|
110
|
+
name = "num-traits"
|
|
111
|
+
version = "0.2.19"
|
|
112
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
113
|
+
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
|
114
|
+
dependencies = [
|
|
115
|
+
"autocfg",
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
[[package]]
|
|
119
|
+
name = "numpy"
|
|
120
|
+
version = "0.22.1"
|
|
121
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
122
|
+
checksum = "edb929bc0da91a4d85ed6c0a84deaa53d411abfb387fc271124f91bf6b89f14e"
|
|
123
|
+
dependencies = [
|
|
124
|
+
"libc",
|
|
125
|
+
"ndarray",
|
|
126
|
+
"num-complex",
|
|
127
|
+
"num-integer",
|
|
128
|
+
"num-traits",
|
|
129
|
+
"pyo3",
|
|
130
|
+
"rustc-hash",
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
[[package]]
|
|
134
|
+
name = "once_cell"
|
|
135
|
+
version = "1.21.4"
|
|
136
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
137
|
+
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
|
138
|
+
|
|
139
|
+
[[package]]
|
|
140
|
+
name = "portable-atomic"
|
|
141
|
+
version = "1.13.1"
|
|
142
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
143
|
+
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
|
144
|
+
|
|
145
|
+
[[package]]
|
|
146
|
+
name = "portable-atomic-util"
|
|
147
|
+
version = "0.2.7"
|
|
148
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
149
|
+
checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618"
|
|
150
|
+
dependencies = [
|
|
151
|
+
"portable-atomic",
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
[[package]]
|
|
155
|
+
name = "proc-macro2"
|
|
156
|
+
version = "1.0.106"
|
|
157
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
158
|
+
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
|
159
|
+
dependencies = [
|
|
160
|
+
"unicode-ident",
|
|
161
|
+
]
|
|
162
|
+
|
|
163
|
+
[[package]]
|
|
164
|
+
name = "pyo3"
|
|
165
|
+
version = "0.22.6"
|
|
166
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
167
|
+
checksum = "f402062616ab18202ae8319da13fa4279883a2b8a9d9f83f20dbade813ce1884"
|
|
168
|
+
dependencies = [
|
|
169
|
+
"cfg-if",
|
|
170
|
+
"indoc",
|
|
171
|
+
"libc",
|
|
172
|
+
"memoffset",
|
|
173
|
+
"once_cell",
|
|
174
|
+
"portable-atomic",
|
|
175
|
+
"pyo3-build-config",
|
|
176
|
+
"pyo3-ffi",
|
|
177
|
+
"pyo3-macros",
|
|
178
|
+
"unindent",
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
[[package]]
|
|
182
|
+
name = "pyo3-build-config"
|
|
183
|
+
version = "0.22.6"
|
|
184
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
185
|
+
checksum = "b14b5775b5ff446dd1056212d778012cbe8a0fbffd368029fd9e25b514479c38"
|
|
186
|
+
dependencies = [
|
|
187
|
+
"once_cell",
|
|
188
|
+
"target-lexicon",
|
|
189
|
+
]
|
|
190
|
+
|
|
191
|
+
[[package]]
|
|
192
|
+
name = "pyo3-ffi"
|
|
193
|
+
version = "0.22.6"
|
|
194
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
195
|
+
checksum = "9ab5bcf04a2cdcbb50c7d6105de943f543f9ed92af55818fd17b660390fc8636"
|
|
196
|
+
dependencies = [
|
|
197
|
+
"libc",
|
|
198
|
+
"pyo3-build-config",
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
[[package]]
|
|
202
|
+
name = "pyo3-macros"
|
|
203
|
+
version = "0.22.6"
|
|
204
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
205
|
+
checksum = "0fd24d897903a9e6d80b968368a34e1525aeb719d568dba8b3d4bfa5dc67d453"
|
|
206
|
+
dependencies = [
|
|
207
|
+
"proc-macro2",
|
|
208
|
+
"pyo3-macros-backend",
|
|
209
|
+
"quote",
|
|
210
|
+
"syn",
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
[[package]]
|
|
214
|
+
name = "pyo3-macros-backend"
|
|
215
|
+
version = "0.22.6"
|
|
216
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
217
|
+
checksum = "36c011a03ba1e50152b4b394b479826cad97e7a21eb52df179cd91ac411cbfbe"
|
|
218
|
+
dependencies = [
|
|
219
|
+
"heck",
|
|
220
|
+
"proc-macro2",
|
|
221
|
+
"pyo3-build-config",
|
|
222
|
+
"quote",
|
|
223
|
+
"syn",
|
|
224
|
+
]
|
|
225
|
+
|
|
226
|
+
[[package]]
|
|
227
|
+
name = "quote"
|
|
228
|
+
version = "1.0.45"
|
|
229
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
230
|
+
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
|
231
|
+
dependencies = [
|
|
232
|
+
"proc-macro2",
|
|
233
|
+
]
|
|
234
|
+
|
|
235
|
+
[[package]]
|
|
236
|
+
name = "rawpointer"
|
|
237
|
+
version = "0.2.1"
|
|
238
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
239
|
+
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
|
240
|
+
|
|
241
|
+
[[package]]
|
|
242
|
+
name = "rustc-hash"
|
|
243
|
+
version = "1.1.0"
|
|
244
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
245
|
+
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
|
246
|
+
|
|
247
|
+
[[package]]
|
|
248
|
+
name = "rustversion"
|
|
249
|
+
version = "1.0.22"
|
|
250
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
251
|
+
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
|
252
|
+
|
|
253
|
+
[[package]]
|
|
254
|
+
name = "syn"
|
|
255
|
+
version = "2.0.117"
|
|
256
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
257
|
+
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
|
258
|
+
dependencies = [
|
|
259
|
+
"proc-macro2",
|
|
260
|
+
"quote",
|
|
261
|
+
"unicode-ident",
|
|
262
|
+
]
|
|
263
|
+
|
|
264
|
+
[[package]]
|
|
265
|
+
name = "target-lexicon"
|
|
266
|
+
version = "0.12.16"
|
|
267
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
268
|
+
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|
269
|
+
|
|
270
|
+
[[package]]
|
|
271
|
+
name = "unicode-ident"
|
|
272
|
+
version = "1.0.24"
|
|
273
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
274
|
+
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
|
275
|
+
|
|
276
|
+
[[package]]
|
|
277
|
+
name = "unindent"
|
|
278
|
+
version = "0.2.4"
|
|
279
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
280
|
+
checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "grid"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
|
|
7
|
+
[lib]
|
|
8
|
+
name = "grid"
|
|
9
|
+
crate-type = ["cdylib"]
|
|
10
|
+
|
|
11
|
+
[dependencies]
|
|
12
|
+
pyo3 = { version = "0.22", features = ["extension-module"] }
|
|
13
|
+
numpy = "0.22"
|
|
14
|
+
ndarray = "0.16"
|
|
15
|
+
|
|
16
|
+
[profile.release]
|
|
17
|
+
opt-level = 3
|
|
18
|
+
lto = true
|
|
19
|
+
codegen-units = 1
|
|
20
|
+
|
|
21
|
+
[dev-dependencies]
|
|
22
|
+
approx = "0.5"
|
|
23
|
+
|
|
24
|
+
[[bin]]
|
|
25
|
+
name = "grid_sim_demo"
|
|
26
|
+
path = "src/main.rs"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# GRiD — Rigidity-Informed Deep Graph Embeddings
|
|
2
|
+
|
|
3
|
+
Dimension reduction via rigidity theory, with a learned GNN-based
|
|
4
|
+
independence scorer replacing classical Gaussian elimination.
|
|
5
|
+
|
|
6
|
+
## Requirements
|
|
7
|
+
- Rust
|
|
8
|
+
- Python 3.13
|
|
9
|
+
|
|
10
|
+
## Setup
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# 1. Create and activate a Python 3.13 virtual environment
|
|
14
|
+
python3.13 -m venv .venv
|
|
15
|
+
.venv\Scripts\activate # Windows
|
|
16
|
+
source .venv/bin/activate # macOS / Linux
|
|
17
|
+
|
|
18
|
+
# 2. Install build tool
|
|
19
|
+
pip install maturin
|
|
20
|
+
|
|
21
|
+
# 3. Compile the Rust simulation and install the Python bridge
|
|
22
|
+
maturin develop
|
|
23
|
+
|
|
24
|
+
# 4. Verify everything works
|
|
25
|
+
python python/test_bridge.py
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Running the standalone Rust demo (no Python needed)
|
|
29
|
+
```bash
|
|
30
|
+
cargo run
|
|
31
|
+
cargo test
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## If you are having problems compiling the code, it might be because of:
|
|
35
|
+
- Your current python version (pyo3 mismatch)
|
|
36
|
+
|
|
37
|
+
### To solve it:
|
|
38
|
+
Just before compiling the code:
|
|
39
|
+
```bash
|
|
40
|
+
$env:PYO3_PYTHON = "Your Python 3.13 path"
|
|
41
|
+
```
|
|
42
|
+
And you should be fine
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["maturin>=1.5"]
|
|
3
|
+
build-backend = "maturin"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "grid-simulate"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Rust + PyO3 simulation library"
|
|
9
|
+
requires-python = ">=3.8"
|
|
10
|
+
|
|
11
|
+
[tool.maturin]
|
|
12
|
+
features = ["pyo3/extension-module"]
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import grid
|
|
2
|
+
import numpy as np
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
This file is both a bridge and a documentary type of file, so that it is easy for
|
|
6
|
+
everyone to understand which methods are available for our custom lib (grid) and
|
|
7
|
+
what each callable does.
|
|
8
|
+
|
|
9
|
+
author: Sezer
|
|
10
|
+
date: 17/06/2026
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# ---------------------------------------------------------------------------
|
|
15
|
+
# Small helpers so every section prints a readable, labeled block.
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
def banner(title):
|
|
18
|
+
line = "=" * 78
|
|
19
|
+
print(f"\n{line}\n {title}\n{line}")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def kv(label, value):
|
|
23
|
+
"""Print a single labeled value."""
|
|
24
|
+
print(f" {label:<20}: {value}")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
################################################################################
|
|
28
|
+
### grid.simulate ###
|
|
29
|
+
"""
|
|
30
|
+
Runs the rigidity simulation on one set of node coordinates
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
coords : np.ndarray shape (n, d) [node coordinates, float64]
|
|
34
|
+
d : int [embedding dimension, must be 2 or 3]
|
|
35
|
+
tol : float [rank tolerance, optional(def=1e-9)]
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
"labels" np.ndarray[uint8] shape (n*(n-1)/2)
|
|
39
|
+
1 = independent (keep), 0 = redundant (skip)
|
|
40
|
+
|
|
41
|
+
"accepted_edges" list[(i, j)] list of kept edges
|
|
42
|
+
"distance_matrix" np.ndarray[float64] shape (n, n)
|
|
43
|
+
"final_rank" int
|
|
44
|
+
"max_rank" int nd - d(d+1)/2
|
|
45
|
+
"is_rigid" bool
|
|
46
|
+
"n_nodes" int
|
|
47
|
+
"d" int
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
banner("grid.simulate - rigidity simulation on a single triangle")
|
|
51
|
+
|
|
52
|
+
coords = np.array([[0, 0], [1, 0], [0.5, 0.866]], dtype=np.float64)
|
|
53
|
+
result = grid.simulate(coords, d=2)
|
|
54
|
+
result = grid.simulate(coords, d=2, tol=1e-6) # custom tolerance (overrides above)
|
|
55
|
+
|
|
56
|
+
kv("n_nodes", result["n_nodes"])
|
|
57
|
+
kv("d", result["d"])
|
|
58
|
+
kv("labels", result["labels"]) # 1 = independent (keep), 0 = redundant
|
|
59
|
+
kv("accepted_edges", result["accepted_edges"])
|
|
60
|
+
kv("final_rank", result["final_rank"])
|
|
61
|
+
kv("max_rank", result["max_rank"]) # nd - d(d+1)/2
|
|
62
|
+
kv("is_rigid", result["is_rigid"])
|
|
63
|
+
print(" distance_matrix:")
|
|
64
|
+
print(result["distance_matrix"])
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
################################################################################
|
|
68
|
+
### grid.generate_training_batch ###
|
|
69
|
+
"""
|
|
70
|
+
Generate many random graphs at once for GNN training data
|
|
71
|
+
All heavy work runs with GIL released so torch can train in parallel
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
n_graphs : int (how many graphs to generate)
|
|
75
|
+
n_nodes : int (nodes per graph)
|
|
76
|
+
d : int (embedding dimension)
|
|
77
|
+
seed : int (RNG seed (graph k gets seed+k, so the results are reproducible))
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
list[dict] (same dict as simulate(), one per graph)
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
banner("grid.generate_training_batch - batched random graphs for GNN data")
|
|
84
|
+
|
|
85
|
+
batch = grid.generate_training_batch(n_graphs=100, n_nodes=20, d=2, seed=42)
|
|
86
|
+
|
|
87
|
+
kv("graphs generated", len(batch))
|
|
88
|
+
|
|
89
|
+
# Inspect the first graph so we see the shape of a single sample.
|
|
90
|
+
first = batch[0]
|
|
91
|
+
kv("graph[0] labels shape", first["labels"].shape)
|
|
92
|
+
kv("graph[0] dist shape", first["distance_matrix"].shape)
|
|
93
|
+
kv("graph[0] is_rigid", first["is_rigid"])
|
|
94
|
+
print(" graph[0] labels:")
|
|
95
|
+
print(first["labels"])
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
################################################################################
|
|
99
|
+
### grid.gram_from_dist ###
|
|
100
|
+
"""
|
|
101
|
+
Compute the Gram matrix from a Euclidean distance matrix
|
|
102
|
+
We will use this to verify isometry such that G should be positive semi definite with rank < d
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
dist : np.ndarray shape(n, n) Euclidean distances
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
np.ndarray shape(n, n) (Gram matrix G = -1/2 H D^2 H)
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
banner("grid.gram_from_dist - Gram matrix + isometry (PSD) check")
|
|
112
|
+
|
|
113
|
+
gram = grid.gram_from_dist(result["distance_matrix"])
|
|
114
|
+
eigenvalues = np.linalg.eigvalsh(gram)
|
|
115
|
+
is_isometric = np.all(eigenvalues >= -1e-9)
|
|
116
|
+
|
|
117
|
+
print(" gram matrix:")
|
|
118
|
+
print(gram)
|
|
119
|
+
kv("eigenvalues", eigenvalues)
|
|
120
|
+
kv("is_isometric (PSD)", is_isometric) # True => valid Euclidean distance matrix
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
################################################################################
|
|
124
|
+
### grid.max_independent ###
|
|
125
|
+
"""
|
|
126
|
+
Returns the maximum number of independent edges for n nodes in d dimension
|
|
127
|
+
(nd - d(d+1)/2)
|
|
128
|
+
We are going to use this as the stopping condition or to pre-allocate label tensors.
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
banner("grid.max_independent - max independent edges = nd - d(d+1)/2")
|
|
132
|
+
|
|
133
|
+
kv("n=10, d=2", grid.max_independent(n=10, d=2))
|
|
134
|
+
kv("n=5, d=3", grid.max_independent(n=5, d=3))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
################################################################################
|
|
138
|
+
### grid.reconstruct ###
|
|
139
|
+
"""
|
|
140
|
+
Reconstructs the original data points from the given Euclidean distance matrix
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
banner("grid.reconstruct - recover coordinates from a distance matrix")
|
|
144
|
+
|
|
145
|
+
coords = np.array([[0, 0], [1, 0], [0.5, 0.866]], dtype=np.float64)
|
|
146
|
+
sim = grid.simulate(coords, d=2)
|
|
147
|
+
rec = grid.reconstruct(sim["distance_matrix"], d=2)
|
|
148
|
+
|
|
149
|
+
kv("stress", rec["stress"]) # should be ~0.0
|
|
150
|
+
kv("is_isometric", rec["is_isometric"]) # True
|
|
151
|
+
kv("eigenvalues", rec["eigenvalues"]) # top-2 eigenvalues of Gram matrix
|
|
152
|
+
print(" recovered coords:")
|
|
153
|
+
print(rec["coords"])
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|