fastnsa 0.3.0__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
fastnsa/__init__.py ADDED
@@ -0,0 +1,83 @@
1
+ """FastNSA public API with optional geospatial dependencies loaded lazily."""
2
+
3
+ from importlib import import_module
4
+ from importlib.metadata import PackageNotFoundError, version
5
+
6
+ try:
7
+ __version__ = version("fastnsa")
8
+ except PackageNotFoundError:
9
+ __version__ = "0.3.0.dev0"
10
+
11
+
12
+ _EXPORTS = {
13
+ "NativeNetwork": ("fastnsa.runtime", "NativeNetwork"),
14
+ "NativePointSet": ("fastnsa.runtime", "NativePointSet"),
15
+ "Network": ("fastnsa.core.network", "Network"),
16
+ "PointEvents": ("fastnsa.core.events", "PointEvents"),
17
+ "network_k_function": ("fastnsa.stats.k_function", "network_k_function"),
18
+ "spatiotemporal_network_k_function": (
19
+ "fastnsa.stats.k_function",
20
+ "spatiotemporal_network_k_function",
21
+ ),
22
+ "network_kde": ("fastnsa.stats.network_kde", "network_kde"),
23
+ "KFunctionResult": ("fastnsa.core.types", "KFunctionResult"),
24
+ "NetworkKDEPointResult": ("fastnsa.core.types", "NetworkKDEPointResult"),
25
+ "SpatiotemporalKFunctionResult": (
26
+ "fastnsa.core.types",
27
+ "SpatiotemporalKFunctionResult",
28
+ ),
29
+ "load_points": ("fastnsa.io.points", "load_points"),
30
+ "load_result": ("fastnsa.io.results", "load_result"),
31
+ "preprocess_events": ("fastnsa.pipeline.preprocess", "preprocess_events"),
32
+ "PreprocessResult": ("fastnsa.pipeline.preprocess", "PreprocessResult"),
33
+ "make_line_network": ("fastnsa.datasets", "make_line_network"),
34
+ "make_line_events": ("fastnsa.datasets", "make_line_events"),
35
+ "MappingMethod": ("fastnsa.enums", "MappingMethod"),
36
+ "KFunctionMethod": ("fastnsa.enums", "KFunctionMethod"),
37
+ "SpatiotemporalKFunctionMethod": ("fastnsa.enums", "SpatiotemporalKFunctionMethod"),
38
+ "NKDVMethod": ("fastnsa.enums", "NKDVMethod"),
39
+ "NKDVKernel": ("fastnsa.enums", "NKDVKernel"),
40
+ "FastNSAError": ("fastnsa.exceptions", "FastNSAError"),
41
+ "FastNSAValidationError": ("fastnsa.exceptions", "FastNSAValidationError"),
42
+ "NativeBackendError": ("fastnsa.exceptions", "NativeBackendError"),
43
+ "FastNSACancelledError": ("fastnsa.exceptions", "FastNSACancelledError"),
44
+ }
45
+
46
+
47
+ def __getattr__(name):
48
+ target = _EXPORTS.get(name)
49
+ if target is None:
50
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
51
+ module_name, attribute_name = target
52
+ value = getattr(import_module(module_name), attribute_name)
53
+ globals()[name] = value
54
+ return value
55
+
56
+ __all__ = [
57
+ "Network",
58
+ "PointEvents",
59
+ "NativeNetwork",
60
+ "NativePointSet",
61
+ "network_k_function",
62
+ "spatiotemporal_network_k_function",
63
+ "network_kde",
64
+ "KFunctionResult",
65
+ "NetworkKDEPointResult",
66
+ "SpatiotemporalKFunctionResult",
67
+ "load_points",
68
+ "load_result",
69
+ "preprocess_events",
70
+ "PreprocessResult",
71
+ "make_line_network",
72
+ "make_line_events",
73
+ "MappingMethod",
74
+ "KFunctionMethod",
75
+ "SpatiotemporalKFunctionMethod",
76
+ "NKDVMethod",
77
+ "NKDVKernel",
78
+ "FastNSAError",
79
+ "FastNSAValidationError",
80
+ "NativeBackendError",
81
+ "FastNSACancelledError",
82
+ "__version__",
83
+ ]
fastnsa/__init__.pyi ADDED
@@ -0,0 +1,44 @@
1
+
2
+ from .core.network import Network
3
+ from .core.events import PointEvents
4
+ from .runtime import NativeNetwork, NativePointSet
5
+ from .stats.k_function import network_k_function, spatiotemporal_network_k_function
6
+ from .stats.network_kde import network_kde
7
+ from .core.types import KFunctionResult, NetworkKDEPointResult, SpatiotemporalKFunctionResult
8
+ from .io.points import load_points
9
+ from .io.results import load_result
10
+ from .pipeline.preprocess import PreprocessResult, preprocess_events
11
+ from .datasets import make_line_events, make_line_network
12
+ from .enums import MappingMethod, KFunctionMethod, SpatiotemporalKFunctionMethod, NKDVMethod, NKDVKernel
13
+ from .exceptions import FastNSAError, FastNSAValidationError, NativeBackendError, FastNSACancelledError
14
+
15
+ __version__: str
16
+
17
+ __all__ = [
18
+ "Network",
19
+ "PointEvents",
20
+ "NativeNetwork",
21
+ "NativePointSet",
22
+ "network_k_function",
23
+ "spatiotemporal_network_k_function",
24
+ "network_kde",
25
+ "KFunctionResult",
26
+ "NetworkKDEPointResult",
27
+ "SpatiotemporalKFunctionResult",
28
+ "load_points",
29
+ "load_result",
30
+ "preprocess_events",
31
+ "PreprocessResult",
32
+ "make_line_network",
33
+ "make_line_events",
34
+ "MappingMethod",
35
+ "KFunctionMethod",
36
+ "SpatiotemporalKFunctionMethod",
37
+ "NKDVMethod",
38
+ "NKDVKernel",
39
+ "FastNSAError",
40
+ "FastNSAValidationError",
41
+ "NativeBackendError",
42
+ "FastNSACancelledError",
43
+ "__version__",
44
+ ]
fastnsa/_selftest.py ADDED
@@ -0,0 +1,62 @@
1
+ """Minimal installed-wheel diagnostic used by release automation."""
2
+
3
+ import struct
4
+
5
+ import numpy as np
6
+
7
+ from fastnsa.runtime import NativeNetwork, NativePointSet
8
+ from fastnsa.datasets import make_line_events, make_line_network
9
+ from fastnsa.stats.k_function import network_k_function
10
+ from fastnsa.stats.network_kde import network_kde
11
+
12
+
13
+ def main() -> None:
14
+ """Run mapping, K-function, NKDE, and sample-data installation checks.
15
+
16
+ The function is intentionally silent on success and raises ``RuntimeError``
17
+ when a native result is missing or numerically invalid. It is invoked by
18
+ ``python -m fastnsa._selftest`` in wheel release verification.
19
+ """
20
+ wkb = struct.pack("<BII4d", 1, 2, 2, 0.0, 0.0, 100.0, 0.0)
21
+ with NativeNetwork(
22
+ edges=np.array([[0, 1, 100.0]], dtype=np.float64),
23
+ offsets=np.array([0, 1, 2], dtype=np.int32),
24
+ indices=np.array([0, 0], dtype=np.int32),
25
+ wkb_blob=wkb,
26
+ wkb_offsets=np.array([0, len(wkb)], dtype=np.int32),
27
+ crs="EPSG:3857",
28
+ ) as network:
29
+ with NativePointSet.map_xy(
30
+ network, [10.0, 40.0, 80.0], [1.0, -1.0, 2.0]
31
+ ) as points:
32
+ mapped = points.offsets_array()
33
+ if not np.allclose(mapped, [10.0, 40.0, 80.0]):
34
+ raise RuntimeError(f"Unexpected nearest-edge offsets: {mapped!r}")
35
+ k_result = network_k_function(
36
+ network=network,
37
+ points=points,
38
+ r_values=np.array([10.0, 50.0]),
39
+ method="NS",
40
+ simulations=1,
41
+ random_state=1234,
42
+ )
43
+ if not np.isfinite(k_result.k_obs).all():
44
+ raise RuntimeError("K-function self-test returned non-finite values.")
45
+ kde_result = network_kde(
46
+ network=network,
47
+ points=points,
48
+ bandwidth=40.0,
49
+ lixel_length=20.0,
50
+ method="ADA",
51
+ )
52
+ if not np.isfinite(kde_result.density).all():
53
+ raise RuntimeError("NKDV self-test returned non-finite values.")
54
+
55
+ with make_line_network(100.0) as network:
56
+ with make_line_events(network) as points:
57
+ if points.n_points != 3:
58
+ raise RuntimeError("Built-in sample events are invalid.")
59
+
60
+
61
+ if __name__ == "__main__":
62
+ main()
@@ -0,0 +1 @@
1
+ """Internal native-library loading and ctypes ABI declarations."""
@@ -0,0 +1,63 @@
1
+ """Locate and load the platform-specific FastNSA shared library."""
2
+
3
+ import ctypes
4
+ import os
5
+ import platform
6
+ from pathlib import Path
7
+
8
+ __all__ = ['lib']
9
+
10
+ _dll_directory_handle = None
11
+
12
+
13
+ def _get_library_filename() -> str:
14
+ """
15
+ Return platform-specific shared library filename.
16
+ """
17
+ system = platform.system()
18
+
19
+ if system == "Linux":
20
+ return "libfastnsa.so"
21
+ elif system == "Darwin":
22
+ return "libfastnsa.dylib"
23
+ elif system == "Windows":
24
+ return "fastnsa.dll"
25
+ else:
26
+ raise RuntimeError(f"Unsupported platform: {system}")
27
+
28
+ def _load_library() -> ctypes.CDLL:
29
+ """
30
+ Load the fastnsa shared library from the same directory as this file.
31
+ """
32
+ global _dll_directory_handle
33
+
34
+ lib_name = _get_library_filename()
35
+ this_dir = Path(__file__).resolve().parent
36
+ override = os.environ.get("FASTNSA_LIBRARY_PATH")
37
+ lib_path = Path(override).expanduser().resolve() if override else this_dir / lib_name
38
+
39
+ if not lib_path.exists():
40
+ raise FileNotFoundError(
41
+ f"Cannot find {lib_name} in {this_dir}\n"
42
+ f"Expected path: {lib_path}\n"
43
+ "Install a wheel matching this operating system and CPU architecture, "
44
+ "or set FASTNSA_LIBRARY_PATH for a development build."
45
+ )
46
+
47
+ # Windows needs explicit DLL search path handling (Python >= 3.8)
48
+ if os.name == "nt":
49
+ _dll_directory_handle = os.add_dll_directory(str(lib_path.parent))
50
+
51
+ try:
52
+ return ctypes.CDLL(str(lib_path))
53
+ except OSError as e:
54
+ raise OSError(
55
+ f"Failed to load shared library: {lib_path}\n"
56
+ f"Platform: {platform.system()} {platform.machine()}\n"
57
+ f"Python architecture: {ctypes.sizeof(ctypes.c_void_p) * 8}-bit\n"
58
+ f"Original error: {e}"
59
+ ) from e
60
+
61
+
62
+ lib = _load_library()
63
+
@@ -0,0 +1,320 @@
1
+ """ctypes declarations for the stable FastNSA C ABI.
2
+
3
+ This module is internal. Public code should use :mod:`fastnsa.runtime` and the
4
+ analysis functions instead of calling these symbols directly.
5
+ """
6
+
7
+ from ._lib import lib
8
+ import ctypes
9
+
10
+ REQUIRED_ABI_VERSION = 2
11
+
12
+ FASTNSA_K_RQS = 1
13
+ FASTNSA_K_SPS = 2
14
+ FASTNSA_K_EAR = 3
15
+ FASTNSA_K_MTS = 4
16
+ FASTNSA_K_EARTH = 5
17
+ FASTNSA_K_NS = 6
18
+ FASTNSA_K_STARS = 7
19
+
20
+ FASTNSA_PLNNS_RTREE = 0
21
+ FASTNSA_PLNNS_COMP_APPROX = 1
22
+ FASTNSA_PLNNS_COMP_EXACT = 3
23
+
24
+ FASTNSA_NKDV_BASIC = 1
25
+ FASTNSA_NKDV_SHARED_SPD = 2
26
+ FASTNSA_NKDV_ADA = 3
27
+ FASTNSA_NKDV_IA = 4
28
+ FASTNSA_NKDV_ADA_IA = 5
29
+ FASTNSA_NKDV_LION = 6
30
+
31
+ FASTNSA_NKDV_KERNEL_GAUSSIAN = 0
32
+ FASTNSA_NKDV_KERNEL_TRIANGULAR = 1
33
+ FASTNSA_NKDV_KERNEL_EPANECHNIKOV = 2
34
+ FASTNSA_NKDV_KERNEL_QUARTIC = 3
35
+
36
+ P_DOUBLE = ctypes.POINTER(ctypes.c_double)
37
+ P_INT = ctypes.POINTER(ctypes.c_int)
38
+ VOID_P = ctypes.c_void_p
39
+ P_UINT8 = ctypes.POINTER(ctypes.c_uint8)
40
+ PROGRESS_CALLBACK = ctypes.CFUNCTYPE(
41
+ ctypes.c_int,
42
+ ctypes.c_char_p,
43
+ ctypes.c_int,
44
+ ctypes.c_int,
45
+ ctypes.c_void_p,
46
+ )
47
+
48
+
49
+ try:
50
+ _abi_version = lib.fastnsa_abi_version
51
+ except AttributeError as exc:
52
+ raise ImportError(
53
+ "The FastNSA native library does not expose fastnsa_abi_version; "
54
+ "reinstall the Python package and its matching native wheel."
55
+ ) from exc
56
+
57
+ _abi_version.argtypes = []
58
+ _abi_version.restype = ctypes.c_int
59
+ NATIVE_ABI_VERSION = int(_abi_version())
60
+ if NATIVE_ABI_VERSION != REQUIRED_ABI_VERSION:
61
+ raise ImportError(
62
+ "Incompatible FastNSA native library ABI: "
63
+ f"expected {REQUIRED_ABI_VERSION}, found {NATIVE_ABI_VERSION}. "
64
+ "Reinstall the Python package and remove stale libfastnsa binaries."
65
+ )
66
+
67
+ _REQUIRED_SYMBOLS = (
68
+ "fastnsa_last_error",
69
+ "fastnsa_network_create",
70
+ "fastnsa_network_destroy",
71
+ "fastnsa_network_set_wkbs_checked",
72
+ "fastnsa_network_set_polylines",
73
+ "fastnsa_pointset_create",
74
+ "fastnsa_pointset_destroy",
75
+ "fastnsa_pointset_set",
76
+ "fastnsa_pointset_set_times",
77
+ "fastnsa_pointset_size",
78
+ "fastnsa_pointset_copy_edge_ids",
79
+ "fastnsa_pointset_copy_offsets",
80
+ "fastnsa_pointset_copy_times",
81
+ "fastnsa_map_points",
82
+ "fastnsa_pointset_dump_text",
83
+ "fastnsa_pointset_dump_text_st",
84
+ "fastnsa_compute_k_function_checked",
85
+ "fastnsa_compute_k_function_with_progress",
86
+ "fastnsa_compute_spatiotemporal_k_function_checked",
87
+ "fastnsa_compute_spatiotemporal_k_function_with_progress",
88
+ "fastnsa_nkdv_count_lixels",
89
+ "fastnsa_compute_nkdv",
90
+ "fastnsa_compute_nkdv_with_progress",
91
+ )
92
+ _missing_symbols = [name for name in _REQUIRED_SYMBOLS if not hasattr(lib, name)]
93
+ if _missing_symbols:
94
+ raise ImportError(
95
+ "The FastNSA native library is incomplete for ABI "
96
+ f"{REQUIRED_ABI_VERSION}; missing: {', '.join(_missing_symbols)}."
97
+ )
98
+
99
+ if hasattr(lib, "fastnsa_last_error"):
100
+ lib.fastnsa_last_error.argtypes = []
101
+ lib.fastnsa_last_error.restype = ctypes.c_char_p
102
+
103
+
104
+ def last_error() -> str:
105
+ """Return the latest native error for the current thread."""
106
+ if not hasattr(lib, "fastnsa_last_error"):
107
+ return "Native FastNSA operation failed."
108
+ message = lib.fastnsa_last_error()
109
+ return message.decode("utf-8", errors="replace") if message else "Native FastNSA operation failed."
110
+
111
+
112
+ # Network lifetime and packed-geometry bindings. Keep these declarations in
113
+ # lockstep with cpp/bindings/fastnsa_capi.h; ctypes cannot validate ABI types.
114
+ lib.fastnsa_network_create.argtypes = [
115
+ P_DOUBLE,
116
+ ctypes.c_int,
117
+ P_INT,
118
+ P_INT,
119
+ ctypes.c_int
120
+ ]
121
+ lib.fastnsa_network_create.restype = VOID_P
122
+
123
+ lib.fastnsa_network_destroy.argtypes = [VOID_P]
124
+ lib.fastnsa_network_destroy.restype = None
125
+
126
+ # WKB offsets contain n_edges + 1 entries and delimit a packed byte buffer.
127
+ lib.fastnsa_network_set_wkbs.argtypes = [VOID_P, P_UINT8, P_INT, ctypes.c_int]
128
+ lib.fastnsa_network_set_wkbs.restype = None
129
+
130
+ lib.fastnsa_network_set_polylines.argtypes = [VOID_P, P_DOUBLE, P_INT, ctypes.c_int]
131
+ lib.fastnsa_network_set_polylines.restype = ctypes.c_int
132
+
133
+ HAS_CHECKED_WKB_SETTER = hasattr(lib, "fastnsa_network_set_wkbs_checked")
134
+ if HAS_CHECKED_WKB_SETTER:
135
+ lib.fastnsa_network_set_wkbs_checked.argtypes = list(
136
+ lib.fastnsa_network_set_wkbs.argtypes
137
+ )
138
+ lib.fastnsa_network_set_wkbs_checked.restype = ctypes.c_int
139
+
140
+
141
+ # Point sets borrow their network pointer; Python wrappers keep the network
142
+ # alive and require point sets to be destroyed first.
143
+ lib.fastnsa_pointset_create.argtypes = [VOID_P]
144
+ lib.fastnsa_pointset_create.restype = VOID_P
145
+
146
+ lib.fastnsa_pointset_destroy.argtypes = [VOID_P]
147
+ lib.fastnsa_pointset_destroy.restype = None
148
+
149
+ # Populate native events from contiguous edge-ID, offset, and optional time
150
+ # arrays. Functions return zero on success unless their declaration says void.
151
+ lib.fastnsa_pointset_set.argtypes = [VOID_P, P_INT, P_DOUBLE, ctypes.c_int]
152
+ lib.fastnsa_pointset_set.restype = ctypes.c_int
153
+ lib.fastnsa_pointset_set_st.argtypes = [VOID_P, P_INT, P_DOUBLE, P_DOUBLE, ctypes.c_int]
154
+ lib.fastnsa_pointset_set_st.restype = ctypes.c_int
155
+ lib.fastnsa_pointset_set_times.argtypes = [VOID_P, P_DOUBLE, ctypes.c_int]
156
+ lib.fastnsa_pointset_set_times.restype = ctypes.c_int
157
+ lib.fastnsa_pointset_size.argtypes = [VOID_P]
158
+ lib.fastnsa_pointset_size.restype = ctypes.c_int
159
+ lib.fastnsa_pointset_copy_edge_ids.argtypes = [VOID_P, P_INT, ctypes.c_int]
160
+ lib.fastnsa_pointset_copy_edge_ids.restype = ctypes.c_int
161
+ lib.fastnsa_pointset_copy_offsets.argtypes = [VOID_P, P_DOUBLE, ctypes.c_int]
162
+ lib.fastnsa_pointset_copy_offsets.restype = ctypes.c_int
163
+ lib.fastnsa_pointset_copy_times.argtypes = [VOID_P, P_DOUBLE, ctypes.c_int]
164
+ lib.fastnsa_pointset_copy_times.restype = ctypes.c_int
165
+
166
+
167
+ lib.fastnsa_map_points.argtypes = [
168
+ ctypes.c_void_p, # network pointer
169
+ P_DOUBLE,
170
+ P_DOUBLE,
171
+ ctypes.c_int, # point count
172
+ ctypes.c_int, # mapping method enum
173
+ ctypes.c_double, # approximation epsilon
174
+ ctypes.c_int, # requested worker count
175
+ ]
176
+ lib.fastnsa_map_points.restype = VOID_P
177
+
178
+ lib.fastnsa_pointset_dump_text.restype = ctypes.c_int
179
+ lib.fastnsa_pointset_dump_text.argtypes = [VOID_P, ctypes.c_char_p]
180
+ lib.fastnsa_pointset_dump_text_st.restype = ctypes.c_int
181
+ lib.fastnsa_pointset_dump_text_st.argtypes = [VOID_P, ctypes.c_char_p]
182
+
183
+
184
+
185
+ # Base K-function entry points predate checked/progress/seeded variants and
186
+ # return void. Public wrappers prefer the checked variants when available.
187
+ lib.fastnsa_compute_k_function.argtypes = [
188
+ VOID_P, # network pointer
189
+ VOID_P, # point-set pointer
190
+ P_DOUBLE, # distance thresholds
191
+ ctypes.c_int, # threshold count
192
+ ctypes.c_int, # method enum
193
+ ctypes.c_int, # simulation count
194
+ P_DOUBLE, # observed output
195
+ P_DOUBLE, # optional simulation output
196
+ ctypes.c_double, # approximate-method tolerance
197
+ ]
198
+ lib.fastnsa_compute_k_function.restype = None
199
+
200
+ HAS_CHECKED_K_FUNCTION = hasattr(lib, "fastnsa_compute_k_function_checked")
201
+ if HAS_CHECKED_K_FUNCTION:
202
+ lib.fastnsa_compute_k_function_checked.argtypes = list(lib.fastnsa_compute_k_function.argtypes)
203
+ lib.fastnsa_compute_k_function_checked.restype = ctypes.c_int
204
+
205
+ HAS_PROGRESS_K_FUNCTION = hasattr(lib, "fastnsa_compute_k_function_with_progress")
206
+ if HAS_PROGRESS_K_FUNCTION:
207
+ lib.fastnsa_compute_k_function_with_progress.argtypes = list(
208
+ lib.fastnsa_compute_k_function.argtypes
209
+ ) + [PROGRESS_CALLBACK, VOID_P]
210
+ lib.fastnsa_compute_k_function_with_progress.restype = ctypes.c_int
211
+
212
+ HAS_SEEDED_K_FUNCTION = hasattr(lib, "fastnsa_compute_k_function_seeded")
213
+ if HAS_SEEDED_K_FUNCTION:
214
+ lib.fastnsa_compute_k_function_seeded.argtypes = list(
215
+ lib.fastnsa_compute_k_function.argtypes
216
+ ) + [ctypes.c_uint32, PROGRESS_CALLBACK, VOID_P]
217
+ lib.fastnsa_compute_k_function_seeded.restype = ctypes.c_int
218
+
219
+ lib.fastnsa_compute_spatiotemporal_k_function.argtypes = [
220
+ VOID_P, # network_ptr
221
+ VOID_P, # point_set_ptr
222
+ P_DOUBLE, # s_values
223
+ ctypes.c_int, # n_s
224
+ P_DOUBLE, # t_values
225
+ ctypes.c_int, # n_t
226
+ ctypes.c_int, # method
227
+ ctypes.c_int, # n_simulations
228
+ P_DOUBLE, # out k_obs
229
+ P_DOUBLE, # out k_sim
230
+ ]
231
+ lib.fastnsa_compute_spatiotemporal_k_function.restype = None
232
+
233
+ HAS_CHECKED_ST_K_FUNCTION = hasattr(
234
+ lib,
235
+ "fastnsa_compute_spatiotemporal_k_function_checked",
236
+ )
237
+ if HAS_CHECKED_ST_K_FUNCTION:
238
+ lib.fastnsa_compute_spatiotemporal_k_function_checked.argtypes = list(
239
+ lib.fastnsa_compute_spatiotemporal_k_function.argtypes
240
+ )
241
+ lib.fastnsa_compute_spatiotemporal_k_function_checked.restype = ctypes.c_int
242
+
243
+ HAS_PROGRESS_ST_K_FUNCTION = hasattr(
244
+ lib, "fastnsa_compute_spatiotemporal_k_function_with_progress"
245
+ )
246
+ if HAS_PROGRESS_ST_K_FUNCTION:
247
+ lib.fastnsa_compute_spatiotemporal_k_function_with_progress.argtypes = list(
248
+ lib.fastnsa_compute_spatiotemporal_k_function.argtypes
249
+ ) + [PROGRESS_CALLBACK, VOID_P]
250
+ lib.fastnsa_compute_spatiotemporal_k_function_with_progress.restype = ctypes.c_int
251
+
252
+ HAS_SEEDED_ST_K_FUNCTION = hasattr(
253
+ lib, "fastnsa_compute_spatiotemporal_k_function_seeded"
254
+ )
255
+ if HAS_SEEDED_ST_K_FUNCTION:
256
+ lib.fastnsa_compute_spatiotemporal_k_function_seeded.argtypes = list(
257
+ lib.fastnsa_compute_spatiotemporal_k_function.argtypes
258
+ ) + [ctypes.c_uint32, PROGRESS_CALLBACK, VOID_P]
259
+ lib.fastnsa_compute_spatiotemporal_k_function_seeded.restype = ctypes.c_int
260
+
261
+ lib.fastnsa_nkdv_count_lixels.argtypes = [
262
+ VOID_P,
263
+ ctypes.c_double,
264
+ ]
265
+ lib.fastnsa_nkdv_count_lixels.restype = ctypes.c_int
266
+
267
+ lib.fastnsa_compute_nkdv.argtypes = [
268
+ VOID_P,
269
+ VOID_P,
270
+ ctypes.c_int,
271
+ ctypes.c_double,
272
+ ctypes.c_int,
273
+ ctypes.c_double,
274
+ ctypes.c_int,
275
+ P_INT,
276
+ P_DOUBLE,
277
+ P_DOUBLE,
278
+ P_DOUBLE,
279
+ ]
280
+ lib.fastnsa_compute_nkdv.restype = ctypes.c_int
281
+
282
+ HAS_PROGRESS_NKDV = hasattr(lib, "fastnsa_compute_nkdv_with_progress")
283
+ if HAS_PROGRESS_NKDV:
284
+ lib.fastnsa_compute_nkdv_with_progress.argtypes = list(
285
+ lib.fastnsa_compute_nkdv.argtypes
286
+ ) + [PROGRESS_CALLBACK, VOID_P]
287
+ lib.fastnsa_compute_nkdv_with_progress.restype = ctypes.c_int
288
+
289
+ HAS_WEIGHTED_NKDV = hasattr(lib, "fastnsa_compute_nkdv_weighted")
290
+ if HAS_WEIGHTED_NKDV:
291
+ lib.fastnsa_compute_nkdv_weighted.argtypes = [
292
+ VOID_P, VOID_P, P_DOUBLE, ctypes.c_int,
293
+ ctypes.c_int, ctypes.c_double, ctypes.c_int, ctypes.c_double,
294
+ ctypes.c_int, P_INT, P_DOUBLE, P_DOUBLE, P_DOUBLE,
295
+ PROGRESS_CALLBACK, VOID_P,
296
+ ]
297
+ lib.fastnsa_compute_nkdv_weighted.restype = ctypes.c_int
298
+
299
+
300
+ def make_progress_callback(callback):
301
+ """Wrap a Python progress/cancel callable for the native ABI.
302
+
303
+ The Python callable receives ``(stage, completed, total)`` and should return
304
+ a truthy value to request cancellation. Exceptions cannot cross the C ABI;
305
+ an exception raised by the callable is therefore converted to a cancellation
306
+ request. The returned ctypes callback must remain alive for the complete
307
+ native call.
308
+ """
309
+ if callback is None:
310
+ return None
311
+
312
+ def bridge(stage, completed, total, _user_data):
313
+ try:
314
+ stage_text = stage.decode("utf-8", errors="replace") if stage else "backend compute"
315
+ return int(bool(callback(stage_text, int(completed), int(total))))
316
+ except Exception:
317
+ # Never allow Python exceptions to cross the C callback boundary.
318
+ return 1
319
+
320
+ return PROGRESS_CALLBACK(bridge)
Binary file
@@ -0,0 +1 @@
1
+ """Network, event, and typed analysis-result data models."""