ilang-python 0.1.0__py3-none-macosx_11_0_arm64.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.
- ilang/__init__.py +20 -0
- ilang/component.py +529 -0
- ilang/ffi.py +151 -0
- ilang/inputs.py +66 -0
- ilang/libi_core.dylib +0 -0
- ilang/tensor.py +205 -0
- ilang_python-0.1.0.dist-info/METADATA +225 -0
- ilang_python-0.1.0.dist-info/RECORD +10 -0
- ilang_python-0.1.0.dist-info/WHEEL +4 -0
- ilang_python-0.1.0.dist-info/licenses/LICENSE +202 -0
ilang/inputs.py
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from . import ffi
|
|
7
|
+
from .tensor import Device, Tensor, _shape_array
|
|
8
|
+
|
|
9
|
+
__all__: list[str] = []
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class _Input:
|
|
13
|
+
def __init__(self, tensor: ffi._CTensor, keepalive: tuple[Any, ...]) -> None:
|
|
14
|
+
self.tensor: ffi._CTensor = tensor
|
|
15
|
+
self.keepalive: tuple[Any, ...] = keepalive
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _input(x: Any) -> _Input:
|
|
19
|
+
if isinstance(x, Tensor):
|
|
20
|
+
try:
|
|
21
|
+
import torch
|
|
22
|
+
|
|
23
|
+
if isinstance(x._owner, torch.Tensor):
|
|
24
|
+
inner = _input(x._owner)
|
|
25
|
+
return _Input(inner.tensor, (x, inner))
|
|
26
|
+
except ImportError:
|
|
27
|
+
pass
|
|
28
|
+
return _Input(x._view(), (x,))
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
import numpy as np
|
|
32
|
+
|
|
33
|
+
if isinstance(x, np.ndarray):
|
|
34
|
+
if x.dtype != np.float32 or not x.flags.c_contiguous:
|
|
35
|
+
raise TypeError("NumPy inputs must be float32 and C-contiguous")
|
|
36
|
+
shape, shape_buf = _shape_array(x.shape)
|
|
37
|
+
data = x.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
|
|
38
|
+
return _Input(ffi._CTensor(data, shape_buf, len(shape)), (x, shape_buf))
|
|
39
|
+
except ImportError:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
import torch
|
|
44
|
+
|
|
45
|
+
if isinstance(x, torch.Tensor):
|
|
46
|
+
if str(x.dtype) != "torch.float32":
|
|
47
|
+
raise TypeError("Torch tensors must be float32")
|
|
48
|
+
if not x.is_contiguous():
|
|
49
|
+
raise TypeError("Torch tensors must be contiguous")
|
|
50
|
+
shape, shape_buf = _shape_array(tuple(x.shape))
|
|
51
|
+
data = ctypes.cast(x.data_ptr(), ctypes.POINTER(ctypes.c_float))
|
|
52
|
+
return _Input(ffi._CTensor(data, shape_buf, len(shape)), (x, shape_buf))
|
|
53
|
+
except ImportError:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
return _input(Tensor(x))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _inputs(
|
|
60
|
+
xs: list[Any] | tuple[Any, ...],
|
|
61
|
+
) -> tuple[ctypes.Array[ffi._CTensor], list[_Input]]:
|
|
62
|
+
views: list[_Input] = [_input(x) for x in xs]
|
|
63
|
+
arr: ctypes.Array[ffi._CTensor] = (ffi._CTensor * len(views))(
|
|
64
|
+
*(v.tensor for v in views)
|
|
65
|
+
)
|
|
66
|
+
return arr, views
|
ilang/libi_core.dylib
ADDED
|
Binary file
|
ilang/tensor.py
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import ctypes
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from numbers import Real
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from . import ffi
|
|
9
|
+
|
|
10
|
+
__all__ = ["Device", "Tensor"]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Device(Enum):
|
|
15
|
+
CPU = "cpu"
|
|
16
|
+
CUDA = "cuda"
|
|
17
|
+
|
|
18
|
+
def _as_ffi(self) -> int:
|
|
19
|
+
return 0 if self is Device.CPU else 1
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def coerce(cls, value: Device | str) -> Device:
|
|
23
|
+
if isinstance(value, Device):
|
|
24
|
+
return value
|
|
25
|
+
name = str(value).lower()
|
|
26
|
+
if name in {"cpu", "device.cpu"}:
|
|
27
|
+
return Device.CPU
|
|
28
|
+
if name in {"cuda", "gpu", "device.cuda"}:
|
|
29
|
+
return Device.CUDA
|
|
30
|
+
raise ValueError(f"unknown device {value!r}")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _shape_array(
|
|
34
|
+
shape: tuple[int, ...],
|
|
35
|
+
) -> tuple[tuple[int, ...], Any]:
|
|
36
|
+
shape = tuple(int(d) for d in shape)
|
|
37
|
+
arr: Any = (ctypes.c_size_t * len(shape))(*shape)
|
|
38
|
+
return shape, arr
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _flatten(x: Any) -> tuple[tuple[int, ...], list[float]]:
|
|
42
|
+
if isinstance(x, Real):
|
|
43
|
+
return (), [float(x)]
|
|
44
|
+
if not isinstance(x, (list, tuple)):
|
|
45
|
+
raise TypeError("Tensor expects a scalar or nested Python lists")
|
|
46
|
+
if not x:
|
|
47
|
+
return (0,), []
|
|
48
|
+
|
|
49
|
+
child_shape, _data = _flatten(x[0])
|
|
50
|
+
shape: tuple[int, ...] = (len(x),) + child_shape
|
|
51
|
+
out: list[float] = []
|
|
52
|
+
for item in x:
|
|
53
|
+
item_shape, item_data = _flatten(item)
|
|
54
|
+
if item_shape != child_shape:
|
|
55
|
+
raise ValueError("ragged Tensor input")
|
|
56
|
+
out.extend(item_data)
|
|
57
|
+
return shape, out
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _torch_cuda_empty(shape: tuple[int, ...]) -> Any | None:
|
|
61
|
+
try:
|
|
62
|
+
import torch
|
|
63
|
+
|
|
64
|
+
if torch.cuda.is_available():
|
|
65
|
+
return torch.empty(shape, dtype=torch.float32, device="cuda")
|
|
66
|
+
except ImportError:
|
|
67
|
+
pass
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _numel(shape: tuple[int, ...]) -> int:
|
|
72
|
+
n = 1
|
|
73
|
+
for dim in shape:
|
|
74
|
+
n *= dim
|
|
75
|
+
return n
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class _OwnedOutputs:
|
|
79
|
+
def __init__(self, outputs: ctypes.Structure) -> None:
|
|
80
|
+
self.outputs: ctypes.Structure | None = outputs
|
|
81
|
+
|
|
82
|
+
def __del__(self) -> None:
|
|
83
|
+
outputs = getattr(self, "outputs", None)
|
|
84
|
+
if outputs is not None:
|
|
85
|
+
self.outputs = None
|
|
86
|
+
ffi._core.i_outputs_free(outputs)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class _DeviceOwner:
|
|
90
|
+
def __init__(self, device: Device, data: Any) -> None:
|
|
91
|
+
self.device = device
|
|
92
|
+
self.data: Any | None = data
|
|
93
|
+
|
|
94
|
+
def __del__(self) -> None:
|
|
95
|
+
data = getattr(self, "data", None)
|
|
96
|
+
if data is not None:
|
|
97
|
+
self.data = None
|
|
98
|
+
ffi._core.i_free(self.device._as_ffi(), data)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class Tensor:
|
|
102
|
+
def __init__(
|
|
103
|
+
self,
|
|
104
|
+
x: Any,
|
|
105
|
+
shape: tuple[int, ...] | None = None,
|
|
106
|
+
*,
|
|
107
|
+
device: Device | str = Device.CPU,
|
|
108
|
+
) -> None:
|
|
109
|
+
device = Device.coerce(device)
|
|
110
|
+
if shape is None:
|
|
111
|
+
shape, data = _flatten(x)
|
|
112
|
+
else:
|
|
113
|
+
shape = tuple(int(d) for d in shape)
|
|
114
|
+
data = [float(v) for v in x]
|
|
115
|
+
self.shape: tuple[int, ...] = tuple(shape)
|
|
116
|
+
self.device: Device = Device.CPU
|
|
117
|
+
self._len: int = len(data)
|
|
118
|
+
self._data: Any = (ctypes.c_float * self._len)(*data)
|
|
119
|
+
self._shape, self._shape_buf = _shape_array(self.shape)
|
|
120
|
+
self._owner: _OwnedOutputs | _DeviceOwner | None = None
|
|
121
|
+
if device is Device.CUDA:
|
|
122
|
+
moved = self.to(Device.CUDA)
|
|
123
|
+
self.device = moved.device
|
|
124
|
+
self._data = moved._data
|
|
125
|
+
self._owner = moved._owner
|
|
126
|
+
moved._owner = None
|
|
127
|
+
|
|
128
|
+
@classmethod
|
|
129
|
+
def _from_owned(cls, owner: _OwnedOutputs, index: int) -> Tensor:
|
|
130
|
+
outputs = owner.outputs
|
|
131
|
+
assert outputs is not None
|
|
132
|
+
raw = outputs.tensors[index]
|
|
133
|
+
self: Tensor = cls.__new__(cls)
|
|
134
|
+
self.shape = tuple(raw.shape[i] for i in range(raw.rank))
|
|
135
|
+
self.device = Device.CPU
|
|
136
|
+
self._len = raw.len
|
|
137
|
+
self._data = raw.data
|
|
138
|
+
self._shape, self._shape_buf = _shape_array(self.shape)
|
|
139
|
+
self._owner = owner
|
|
140
|
+
return self
|
|
141
|
+
|
|
142
|
+
@classmethod
|
|
143
|
+
def _empty(cls, shape: tuple[int, ...], device: Device | str) -> Tensor:
|
|
144
|
+
device = Device.coerce(device)
|
|
145
|
+
self: Tensor = cls.__new__(cls)
|
|
146
|
+
self.shape = tuple(int(d) for d in shape)
|
|
147
|
+
self.device = device
|
|
148
|
+
self._len = _numel(self.shape)
|
|
149
|
+
self._shape, self._shape_buf = _shape_array(self.shape)
|
|
150
|
+
if device is Device.CPU:
|
|
151
|
+
self._data = (ctypes.c_float * self._len)()
|
|
152
|
+
self._owner = None
|
|
153
|
+
else:
|
|
154
|
+
torch_owner = _torch_cuda_empty(self.shape)
|
|
155
|
+
if torch_owner is not None:
|
|
156
|
+
self._data = ctypes.cast(torch_owner.data_ptr(), ctypes.POINTER(ctypes.c_float))
|
|
157
|
+
self._owner = torch_owner
|
|
158
|
+
else:
|
|
159
|
+
data = ffi._check_ptr(ffi._core.i_alloc(device._as_ffi(), self._len))
|
|
160
|
+
self._data = ctypes.cast(data, ctypes.POINTER(ctypes.c_float))
|
|
161
|
+
self._owner = _DeviceOwner(device, self._data)
|
|
162
|
+
return self
|
|
163
|
+
|
|
164
|
+
@property
|
|
165
|
+
def data(self) -> list[float]:
|
|
166
|
+
if self.device is not Device.CPU:
|
|
167
|
+
raise RuntimeError(
|
|
168
|
+
"CUDA tensor data is not directly accessible; call .to(Device.CPU) first"
|
|
169
|
+
)
|
|
170
|
+
return [self._data[i] for i in range(self._len)]
|
|
171
|
+
|
|
172
|
+
def to(self, device: Device | str) -> Tensor:
|
|
173
|
+
device = Device.coerce(device)
|
|
174
|
+
if device is self.device:
|
|
175
|
+
return self
|
|
176
|
+
out = Tensor._empty(self.shape, device)
|
|
177
|
+
ffi._check(
|
|
178
|
+
ffi._core.i_copy(
|
|
179
|
+
out.device._as_ffi(),
|
|
180
|
+
out._data,
|
|
181
|
+
self.device._as_ffi(),
|
|
182
|
+
self._data,
|
|
183
|
+
self._len,
|
|
184
|
+
)
|
|
185
|
+
)
|
|
186
|
+
return out
|
|
187
|
+
|
|
188
|
+
def _view(self) -> ffi._CTensor:
|
|
189
|
+
try:
|
|
190
|
+
import torch
|
|
191
|
+
|
|
192
|
+
if isinstance(self._owner, torch.Tensor):
|
|
193
|
+
data = ctypes.cast(self._owner.data_ptr(), ctypes.POINTER(ctypes.c_float))
|
|
194
|
+
return ffi._CTensor(data, self._shape_buf, len(self.shape))
|
|
195
|
+
except ImportError:
|
|
196
|
+
pass
|
|
197
|
+
return ffi._CTensor(self._data, self._shape_buf, len(self.shape))
|
|
198
|
+
|
|
199
|
+
def __del__(self) -> None:
|
|
200
|
+
self._owner = None
|
|
201
|
+
|
|
202
|
+
def __repr__(self) -> str:
|
|
203
|
+
if self.device is Device.CPU:
|
|
204
|
+
return f"Tensor(shape={self.shape}, device=CPU, data={self.data})"
|
|
205
|
+
return f"Tensor(shape={self.shape}, device=CUDA)"
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ilang-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python front-end for 𝚒
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
Python front-end for 𝚒.
|
|
12
|
+
|
|
13
|
+
This package exposes 𝚒 components as Python objects. Components compile lazily,
|
|
14
|
+
execute on CPU or CUDA according to their inputs, and interoperate with
|
|
15
|
+
`i.Tensor`, Python scalar/list literals, NumPy `array`s, and Torch `tensor`s.
|
|
16
|
+
|
|
17
|
+
## Package-style API
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import ilang
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Exports:
|
|
24
|
+
|
|
25
|
+
- `ilang.Component`
|
|
26
|
+
- `ilang.Tensor`
|
|
27
|
+
- `ilang.Device`
|
|
28
|
+
- `ilang.Bench`
|
|
29
|
+
- `ilang.i`
|
|
30
|
+
|
|
31
|
+
## Preferred "DSL-style" API
|
|
32
|
+
|
|
33
|
+
The package-exported object `i` acts as a callable "namespace" that enables a
|
|
34
|
+
more compact style of 𝚒 code. When called, it constructs a `Component`, but
|
|
35
|
+
it also re-exposes much of the same package-level API as attributes.
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from ilang import i
|
|
39
|
+
|
|
40
|
+
i("+i~.") # <ilang.component.Component object at ...>
|
|
41
|
+
i.Tensor # <class 'ilang.tensor.Tensor'>
|
|
42
|
+
i.Component # <class 'ilang.component.Component'>
|
|
43
|
+
i.Device # <enum 'Device'>
|
|
44
|
+
i.I # mirrors `ilang.Component.I`
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Devices
|
|
48
|
+
|
|
49
|
+
A `Device` dictates where data lives and where compuation will run.
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
i.Device.CPU # "cpu"
|
|
53
|
+
i.Device.CUDA # "cuda"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Tensors
|
|
57
|
+
|
|
58
|
+
`Tensor`s are immutable multidimensional data arrays.
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
x = i.Tensor([[1, 2], [3, 4]]) # standard construction does shape-inference on nested list
|
|
62
|
+
x = i.Tensor([1, 2, 3, 4], shape=(2, 2)) # flat data with shape also works
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Values are stored as `float32`.
|
|
66
|
+
|
|
67
|
+
### Attributes
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
x.shape # tuple[int, ...]
|
|
71
|
+
x.device # i.Device.CPU or i.Device.CUDA
|
|
72
|
+
x.data # list[float] (only available on CPU tensors)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Methods
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
Tensor.to(device i.Device) -> Tensor # gives a new tensor on specified device
|
|
79
|
+
|
|
80
|
+
# examples:
|
|
81
|
+
x.to(i.Device.CUDA)
|
|
82
|
+
x.to(i.Device.CPU)
|
|
83
|
+
x.to("cuda")
|
|
84
|
+
x.to("cpu")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Components
|
|
88
|
+
|
|
89
|
+
`i(expr: str) -> Component` parses one 𝚒 expression.
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
f = i("+ij~i") # row-sum
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`i.I` is the identity component.
|
|
96
|
+
|
|
97
|
+
### Component combinators
|
|
98
|
+
|
|
99
|
+
Components are combined using combinators. Components are immutable, so
|
|
100
|
+
combinators each return a new component.
|
|
101
|
+
|
|
102
|
+
Method forms:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
f.compose(g) # wires outputs of the right component into inputs of the left component
|
|
106
|
+
f.chain(g) # wires outputs of the left component into inputs of the right component
|
|
107
|
+
f.fanout(g) # shares inputs pairwise between two components
|
|
108
|
+
f.pair(g) # concatenates the inputs and outputs of two components
|
|
109
|
+
f.swap() # swaps the first two outputs of one component
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Operator forms:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
f << g # f.compose(g)
|
|
116
|
+
f >> g # f.chain(g)
|
|
117
|
+
f & g # f.fanout(g)
|
|
118
|
+
f | g # f.pair(g)
|
|
119
|
+
~f # f.swap()
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Example:
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
matmul = i("ik*kj~ijk") >> i("+ijk~ij")
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Execution
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
out = matmul.exec(x, y)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`Component.exec(*inputs: TensorLike, into=None)` executes one component.
|
|
135
|
+
|
|
136
|
+
where `TensorLike = Tensor | torch.Tensor | numpy.ndarray | nested Python
|
|
137
|
+
sequence`
|
|
138
|
+
|
|
139
|
+
Execution device is determined by the input devices. All inputs must use the
|
|
140
|
+
same device. NumPy/Torch inputs must be contiguous and of dtype `float32`.
|
|
141
|
+
Python scalars/lists get promoted to CPU `ilang.Tensor`.
|
|
142
|
+
|
|
143
|
+
### Output type inference
|
|
144
|
+
|
|
145
|
+
The output container type and device are inferred from the input. For example,
|
|
146
|
+
`f.exec(torch.tensor([...], device="cuda"))` returns an `torch.Tensor` with
|
|
147
|
+
`device="cuda"`. This can be overridden with `into=`: `f.exec(nparray,
|
|
148
|
+
into=i.Tensor)`.
|
|
149
|
+
|
|
150
|
+
In general, component execution returns `Tuple[Tensor]` but is automatically
|
|
151
|
+
unpacked for single output results.
|
|
152
|
+
|
|
153
|
+
### Shape inference
|
|
154
|
+
|
|
155
|
+
`Component.output_shapes(*inputs)` returns one shape tuple per output. Shapes
|
|
156
|
+
are computed from input shapes without executing any kernels.
|
|
157
|
+
|
|
158
|
+
## Benchmarking
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
bench = f.bench([x], n_warmups=10, n_runs=100)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`bench` executes warmup runs, records timed runs, and returns `Bench`.
|
|
165
|
+
|
|
166
|
+
`Bench` fields:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
bench.mean # datetime.timedelta
|
|
170
|
+
bench.std # datetime.timedelta
|
|
171
|
+
bench.n_warmups # int
|
|
172
|
+
bench.n_runs # int
|
|
173
|
+
bench.runs # list[datetime.timedelta]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
`repr(bench)` prints a compact human-readable timing summary.
|
|
177
|
+
|
|
178
|
+
## Errors
|
|
179
|
+
|
|
180
|
+
Invalid programs, invalid input types, invalid dtypes, non-contiguous arrays,
|
|
181
|
+
device mismatches, and backend failures raise Python exceptions.
|
|
182
|
+
|
|
183
|
+
Execution requires all inputs to reside on one device. No implicit CPU/CUDA
|
|
184
|
+
input synchronization is performed by `exec`.
|
|
185
|
+
|
|
186
|
+
CUDA tensor data is not read by `repr` and is not exposed by `.data`. Copy to
|
|
187
|
+
CPU explicitly.
|
|
188
|
+
|
|
189
|
+
## Examples
|
|
190
|
+
|
|
191
|
+
Native tensor execution:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
from ilang import i
|
|
195
|
+
|
|
196
|
+
f = i.i("+ij~ij")
|
|
197
|
+
x = i.Tensor([[1, 2], [3, 4]])
|
|
198
|
+
y = f.exec(x)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
CUDA tensor execution:
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
x = i.Tensor([[1, 2], [3, 4]]).to("cuda")
|
|
205
|
+
y = f.exec(x)
|
|
206
|
+
z = y.to("cpu")
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
NumPy execution:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
import numpy as np
|
|
213
|
+
|
|
214
|
+
x = np.ones((2, 2), dtype=np.float32)
|
|
215
|
+
y = f.exec(x)
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Torch CUDA execution:
|
|
219
|
+
|
|
220
|
+
```python
|
|
221
|
+
import torch
|
|
222
|
+
|
|
223
|
+
x = torch.ones((2, 2), dtype=torch.float32, device="cuda")
|
|
224
|
+
y = f.exec(x)
|
|
225
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
ilang/__init__.py,sha256=mPPSerGXB03-ZnBw73WoAxCr6D8oGOXkpQS3MEbP8Us,407
|
|
2
|
+
ilang/component.py,sha256=Eyj2woo0CdS4PZ-N0cuExeYL2IOu6C0aCqL6B-PjYe4,18629
|
|
3
|
+
ilang/ffi.py,sha256=0dM1Oo4OH-0r_dTbws7RomEJ1bMho9jKUXzPm0dYG6g,5023
|
|
4
|
+
ilang/inputs.py,sha256=pYQgclRFTgVGRleDOUQc_OCDnu-BUfcCX_sgNSbXg3s,2024
|
|
5
|
+
ilang/libi_core.dylib,sha256=X2K5ST24X22ZNmLZuJrkeScI_XBunIcSD7icPcpMaxM,1382848
|
|
6
|
+
ilang/tensor.py,sha256=3SsbDPQNW_ogES4Kz7khxOLKn2mVjrwrAyzD2y206T8,6347
|
|
7
|
+
ilang_python-0.1.0.dist-info/METADATA,sha256=osIqosptFQ5ufBCxGOOeG-gzowSI4x6VcCuoKKgPV_c,5059
|
|
8
|
+
ilang_python-0.1.0.dist-info/RECORD,,
|
|
9
|
+
ilang_python-0.1.0.dist-info/WHEEL,sha256=roArpf_MxwvZELSyjqDlac-lUD5_1viQfLUbIwp-24k,102
|
|
10
|
+
ilang_python-0.1.0.dist-info/licenses/LICENSE,sha256=q2NkHiIxxAaG46uZAoBv9ZQlc9OMZBpKv8djpcX5kmo,11341
|