klongpy 0.6.9__py3-none-any.whl → 0.7.1__py3-none-any.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.
- klongpy/__init__.py +17 -1
- klongpy/adverbs.py +84 -82
- klongpy/autograd.py +299 -0
- klongpy/backend.py +38 -103
- klongpy/backends/__init__.py +26 -0
- klongpy/backends/base.py +469 -0
- klongpy/backends/numpy_backend.py +123 -0
- klongpy/backends/registry.py +76 -0
- klongpy/backends/torch_backend.py +1047 -0
- klongpy-0.6.9.data/scripts/kgpy → klongpy/cli.py +110 -90
- klongpy/core.py +113 -974
- klongpy/db/sys_fn_db.py +7 -6
- klongpy/db/sys_fn_kvs.py +2 -4
- klongpy/dyads.py +332 -160
- klongpy/interpreter.py +60 -15
- klongpy/monads.py +121 -75
- klongpy/parser.py +328 -0
- klongpy/repl.py +23 -5
- klongpy/sys_fn.py +170 -21
- klongpy/sys_fn_autograd.py +290 -0
- klongpy/sys_fn_ipc.py +22 -15
- klongpy/sys_fn_timer.py +13 -3
- klongpy/types.py +503 -0
- klongpy/web/sys_fn_web.py +14 -4
- klongpy/writer.py +122 -0
- klongpy/ws/sys_fn_ws.py +5 -8
- klongpy-0.7.1.dist-info/METADATA +544 -0
- klongpy-0.7.1.dist-info/RECORD +52 -0
- {klongpy-0.6.9.dist-info → klongpy-0.7.1.dist-info}/WHEEL +1 -1
- klongpy-0.7.1.dist-info/entry_points.txt +2 -0
- {klongpy-0.6.9.dist-info → klongpy-0.7.1.dist-info}/top_level.txt +0 -1
- klongpy-0.6.9.dist-info/METADATA +0 -448
- klongpy-0.6.9.dist-info/RECORD +0 -77
- tests/__init__.py +0 -6
- tests/gen_join_over.py +0 -119
- tests/gen_py_suite.py +0 -77
- tests/gen_test_fn.py +0 -259
- tests/perf_async.py +0 -25
- tests/perf_avg.py +0 -18
- tests/perf_duckdb.py +0 -32
- tests/perf_gen.py +0 -38
- tests/perf_ipc_overhead.py +0 -34
- tests/perf_join.py +0 -53
- tests/perf_load.py +0 -17
- tests/perf_prog.py +0 -18
- tests/perf_serdes.py +0 -52
- tests/perf_sys_fn_db.py +0 -263
- tests/perf_vector.py +0 -40
- tests/test_accel.py +0 -227
- tests/test_df_cache.py +0 -85
- tests/test_eval_monad_list.py +0 -34
- tests/test_examples.py +0 -64
- tests/test_extra_suite.py +0 -382
- tests/test_file_cache.py +0 -185
- tests/test_interop.py +0 -180
- tests/test_kg_asarray.py +0 -94
- tests/test_kgtests.py +0 -65
- tests/test_known_bugs.py +0 -206
- tests/test_prog.py +0 -107
- tests/test_reshape_strings.py +0 -33
- tests/test_suite.py +0 -1480
- tests/test_suite_file.py +0 -153
- tests/test_sys_fn.py +0 -420
- tests/test_sys_fn_db.py +0 -88
- tests/test_sys_fn_ipc.py +0 -587
- tests/test_sys_fn_timer.py +0 -133
- tests/test_sys_fn_web.py +0 -50
- tests/test_util.py +0 -233
- tests/utils.py +0 -126
- {klongpy-0.6.9.dist-info → klongpy-0.7.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""
|
|
2
|
+
NumPy backend provider for KlongPy.
|
|
3
|
+
|
|
4
|
+
This is the default backend that supports all Klong operations including
|
|
5
|
+
string manipulation and object dtype arrays.
|
|
6
|
+
"""
|
|
7
|
+
import warnings
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
from .base import BackendProvider
|
|
11
|
+
|
|
12
|
+
# numpy 2.x moved VisibleDeprecationWarning to numpy.exceptions
|
|
13
|
+
from numpy.exceptions import VisibleDeprecationWarning as NumpyVisibleDeprecationWarning
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class KGChar(str):
|
|
17
|
+
"""Character type for Klong."""
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class NumpyBackendProvider(BackendProvider):
|
|
22
|
+
"""NumPy-based backend provider."""
|
|
23
|
+
|
|
24
|
+
def __init__(self, device=None):
|
|
25
|
+
if device is not None:
|
|
26
|
+
raise ValueError("Backend 'numpy' does not support device selection")
|
|
27
|
+
self._np = np
|
|
28
|
+
np.seterr(divide='ignore')
|
|
29
|
+
warnings.filterwarnings("error", category=NumpyVisibleDeprecationWarning)
|
|
30
|
+
# Add isarray method to numpy module reference
|
|
31
|
+
self._np.isarray = lambda x: isinstance(x, np.ndarray)
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def name(self) -> str:
|
|
35
|
+
return 'numpy'
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def np(self):
|
|
39
|
+
return self._np
|
|
40
|
+
|
|
41
|
+
def supports_object_dtype(self) -> bool:
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
def supports_strings(self) -> bool:
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
def supports_float64(self) -> bool:
|
|
48
|
+
return True
|
|
49
|
+
|
|
50
|
+
def is_array(self, x) -> bool:
|
|
51
|
+
return isinstance(x, np.ndarray)
|
|
52
|
+
|
|
53
|
+
def is_backend_array(self, x) -> bool:
|
|
54
|
+
return False # numpy arrays are the base case, not a "backend" type
|
|
55
|
+
|
|
56
|
+
def get_dtype_kind(self, arr) -> str:
|
|
57
|
+
if hasattr(arr, 'dtype') and hasattr(arr.dtype, 'kind'):
|
|
58
|
+
return arr.dtype.kind
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
def to_numpy(self, x):
|
|
62
|
+
# Already numpy, just return as-is
|
|
63
|
+
return x
|
|
64
|
+
|
|
65
|
+
def is_scalar_integer(self, x) -> bool:
|
|
66
|
+
if isinstance(x, np.ndarray) and x.ndim == 0:
|
|
67
|
+
return np.issubdtype(x.dtype, np.integer)
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
def is_scalar_float(self, x) -> bool:
|
|
71
|
+
if isinstance(x, np.ndarray) and x.ndim == 0:
|
|
72
|
+
return np.issubdtype(x.dtype, np.floating)
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
def argsort(self, a, descending=False):
|
|
76
|
+
"""Return indices that would sort the array."""
|
|
77
|
+
indices = np.argsort(a)
|
|
78
|
+
if descending:
|
|
79
|
+
indices = indices[::-1].copy()
|
|
80
|
+
return indices
|
|
81
|
+
|
|
82
|
+
def array_size(self, a):
|
|
83
|
+
"""Get the total number of elements in an array."""
|
|
84
|
+
if hasattr(a, 'size'):
|
|
85
|
+
return a.size
|
|
86
|
+
return len(a) if hasattr(a, '__len__') else 1
|
|
87
|
+
|
|
88
|
+
def safe_equal(self, x, y):
|
|
89
|
+
"""Compare two values for equality."""
|
|
90
|
+
return np.asarray(x, dtype=object) == np.asarray(y, dtype=object)
|
|
91
|
+
|
|
92
|
+
def to_int_array(self, a):
|
|
93
|
+
"""Convert array to integer type."""
|
|
94
|
+
return np.asarray(a, dtype=int) if self.is_array(a) else int(a)
|
|
95
|
+
|
|
96
|
+
def power(self, a, b):
|
|
97
|
+
"""Compute a^b, returning integer if result is whole number."""
|
|
98
|
+
r = np.power(float(a) if isinstance(a, (int, np.integer)) else a, b)
|
|
99
|
+
return r
|
|
100
|
+
|
|
101
|
+
def str_to_char_array(self, s):
|
|
102
|
+
"""Convert string to character array."""
|
|
103
|
+
return self._np.asarray([KGChar(x) for x in s], dtype=object)
|
|
104
|
+
|
|
105
|
+
def kg_asarray(self, a):
|
|
106
|
+
"""Convert input to numpy array, handling strings and jagged/nested data."""
|
|
107
|
+
if isinstance(a, str):
|
|
108
|
+
return self.str_to_char_array(a)
|
|
109
|
+
try:
|
|
110
|
+
arr = self._np.asarray(a)
|
|
111
|
+
if arr.dtype.kind not in ['O', 'i', 'f']:
|
|
112
|
+
raise ValueError
|
|
113
|
+
except (NumpyVisibleDeprecationWarning, ValueError):
|
|
114
|
+
try:
|
|
115
|
+
arr = self._np.asarray(a, dtype=object)
|
|
116
|
+
except ValueError:
|
|
117
|
+
arr = [x.tolist() if self.is_array(x) else x for x in a]
|
|
118
|
+
arr = self._np.asarray(arr, dtype=object)
|
|
119
|
+
arr = self._np.asarray(
|
|
120
|
+
[self.kg_asarray(x) if isinstance(x, list) else x for x in arr],
|
|
121
|
+
dtype=object
|
|
122
|
+
)
|
|
123
|
+
return arr
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Backend registry for KlongPy.
|
|
3
|
+
|
|
4
|
+
Owns backend registration, lookup, and lazy torch loading.
|
|
5
|
+
"""
|
|
6
|
+
import importlib
|
|
7
|
+
import importlib.util
|
|
8
|
+
|
|
9
|
+
from .base import BackendProvider
|
|
10
|
+
from .numpy_backend import NumpyBackendProvider
|
|
11
|
+
|
|
12
|
+
# Registry of available backends
|
|
13
|
+
_BACKENDS = {}
|
|
14
|
+
|
|
15
|
+
# Default backend name
|
|
16
|
+
_DEFAULT_BACKEND = 'numpy'
|
|
17
|
+
|
|
18
|
+
_TORCH_AVAILABLE = importlib.util.find_spec("torch") is not None
|
|
19
|
+
_TORCH_BACKEND_LOADED = False
|
|
20
|
+
TorchBackendProvider = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def register_backend(name: str, provider_class):
|
|
24
|
+
"""Register a backend provider class."""
|
|
25
|
+
_BACKENDS[name] = provider_class
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _load_torch_backend():
|
|
29
|
+
global _TORCH_BACKEND_LOADED, TorchBackendProvider
|
|
30
|
+
if _TORCH_BACKEND_LOADED or not _TORCH_AVAILABLE:
|
|
31
|
+
return
|
|
32
|
+
_torch_backend = importlib.import_module("klongpy.backends.torch_backend")
|
|
33
|
+
TorchBackendProvider = _torch_backend.TorchBackendProvider
|
|
34
|
+
register_backend('torch', TorchBackendProvider)
|
|
35
|
+
_TORCH_BACKEND_LOADED = True
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_backend(name: str = None, **kwargs) -> BackendProvider:
|
|
39
|
+
"""
|
|
40
|
+
Get a backend provider instance.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
name : str, optional
|
|
45
|
+
Backend name ('numpy' or 'torch'). If None, uses default.
|
|
46
|
+
**kwargs
|
|
47
|
+
Additional arguments passed to the backend provider constructor.
|
|
48
|
+
|
|
49
|
+
Returns
|
|
50
|
+
-------
|
|
51
|
+
BackendProvider
|
|
52
|
+
The backend provider instance.
|
|
53
|
+
"""
|
|
54
|
+
if name is None:
|
|
55
|
+
name = _DEFAULT_BACKEND
|
|
56
|
+
|
|
57
|
+
if name == 'torch':
|
|
58
|
+
_load_torch_backend()
|
|
59
|
+
|
|
60
|
+
if name not in _BACKENDS:
|
|
61
|
+
available = ', '.join(_BACKENDS.keys())
|
|
62
|
+
raise ValueError(f"Unknown backend: '{name}'. Available: {available}")
|
|
63
|
+
|
|
64
|
+
return _BACKENDS[name](**kwargs)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def list_backends():
|
|
68
|
+
"""Return list of available backend names."""
|
|
69
|
+
backends = list(_BACKENDS.keys())
|
|
70
|
+
if _TORCH_AVAILABLE and 'torch' not in backends:
|
|
71
|
+
backends.append('torch')
|
|
72
|
+
return backends
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# Register built-in backends
|
|
76
|
+
register_backend('numpy', NumpyBackendProvider)
|