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 +83 -0
- fastnsa/__init__.pyi +44 -0
- fastnsa/_selftest.py +62 -0
- fastnsa/bindings/__init__.py +1 -0
- fastnsa/bindings/_lib.py +63 -0
- fastnsa/bindings/capi.py +320 -0
- fastnsa/bindings/fastnsa.dll +0 -0
- fastnsa/core/__init__.py +1 -0
- fastnsa/core/events.py +276 -0
- fastnsa/core/network.py +370 -0
- fastnsa/core/types.py +620 -0
- fastnsa/datasets.py +70 -0
- fastnsa/enums.py +51 -0
- fastnsa/exceptions.py +24 -0
- fastnsa/io/__init__.py +1 -0
- fastnsa/io/network.py +63 -0
- fastnsa/io/points.py +148 -0
- fastnsa/io/results.py +62 -0
- fastnsa/pipeline/__init__.py +5 -0
- fastnsa/pipeline/preprocess.py +165 -0
- fastnsa/py.typed +1 -0
- fastnsa/runtime.py +455 -0
- fastnsa/stats/__init__.py +6 -0
- fastnsa/stats/k_function.py +526 -0
- fastnsa/stats/network_kde.py +230 -0
- fastnsa/utils/__init__.py +1 -0
- fastnsa-0.3.0.dist-info/METADATA +185 -0
- fastnsa-0.3.0.dist-info/RECORD +31 -0
- fastnsa-0.3.0.dist-info/WHEEL +5 -0
- fastnsa-0.3.0.dist-info/licenses/python/LICENSE +504 -0
- lib/fastnsa.lib +0 -0
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."""
|
fastnsa/bindings/_lib.py
ADDED
|
@@ -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
|
+
|
fastnsa/bindings/capi.py
ADDED
|
@@ -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
|
fastnsa/core/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Network, event, and typed analysis-result data models."""
|