jjinx 0.0.1__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.
- jjinx-0.0.1/LICENSE +21 -0
- jjinx-0.0.1/PKG-INFO +148 -0
- jjinx-0.0.1/README.md +106 -0
- jjinx-0.0.1/pyproject.toml +49 -0
- jjinx-0.0.1/setup.cfg +4 -0
- jjinx-0.0.1/src/jinx/__init__.py +0 -0
- jjinx-0.0.1/src/jinx/errors.py +41 -0
- jjinx-0.0.1/src/jinx/execution/executor.py +60 -0
- jjinx-0.0.1/src/jinx/execution/jax/__init__.py +45 -0
- jjinx-0.0.1/src/jinx/execution/jax/adverbs.py +91 -0
- jjinx-0.0.1/src/jinx/execution/jax/application.py +231 -0
- jjinx-0.0.1/src/jinx/execution/jax/verbs.py +90 -0
- jjinx-0.0.1/src/jinx/execution/numpy/__init__.py +29 -0
- jjinx-0.0.1/src/jinx/execution/numpy/adverbs.py +334 -0
- jjinx-0.0.1/src/jinx/execution/numpy/application.py +343 -0
- jjinx-0.0.1/src/jinx/execution/numpy/conjunctions.py +437 -0
- jjinx-0.0.1/src/jinx/execution/numpy/conversion.py +62 -0
- jjinx-0.0.1/src/jinx/execution/numpy/helpers.py +158 -0
- jjinx-0.0.1/src/jinx/execution/numpy/printing.py +179 -0
- jjinx-0.0.1/src/jinx/execution/numpy/verbs.py +850 -0
- jjinx-0.0.1/src/jinx/primitives.py +490 -0
- jjinx-0.0.1/src/jinx/shell.py +68 -0
- jjinx-0.0.1/src/jinx/vocabulary.py +181 -0
- jjinx-0.0.1/src/jinx/word_evaluation.py +375 -0
- jjinx-0.0.1/src/jinx/word_formation.py +229 -0
- jjinx-0.0.1/src/jinx/word_spelling.py +118 -0
- jjinx-0.0.1/src/jjinx.egg-info/PKG-INFO +148 -0
- jjinx-0.0.1/src/jjinx.egg-info/SOURCES.txt +33 -0
- jjinx-0.0.1/src/jjinx.egg-info/dependency_links.txt +1 -0
- jjinx-0.0.1/src/jjinx.egg-info/entry_points.txt +2 -0
- jjinx-0.0.1/src/jjinx.egg-info/requires.txt +1 -0
- jjinx-0.0.1/src/jjinx.egg-info/top_level.txt +1 -0
- jjinx-0.0.1/tests/test_word_evaluation.py +993 -0
- jjinx-0.0.1/tests/test_word_formation.py +142 -0
- jjinx-0.0.1/tests/test_word_spelling.py +54 -0
jjinx-0.0.1/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Alex Riley
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
jjinx-0.0.1/PKG-INFO
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: jjinx
|
3
|
+
Version: 0.0.1
|
4
|
+
Summary: Interpreter for the J programming language.
|
5
|
+
Author: Alex Riley
|
6
|
+
License: MIT License
|
7
|
+
|
8
|
+
Copyright (c) 2025 Alex Riley
|
9
|
+
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
12
|
+
in the Software without restriction, including without limitation the rights
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
15
|
+
furnished to do so, subject to the following conditions:
|
16
|
+
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
18
|
+
copies or substantial portions of the Software.
|
19
|
+
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
26
|
+
SOFTWARE.
|
27
|
+
|
28
|
+
Project-URL: Homepage, https://github.com/ajcr/jinx
|
29
|
+
Keywords: J,interpreter
|
30
|
+
Classifier: Development Status :: 3 - Alpha
|
31
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
32
|
+
Classifier: Topic :: Utilities
|
33
|
+
Classifier: Typing :: Typed
|
34
|
+
Classifier: Intended Audience :: Science/Research
|
35
|
+
Classifier: License :: OSI Approved :: MIT License
|
36
|
+
Classifier: Programming Language :: Python :: 3.13
|
37
|
+
Requires-Python: >=3.13
|
38
|
+
Description-Content-Type: text/markdown
|
39
|
+
License-File: LICENSE
|
40
|
+
Requires-Dist: numpy>=2.3.3
|
41
|
+
Dynamic: license-file
|
42
|
+
|
43
|
+
# Jinx
|
44
|
+
|
45
|
+

