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.
@@ -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
+ # Default ignored files
2
+ /shelf/
3
+ /workspace.xml
4
+ # Editor-based HTTP Client requests
5
+ /httpRequests/
6
+ # Datasource local storage ignored files
7
+ /dataSources/
8
+ /dataSources.local.xml
@@ -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,6 @@
1
+ <component name="InspectionProjectProfileManager">
2
+ <settings>
3
+ <option name="USE_PROJECT_PROFILE" value="false" />
4
+ <version value="1.0" />
5
+ </settings>
6
+ </component>
@@ -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,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/GRiD.iml" filepath="$PROJECT_DIR$/.idea/GRiD.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="" vcs="Git" />
5
+ </component>
6
+ </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,5 @@
1
+ Metadata-Version: 2.4
2
+ Name: grid-simulate
3
+ Version: 0.1.0
4
+ Summary: Rust + PyO3 simulation library
5
+ Requires-Python: >=3.8
@@ -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
+