|
46
|
+
|
47
|
+
An experimental interpreter for the J programming language, built on top of [NumPy](https://numpy.org/).
|
48
|
+
|
49
|
+
Implements many of J's primitives and tacit programming capabilities, and can be extended to support execution via other frameworks too.
|
50
|
+
|
51
|
+
## Executing J
|
52
|
+
|
53
|
+
Start the interactive shell:
|
54
|
+
```sh
|
55
|
+
jinx
|
56
|
+
```
|
57
|
+
The shell prompt is four spaces, so commands appear indented. Internally, all multidimensional arrays are NumPy arrays. Verbs, conjunctions and adverbs are a mixture of Python and NumPy methods.
|
58
|
+
|
59
|
+
Here are some examples what Jinx can do so far:
|
60
|
+
|
61
|
+
- Solve the "trapping rainwater" problem (solution taken from [here](https://mmapped.blog/posts/04-square-joy-trapped-rain-water)):
|
62
|
+
```j
|
63
|
+
+/@((>./\ <. >./\.)-]) 0 1 0 2 1 0 1 3 2 1 2 1
|
64
|
+
6
|
65
|
+
```
|
66
|
+
- Compute the correlation between two arrays of numbers (taken from [here](https://stackoverflow.com/a/44845495/3923281)). This is a complex combination of different verbs, adverbs, conjunctions and trains:
|
67
|
+
```j
|
68
|
+
2 1 1 7 9 (+/@:* % *&(+/)&.:*:)&(- +/%#) 6 3 1 5 7
|
69
|
+
0.721332
|
70
|
+
```
|
71
|
+
- Create identity matrices in inventive ways (see [this essay](https://code.jsoftware.com/wiki/Essays/Identity_Matrix)):
|
72
|
+
```j
|
73
|
+
|.@~:\ @ ($&0) 3
|
74
|
+
1 0 0
|
75
|
+
0 1 0
|
76
|
+
0 0 1
|
77
|
+
|
78
|
+
(i.@,~ = >: * i.) 3
|
79
|
+
1 0 0
|
80
|
+
0 1 0
|
81
|
+
0 0 1
|
82
|
+
|
83
|
+
((={:)\ @ i.) 3
|
84
|
+
1 0 0
|
85
|
+
0 1 0
|
86
|
+
0 0 1
|
87
|
+
```
|
88
|
+
- Solve the Josephus problem (see [this essay](https://code.jsoftware.com/wiki/Essays/Josephus_Problem)). Calculate the survivor's number for a circle of people of size N. Note the use of verb obverse and the rank conjunction:
|
89
|
+
```j
|
90
|
+
(1&|.&.#:)"0 >: i. 5 10 NB. N ranges from 1 to 50 here (arranged as a table)
|
91
|
+
1 1 3 1 3 5 7 1 3 5
|
92
|
+
7 9 11 13 15 1 3 5 7 9
|
93
|
+
11 13 15 17 19 21 23 25 27 29
|
94
|
+
31 1 3 5 7 9 11 13 15 17
|
95
|
+
19 21 23 25 27 29 31 33 35 37
|
96
|
+
```
|
97
|
+
- Build nested boxes containing heterogeneous data types and print the contents:
|
98
|
+
```j
|
99
|
+
(<<'abc'),(<(<'de',.'fg'),(<<i. 5 2)),(<(<"0 ] % i. 2 2 3))
|
100
|
+
┌─────┬──────────┬────────────────────────────┐
|
101
|
+
│┌───┐│┌──┬─────┐│┌────────┬────────┬────────┐│
|
102
|
+
││abc│││df│┌───┐│││_ │1 │0.5 ││
|
103
|
+
│└───┘││eg││0 1│││├────────┼────────┼────────┤│
|
104
|
+
│ ││ ││2 3││││0.333333│0.25 │0.2 ││
|
105
|
+
│ ││ ││4 5│││└────────┴────────┴────────┘│
|
106
|
+
│ ││ ││6 7│││ │
|
107
|
+
│ ││ ││8 9│││┌────────┬────────┬────────┐│
|
108
|
+
│ ││ │└───┘│││0.166667│0.142857│0.125 ││
|
109
|
+
│ │└──┴─────┘│├────────┼────────┼────────┤│
|
110
|
+
│ │ ││0.111111│0.1 │0.090909││
|
111
|
+
│ │ │└────────┴────────┴────────┘│
|
112
|
+
└─────┴──────────┴────────────────────────────┘
|
113
|
+
```
|
114
|
+
|
115
|
+
## Easily Customisable
|
116
|
+
|
117
|
+
Everything is in Python. Adding new primitives is easy.
|
118
|
+
|
119
|
+
Update the `primitives.py` file with your new part of speech (e.g. a new verb such as `+::`). Write your implementation of this new part of speech in the relevant executor module (e.g. `verbs.py`) and then update the name-to-method mapping at the foot of that module. That's all that's needed.
|
120
|
+
|
121
|
+
## Alternative Executors
|
122
|
+
|
123
|
+
Execution of sentences is backed by NumPy by default.
|
124
|
+
|
125
|
+
However Jinx is designed so that it's possible to implement the primitives using alternative frameworks too. Python many Machine Learning and Scientific Programming libraries that could be used to execution J code.
|
126
|
+
|
127
|
+
To prove this concept, there's _highly experimental and incomplete_ support for [JAX](https://docs.jax.dev/en/latest/index.html):
|
128
|
+
```sh
|
129
|
+
jinx --executor jax
|
130
|
+
```
|
131
|
+
Primitive verbs are JIT compiled and execute on JAX arrays:
|
132
|
+
```j
|
133
|
+
mean =: +/ % #
|
134
|
+
mean 33 55 77 100 101
|
135
|
+
73.2
|
136
|
+
```
|
137
|
+
|
138
|
+
## Warning
|
139
|
+
|
140
|
+
This project is experimental. There will be bugs, missing features and performance quirks.
|
141
|
+
|
142
|
+
Many key parts of J are not currently implemented (but might be in future). These include:
|
143
|
+
- Differences in how names are interpreted and resolved at execution time.
|
144
|
+
- Locales.
|
145
|
+
- Definitions and direct definitions (using `{{ ... }}`).
|
146
|
+
- Array types other than floats, integers and and strings.
|
147
|
+
- Executing J scripts.
|
148
|
+
- Control words.
|
jjinx-0.0.1/README.md
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
# Jinx
|
2
|
+
|
3
|
+

|
4
|
+
|
5
|
+
An experimental interpreter for the J programming language, built on top of [NumPy](https://numpy.org/).
|
6
|
+
|
7
|
+
Implements many of J's primitives and tacit programming capabilities, and can be extended to support execution via other frameworks too.
|
8
|
+
|
9
|
+
## Executing J
|
10
|
+
|
11
|
+
Start the interactive shell:
|
12
|
+
```sh
|
13
|
+
jinx
|
14
|
+
```
|
15
|
+
The shell prompt is four spaces, so commands appear indented. Internally, all multidimensional arrays are NumPy arrays. Verbs, conjunctions and adverbs are a mixture of Python and NumPy methods.
|
16
|
+
|
17
|
+
Here are some examples what Jinx can do so far:
|
18
|
+
|
19
|
+
- Solve the "trapping rainwater" problem (solution taken from [here](https://mmapped.blog/posts/04-square-joy-trapped-rain-water)):
|
20
|
+
```j
|
21
|
+
+/@((>./\ <. >./\.)-]) 0 1 0 2 1 0 1 3 2 1 2 1
|
22
|
+
6
|
23
|
+
```
|
24
|
+
- Compute the correlation between two arrays of numbers (taken from [here](https://stackoverflow.com/a/44845495/3923281)). This is a complex combination of different verbs, adverbs, conjunctions and trains:
|
25
|
+
```j
|
26
|
+
2 1 1 7 9 (+/@:* % *&(+/)&.:*:)&(- +/%#) 6 3 1 5 7
|
27
|
+
0.721332
|
28
|
+
```
|
29
|
+
- Create identity matrices in inventive ways (see [this essay](https://code.jsoftware.com/wiki/Essays/Identity_Matrix)):
|
30
|
+
```j
|
31
|
+
|.@~:\ @ ($&0) 3
|
32
|
+
1 0 0
|
33
|
+
0 1 0
|
34
|
+
0 0 1
|
35
|
+
|
36
|
+
(i.@,~ = >: * i.) 3
|
37
|
+
1 0 0
|
38
|
+
0 1 0
|
39
|
+
0 0 1
|
40
|
+
|
41
|
+
((={:)\ @ i.) 3
|
42
|
+
1 0 0
|
43
|
+
0 1 0
|
44
|
+
0 0 1
|
45
|
+
```
|
46
|
+
- Solve the Josephus problem (see [this essay](https://code.jsoftware.com/wiki/Essays/Josephus_Problem)). Calculate the survivor's number for a circle of people of size N. Note the use of verb obverse and the rank conjunction:
|
47
|
+
```j
|
48
|
+
(1&|.&.#:)"0 >: i. 5 10 NB. N ranges from 1 to 50 here (arranged as a table)
|
49
|
+
1 1 3 1 3 5 7 1 3 5
|
50
|
+
7 9 11 13 15 1 3 5 7 9
|
51
|
+
11 13 15 17 19 21 23 25 27 29
|
52
|
+
31 1 3 5 7 9 11 13 15 17
|
53
|
+
19 21 23 25 27 29 31 33 35 37
|
54
|
+
```
|
55
|
+
- Build nested boxes containing heterogeneous data types and print the contents:
|
56
|
+
```j
|
57
|
+
(<<'abc'),(<(<'de',.'fg'),(<<i. 5 2)),(<(<"0 ] % i. 2 2 3))
|
58
|
+
┌─────┬──────────┬────────────────────────────┐
|
59
|
+
│┌───┐│┌──┬─────┐│┌────────┬────────┬────────┐│
|
60
|
+
││abc│││df│┌───┐│││_ │1 │0.5 ││
|
61
|
+
│└───┘││eg││0 1│││├────────┼────────┼────────┤│
|
62
|
+
│ ││ ││2 3││││0.333333│0.25 │0.2 ││
|
63
|
+
│ ││ ││4 5│││└────────┴────────┴────────┘│
|
64
|
+
│ ││ ││6 7│││ │
|
65
|
+
│ ││ ││8 9│││┌────────┬────────┬────────┐│
|
66
|
+
│ ││ │└───┘│││0.166667│0.142857│0.125 ││
|
67
|
+
│ │└──┴─────┘│├────────┼────────┼────────┤│
|
68
|
+
│ │ ││0.111111│0.1 │0.090909││
|
69
|
+
│ │ │└────────┴────────┴────────┘│
|
70
|
+
└─────┴──────────┴────────────────────────────┘
|
71
|
+
```
|
72
|
+
|
73
|
+
## Easily Customisable
|
74
|
+
|
75
|
+
Everything is in Python. Adding new primitives is easy.
|
76
|
+
|
77
|
+
Update the `primitives.py` file with your new part of speech (e.g. a new verb such as `+::`). Write your implementation of this new part of speech in the relevant executor module (e.g. `verbs.py`) and then update the name-to-method mapping at the foot of that module. That's all that's needed.
|
78
|
+
|
79
|
+
## Alternative Executors
|
80
|
+
|
81
|
+
Execution of sentences is backed by NumPy by default.
|
82
|
+
|
83
|
+
However Jinx is designed so that it's possible to implement the primitives using alternative frameworks too. Python many Machine Learning and Scientific Programming libraries that could be used to execution J code.
|
84
|
+
|
85
|
+
To prove this concept, there's _highly experimental and incomplete_ support for [JAX](https://docs.jax.dev/en/latest/index.html):
|
86
|
+
```sh
|
87
|
+
jinx --executor jax
|
88
|
+
```
|
89
|
+
Primitive verbs are JIT compiled and execute on JAX arrays:
|
90
|
+
```j
|
91
|
+
mean =: +/ % #
|
92
|
+
mean 33 55 77 100 101
|
93
|
+
73.2
|
94
|
+
```
|
95
|
+
|
96
|
+
## Warning
|
97
|
+
|
98
|
+
This project is experimental. There will be bugs, missing features and performance quirks.
|
99
|
+
|
100
|
+
Many key parts of J are not currently implemented (but might be in future). These include:
|
101
|
+
- Differences in how names are interpreted and resolved at execution time.
|
102
|
+
- Locales.
|
103
|
+
- Definitions and direct definitions (using `{{ ... }}`).
|
104
|
+
- Array types other than floats, integers and and strings.
|
105
|
+
- Executing J scripts.
|
106
|
+
- Control words.
|
@@ -0,0 +1,49 @@
|
|
1
|
+
[build-system]
|
2
|
+
requires = ["setuptools>=61.0.0", "wheel"]
|
3
|
+
build-backend = "setuptools.build_meta"
|
4
|
+
|
5
|
+
[project]
|
6
|
+
name = "jjinx"
|
7
|
+
version = "0.0.1"
|
8
|
+
description = "Interpreter for the J programming language."
|
9
|
+
readme = "README.md"
|
10
|
+
authors = [{ name = "Alex Riley" }]
|
11
|
+
license = { file = "LICENSE" }
|
12
|
+
classifiers = [
|
13
|
+
"Development Status :: 3 - Alpha",
|
14
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
15
|
+
"Topic :: Utilities",
|
16
|
+
"Typing :: Typed",
|
17
|
+
"Intended Audience :: Science/Research",
|
18
|
+
"License :: OSI Approved :: MIT License",
|
19
|
+
"Programming Language :: Python :: 3.13",
|
20
|
+
]
|
21
|
+
keywords = ["J", "interpreter"]
|
22
|
+
requires-python = ">=3.13"
|
23
|
+
dependencies = [
|
24
|
+
"numpy>=2.3.3",
|
25
|
+
]
|
26
|
+
|
27
|
+
[project.urls]
|
28
|
+
Homepage = "https://github.com/ajcr/jinx"
|
29
|
+
|
30
|
+
[project.scripts]
|
31
|
+
jinx = "jinx.shell:main"
|
32
|
+
|
33
|
+
[tool.pytest.ini_options]
|
34
|
+
pythonpath = [
|
35
|
+
"src"
|
36
|
+
]
|
37
|
+
addopts = [
|
38
|
+
"--import-mode=importlib",
|
39
|
+
]
|
40
|
+
|
41
|
+
[dependency-groups]
|
42
|
+
dev = [
|
43
|
+
"mypy>=1.18.2",
|
44
|
+
"pytest>=8.4.2",
|
45
|
+
"ruff>=0.13.1",
|
46
|
+
]
|
47
|
+
jax = [
|
48
|
+
"jax>=0.7.2",
|
49
|
+
]
|
jjinx-0.0.1/setup.cfg
ADDED
File without changes
|
@@ -0,0 +1,41 @@
|
|
1
|
+
"""J errors for incorrect usage of J primitives."""
|
2
|
+
|
3
|
+
|
4
|
+
class BaseJError(Exception):
|
5
|
+
pass
|
6
|
+
|
7
|
+
|
8
|
+
class LengthError(BaseJError):
|
9
|
+
pass
|
10
|
+
|
11
|
+
|
12
|
+
class DomainError(BaseJError):
|
13
|
+
pass
|
14
|
+
|
15
|
+
|
16
|
+
class ValenceError(BaseJError):
|
17
|
+
pass
|
18
|
+
|
19
|
+
|
20
|
+
class JIndexError(BaseJError):
|
21
|
+
pass
|
22
|
+
|
23
|
+
|
24
|
+
class SpellingError(BaseJError):
|
25
|
+
pass
|
26
|
+
|
27
|
+
|
28
|
+
class StackError(BaseJError):
|
29
|
+
pass
|
30
|
+
|
31
|
+
|
32
|
+
class EvaluationError(BaseJError):
|
33
|
+
pass
|
34
|
+
|
35
|
+
|
36
|
+
class JSyntaxError(BaseJError):
|
37
|
+
pass
|
38
|
+
|
39
|
+
|
40
|
+
class JinxNotImplementedError(BaseJError):
|
41
|
+
"""Raised when a feature is not implemented in Jinx."""
|
@@ -0,0 +1,60 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from typing import Callable
|
3
|
+
|
4
|
+
from jinx.vocabulary import Adverb, Conjunction, Noun, Verb
|
5
|
+
|
6
|
+
|
7
|
+
@dataclass(frozen=True)
|
8
|
+
class Executor[T]:
|
9
|
+
apply_monad: Callable[[Verb[T], Noun[T]], Noun[T]]
|
10
|
+
"""Apply monadic form of verb to a noun."""
|
11
|
+
|
12
|
+
apply_dyad: Callable[[Verb[T], Noun[T], Noun[T]], Noun[T]]
|
13
|
+
"""Apply dyadic form of verb to two nouns."""
|
14
|
+
|
15
|
+
apply_conjunction: Callable[
|
16
|
+
[Verb[T] | Noun[T], Conjunction, Verb[T]], Verb[T] | Noun[T]
|
17
|
+
]
|
18
|
+
"""Apply conjunction to left and right arguments."""
|
19
|
+
|
20
|
+
apply_adverb: Callable[[Verb[T] | Noun[T], Adverb], Verb[T] | Noun[T]]
|
21
|
+
"""Apply adverb to left argument."""
|
22
|
+
|
23
|
+
build_fork: Callable[[Noun[T] | Verb[T], Verb[T], Verb[T]], Verb[T]]
|
24
|
+
"""Build fork."""
|
25
|
+
|
26
|
+
build_hook: Callable[[Verb[T], Verb[T]], Verb[T]]
|
27
|
+
"""Build hook."""
|
28
|
+
|
29
|
+
ensure_noun_implementation: Callable[[Noun[T]], None]
|
30
|
+
"""Ensure that the noun has an implementation."""
|
31
|
+
|
32
|
+
primitive_verb_map: dict[
|
33
|
+
str, tuple[Callable[[T], T] | None, Callable[[T, T], T] | None]
|
34
|
+
]
|
35
|
+
"""Map of primitive verb names to implementations of monad and dyad functions."""
|
36
|
+
|
37
|
+
primitive_adverb_map: dict[str, Callable[[Verb[T]], Verb[T]]]
|
38
|
+
"""Map of primitive adverb names to implementation function."""
|
39
|
+
|
40
|
+
primitive_conjuction_map: dict[
|
41
|
+
str, Callable[[Verb[T] | Noun[T], Verb[T] | Noun[T]], Verb[T]]
|
42
|
+
]
|
43
|
+
"""Map of primitive conjunction names to implementation function."""
|
44
|
+
|
45
|
+
noun_to_string: Callable[[Noun[T]], str]
|
46
|
+
"""Convert a noun to a string representation for printing."""
|
47
|
+
|
48
|
+
|
49
|
+
def load_executor(name: str) -> Executor:
|
50
|
+
if name == "numpy":
|
51
|
+
from jinx.execution.numpy import executor as numpy_executor
|
52
|
+
|
53
|
+
return numpy_executor
|
54
|
+
|
55
|
+
if name == "jax":
|
56
|
+
from jinx.execution.jax import executor as jax_executor
|
57
|
+
|
58
|
+
return jax_executor
|
59
|
+
|
60
|
+
raise ValueError(f"Unknown executor: {name}")
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import jax
|
2
|
+
from jinx.errors import JinxNotImplementedError
|
3
|
+
from jinx.execution.executor import Executor
|
4
|
+
from jinx.execution.jax.adverbs import ADVERB_MAP
|
5
|
+
from jinx.execution.jax.application import (
|
6
|
+
apply_adverb,
|
7
|
+
# apply_conjunction,
|
8
|
+
apply_dyad,
|
9
|
+
apply_monad,
|
10
|
+
build_fork,
|
11
|
+
# build_hook,
|
12
|
+
ensure_noun_implementation,
|
13
|
+
)
|
14
|
+
from jinx.execution.jax.verbs import VERB_MAP
|
15
|
+
|
16
|
+
# from jinx.execution.numpy.conjunctions import CONJUNCTION_MAP
|
17
|
+
# from jinx.execution.numpy.conversion import ensure_noun_implementation
|
18
|
+
from jinx.execution.numpy.printing import noun_to_string
|
19
|
+
|
20
|
+
jax.config.update("jax_dynamic_shapes", True)
|
21
|
+
|
22
|
+
|
23
|
+
def make_not_implemented(name: str):
|
24
|
+
def _not_implemented(*_, **__):
|
25
|
+
raise JinxNotImplementedError(
|
26
|
+
f"{name}: not yet implemented in the JAX executor."
|
27
|
+
)
|
28
|
+
|
29
|
+
return _not_implemented
|
30
|
+
|
31
|
+
|
32
|
+
executor = Executor[jax.Array](
|
33
|
+
apply_monad=apply_monad,
|
34
|
+
apply_dyad=apply_dyad,
|
35
|
+
apply_conjunction=make_not_implemented("conjunction"),
|
36
|
+
apply_adverb=apply_adverb,
|
37
|
+
build_fork=build_fork,
|
38
|
+
build_hook=make_not_implemented("hook"),
|
39
|
+
ensure_noun_implementation=ensure_noun_implementation,
|
40
|
+
primitive_verb_map=VERB_MAP,
|
41
|
+
primitive_adverb_map=ADVERB_MAP,
|
42
|
+
primitive_conjuction_map={},
|
43
|
+
# Just use the NumPy implementation of printing.
|
44
|
+
noun_to_string=noun_to_string, # type: ignore[arg-type]
|
45
|
+
)
|
@@ -0,0 +1,91 @@
|
|
1
|
+
"""Methods implementing J adverbs."""
|
2
|
+
|
3
|
+
import functools
|
4
|
+
from typing import Callable
|
5
|
+
|
6
|
+
import jax
|
7
|
+
import jax.numpy as jnp
|
8
|
+
from jinx.errors import JinxNotImplementedError, ValenceError
|
9
|
+
from jinx.execution.jax.application import _apply_dyad
|
10
|
+
from jinx.execution.numpy.helpers import (
|
11
|
+
maybe_parenthesise_verb_spelling,
|
12
|
+
)
|
13
|
+
from jinx.vocabulary import Dyad, Monad, Verb
|
14
|
+
|
15
|
+
INFINITY = float("inf")
|
16
|
+
|
17
|
+
|
18
|
+
def slash_adverb(verb: Verb[jax.Array]) -> Verb[jax.Array]:
|
19
|
+
if verb.dyad is None or verb.dyad.function is None:
|
20
|
+
# Note: this differs from J which still allows the adverb to be applied
|
21
|
+
# to a verb, but may raise an error when the new verb is applied to a noun
|
22
|
+
# and the verb has no dyadic valence.
|
23
|
+
raise ValenceError(f"Verb {verb.spelling} has no dyadic valence.")
|
24
|
+
|
25
|
+
if isinstance(verb.dyad.function, jnp.ufunc) and verb.dyad.is_commutative:
|
26
|
+
monad = verb.dyad.function.reduce
|
27
|
+
dyad = verb.dyad.function.outer
|
28
|
+
|
29
|
+
else:
|
30
|
+
# Slow path: dyad is not a ufunc.
|
31
|
+
# The function is either callable, in which cases it is applied directly,
|
32
|
+
# or a Verb object that needs to be applied indirectly with _apply_dyad().
|
33
|
+
if isinstance(verb.dyad.function, Verb):
|
34
|
+
func = functools.partial(_apply_dyad, verb) # type: ignore[assignment]
|
35
|
+
else:
|
36
|
+
func = verb.dyad.function # type: ignore[assignment]
|
37
|
+
|
38
|
+
def _dyad_arg_swap(x: jax.Array, y: jax.Array) -> jax.Array:
|
39
|
+
return func(y, x)
|
40
|
+
|
41
|
+
def _reduce(y: jax.Array) -> jax.Array:
|
42
|
+
y = jnp.atleast_1d(y)
|
43
|
+
y = jnp.flip(y, axis=0)
|
44
|
+
return functools.reduce(_dyad_arg_swap, y)
|
45
|
+
|
46
|
+
monad = _reduce # type: ignore[assignment]
|
47
|
+
dyad = NotImplemented
|
48
|
+
|
49
|
+
spelling = maybe_parenthesise_verb_spelling(verb.spelling)
|
50
|
+
spelling = f"{verb.spelling}/"
|
51
|
+
|
52
|
+
return Verb[jax.Array](
|
53
|
+
name=spelling,
|
54
|
+
spelling=spelling,
|
55
|
+
monad=Monad(name=spelling, rank=INFINITY, function=monad),
|
56
|
+
dyad=Dyad(
|
57
|
+
name=spelling, left_rank=INFINITY, right_rank=INFINITY, function=dyad
|
58
|
+
),
|
59
|
+
)
|
60
|
+
|
61
|
+
|
62
|
+
def bslash_adverb(verb: Verb[jax.Array]) -> Verb[jax.Array]:
|
63
|
+
# Common cases that have a straightforward optimisation.
|
64
|
+
SPECIAL_MONAD = {
|
65
|
+
"+/": jnp.cumulative_sum,
|
66
|
+
"*/": jnp.cumulative_prod,
|
67
|
+
}
|
68
|
+
|
69
|
+
if verb.spelling in SPECIAL_MONAD:
|
70
|
+
monad_ = SPECIAL_MONAD[verb.spelling]
|
71
|
+
|
72
|
+
else:
|
73
|
+
raise JinxNotImplementedError(
|
74
|
+
f"Adverb \\ applied to verb {verb.spelling} is not yet implemented."
|
75
|
+
)
|
76
|
+
|
77
|
+
spelling = maybe_parenthesise_verb_spelling(verb.spelling)
|
78
|
+
spelling = f"{spelling}\\"
|
79
|
+
|
80
|
+
return Verb(
|
81
|
+
name=spelling,
|
82
|
+
spelling=spelling,
|
83
|
+
monad=Monad(name=spelling, rank=INFINITY, function=monad_),
|
84
|
+
dyad=Dyad(name=spelling, left_rank=0, right_rank=INFINITY, function=None), # type: ignore[arg-type]
|
85
|
+
)
|
86
|
+
|
87
|
+
|
88
|
+
ADVERB_MAP: dict[str, Callable[[Verb[jax.Array]], Verb[jax.Array]]] = {
|
89
|
+
"SLASH": slash_adverb,
|
90
|
+
"BSLASH": bslash_adverb,
|
91
|
+
}
|