Skip to content

Commit 7a80302

Browse files
Merge branch 'main' into add-larecs
2 parents 4cf9acf + 47dd2ef commit 7a80302

File tree

22 files changed

+417
-95
lines changed

22 files changed

+417
-95
lines changed

recipes/ExtraMojo/recipe.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
context:
2-
version: "0.12.0"
2+
version: "0.13.0"
33

44
package:
55
name: "extramojo"
66
version: ${{ version }}
77

88
source:
99
- git: https://github.com/ExtraMojo/ExtraMojo.git
10-
rev: 25b6a6e7089138ab93f99d79401c57c8174c38ee
10+
rev: 97c9151d968206581cfd8a1d626c2e5d519046e5
1111

1212
build:
1313
number: 0

recipes/ExtraMojo/tests/test_bstr.mojo

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ from ExtraMojo.bstr.bstr import (
55
to_ascii_uppercase,
66
)
77
from ExtraMojo.bstr.memchr import memchr, memchr_wide
8-
from memory import Span
98
from testing import *
109

1110

@@ -28,30 +27,36 @@ fn s(bytes: Span[UInt8]) -> String:
2827

2928

3029
fn test_memchr() raises:
31-
var cases = List[(StringLiteral, Int)](
32-
(
33-
"enlivened,unleavened,Arnulfo's,Unilever's,unloved|Anouilh,analogue,analogy",
34-
49,
35-
),
36-
(
37-
"enlivened,unleavened,Arnulfo's,Unilever's,unloved,Anouilh,analogue,analogy,enlivened,unleavened,Arnulfo's,Unilever's,unloved|Anouilh,analogue,analogy",
38-
124,
39-
),
40-
)
41-
42-
for kase in cases:
43-
var index = memchr(kase[][0].as_bytes(), ord("|"))
44-
assert_equal(
45-
index,
46-
kase[][1],
47-
"Expected "
48-
+ String(kase[][1])
49-
+ " Found "
50-
+ String(index)
51-
+ " in "
52-
+ kase[][0],
30+
alias check = InlineArray[Bool, 2](True, False)
31+
32+
@parameter
33+
for do_alignment in range(0, len(check)):
34+
var cases = List[(StringLiteral, Int)](
35+
(
36+
"enlivened,unleavened,Arnulfo's,Unilever's,unloved|Anouilh,analogue,analogy",
37+
49,
38+
),
39+
(
40+
"enlivened,unleavened,Arnulfo's,Unilever's,unloved,Anouilh,analogue,analogy,enlivened,unleavened,Arnulfo's,Unilever's,unloved|Anouilh,analogue,analogy",
41+
124,
42+
),
5343
)
5444

45+
for kase in cases:
46+
var index = memchr[do_alignment = check[do_alignment]](
47+
kase[][0].as_bytes(), ord("|")
48+
)
49+
assert_equal(
50+
index,
51+
kase[][1],
52+
"Expected "
53+
+ String(kase[][1])
54+
+ " Found "
55+
+ String(index)
56+
+ " in "
57+
+ kase[][0],
58+
)
59+
5560

5661
fn test_memchr_wide() raises:
5762
var cases = List[(StringLiteral, Int)](

recipes/ExtraMojo/tests/test_file.mojo

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
from collections import Optional, Dict
1+
from collections import Dict
22
from utils import StringSlice
3-
from memory import Span
43
from pathlib import Path
54
from python import Python
65
from tensor import Tensor

recipes/bridge/README.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,33 @@
66

77
This package acts as a bridge between Mojo native types and those from the Python world.
88

9-
Example usage, to convert a NumPy array to a Mojo tensor:
9+
Example usage, to convert a NumPy array to a Mojo `LayoutTensor` or `Tensor`:
1010
```mojo
1111
from python import Python
12-
from bridge.numpy import ndarray_to_tensor
12+
from bridge.numpy import ndarray_to_layouttensor, ndarray_to_tensor
1313
1414
var np = Python.import_module("numpy")
1515
np_array = np.arange(6.0).reshape(2,3)
16-
mojo_tensor = ndarray_to_tensor[DType.float64](np_array)
16+
17+
# Convert to new-style `LayoutTensor`.
18+
mojo_tensor = ndarray_to_layouttensor[order=2](np_array)
19+
20+
# Convert to old-style `Tensor`.
21+
mojo_oldtensor = ndarray_to_tensor[DType.float64](np_array)
1722
```
1823
Or to achieve the reverse:
1924
```mojo
2025
from tensor import Tensor
2126
22-
from bridge.numpy import tensor_to_ndarray
27+
from bridge.numpy import layouttensor_to_ndarray, tensor_to_ndarray
28+
29+
# Convert new-style `LayoutTensor` to numpy array.
30+
np_array = layouttensor_to_ndarray(mojo_tensor)
2331
32+
# Convert old-style `Tensor` to numpy array.
2433
values = List[Float64](0.0, 1.0, 2.0, 3.0, 4.0, 5.0)
25-
mojo_tensor = Tensor[DType.float64](shape=(2, 3), list=values)
26-
np_array = tensor_to_ndarray(mojo_tensor)
34+
mojo_oldtensor = Tensor[DType.float64](shape=(2, 3), list=values)
35+
np_array = tensor_to_ndarray(mojo_oldtensor)
2736
```
2837

2938
# Installation

recipes/bridge/recipe.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
context:
2-
version: "0.1.0"
2+
version: "0.2.0"
33

44
package:
55
name: "bridge"
66
version: ${{ version }}
77

88
source:
99
- git: https://gitlab.com/hylkedonker/bridge.git
10-
rev: dc89432cb79b6eeef42e1755593ea3837c48d7dd
10+
rev: 87f10144b004ff4ef8e73d6b8b52e3f81effd40f
1111

1212
build:
1313
number: 0
1414
script:
1515
- mojo package src/bridge -o ${{ PREFIX }}/lib/mojo/bridge.mojopkg
1616
requirements:
1717
host:
18-
- max=25.1
18+
- max=25.2
1919
run:
2020
- ${{ pin_compatible('max') }}
2121

recipes/bridge/test_numpy.🔥

Lines changed: 104 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
from python import Python
2-
from tensor import Tensor, rand
3-
from testing import assert_true, assert_equal
2+
from layout import Layout, LayoutTensor
3+
from tensor import Tensor
4+
from testing import assert_equal, assert_raises, assert_true
45

5-
from bridge.numpy import ndarray_to_tensor, tensor_to_ndarray
6+
from bridge.numpy import (
7+
layouttensor_to_ndarray,
8+
ndarray_to_layouttensor,
9+
ndarray_to_tensor,
10+
tensor_to_ndarray,
11+
)
612

713

814
def test_tensor_identity_transformation():
@@ -14,10 +20,104 @@ def test_tensor_identity_transformation():
1420
assert_equal(in_matrix, out_matrix)
1521

1622

17-
def test_numpy_identity_transformation():
23+
def test_numpy_tensor_identity_transformation():
1824
"""Test that `tensor_to_ndarray` is inverse of `ndarray_to_tensor`."""
1925
var np = Python.import_module("numpy")
2026
var in_array = np.arange(6).reshape(3, 2)
2127
var tensor = ndarray_to_tensor[DType.float64](in_array)
2228
var out_array = tensor_to_ndarray(tensor)
2329
assert_equal(in_array, out_array)
30+
31+
32+
def test_ndarray_to_layouttensor():
33+
"""Test numpy array conversion to layouttensor for various tensor shapes."""
34+
var np = Python.import_module("numpy")
35+
36+
# 1) Test vectors
37+
var in_vector = np.arange(4.0)
38+
var out_vector = ndarray_to_layouttensor[order=1](in_vector)
39+
assert_equal(out_vector[1], 1.0)
40+
assert_equal(out_vector[3], 3.0)
41+
42+
# 2) Test matrices
43+
var in_matrix = np.arange(4.0 * 3.0).reshape(3, 4)
44+
var out_matrix = ndarray_to_layouttensor[order=2](in_matrix)
45+
assert_equal(out_matrix[0, 0], 0.0)
46+
assert_equal(out_matrix[1, 1], 5.0)
47+
assert_equal(out_matrix[1, 3], 7.0)
48+
assert_equal(out_matrix[2, 1], 9.0)
49+
50+
# Check that non-contiguous arrays raise exceptions.
51+
with assert_raises():
52+
var in_matrix_col_major = np.asfortranarray(in_matrix)
53+
_ = ndarray_to_layouttensor[order=2](in_matrix_col_major)
54+
55+
# 3) Test three-index tensors
56+
var in_tensor = np.arange(4.0 * 3.0).reshape(3, 1, 4)
57+
var out_tensor = ndarray_to_layouttensor[order=3](in_tensor)
58+
assert_equal(out_tensor[0, 0, 0], 0.0)
59+
assert_equal(out_tensor[1, 0, 1], 5.0)
60+
assert_equal(out_tensor[1, 0, 3], 7.0)
61+
assert_equal(out_tensor[2, 0, 1], 9.0)
62+
63+
# 3) Test four-index tensors
64+
var in_4tensor = np.arange(4.0 * 3.0).reshape(2, 3, 1, 2)
65+
var out_4tensor = ndarray_to_layouttensor[order=4](in_4tensor)
66+
assert_equal(out_4tensor[0, 0, 0, 0], 0.0)
67+
assert_equal(out_4tensor[0, 1, 0, 1], 3.0)
68+
assert_equal(out_4tensor[1, 0, 0, 1], 7.0)
69+
assert_equal(out_4tensor[0, 2, 0, 0], 4.0)
70+
71+
72+
def test_memory_leaks():
73+
"""Test that we can safely remove the reference to the numpy array."""
74+
var np = Python.import_module("numpy")
75+
var np_array = np.arange(6.0).reshape(3, 2)
76+
var tensor = ndarray_to_layouttensor[order=2](np_array)
77+
np_array.__del__()
78+
assert_equal(tensor[1, 0], 2.0)
79+
assert_equal(tensor[1, 1], 3.0)
80+
assert_equal(tensor[2, 1], 5.0)
81+
82+
83+
# def test_layouttensor_numpy_identity_transformation():
84+
# """Test that `layouttensor_to_ndarray` is inverse of `ndarray_to_layouttensor`.
85+
# """
86+
# values = List[Float64](0.0, 1.0, 2.0, 3.0, 4.0, 5.0)
87+
# tensor = Tensor[DType.float64](shape=(2, 3), list=values)
88+
# var ptr = tensor.unsafe_ptr()
89+
# layouttensor = LayoutTensor[
90+
# mut=False,
91+
# DType.float64,
92+
# Layout.row_major(2, 3),
93+
# __origin_of(ptr[]),
94+
# ](ptr=ptr)
95+
# np_array = layouttensor_to_ndarray(layouttensor)
96+
# out_layouttensor = ndarray_to_layouttensor[order=2](in_array)
97+
98+
99+
def test_numpy_layouttensor_identity_transformation():
100+
"""Test that `ndarray_to_layouttensor` is the inverse of `layouttensor_to_ndarray`.
101+
"""
102+
var np = Python.import_module("numpy")
103+
104+
# 1) Test vectors
105+
# TODO: Add support for vectors!
106+
107+
# 2) Test matrices
108+
var in_matrix = np.arange(4.0 * 3.0).reshape(3, 4)
109+
var layout_matrix = ndarray_to_layouttensor[order=2](in_matrix)
110+
var out_matrix = layouttensor_to_ndarray(layout_matrix)
111+
np.testing.assert_array_equal(in_matrix, out_matrix)
112+
113+
# 3) Test three-index tensors
114+
var in_tensor = np.arange(4.0 * 3.0).reshape(3, 1, 4)
115+
var layout_tensor = ndarray_to_layouttensor[order=3](in_tensor)
116+
var out_tensor = layouttensor_to_ndarray(layout_tensor)
117+
np.testing.assert_array_equal(in_tensor, out_tensor)
118+
119+
# 3) Test four-index tensors
120+
var in_4tensor = np.arange(4.0 * 3.0).reshape(2, 3, 1, 2)
121+
var layout_4tensor = ndarray_to_layouttensor[order=4](in_4tensor)
122+
var out_4tensor = layouttensor_to_ndarray(layout_4tensor)
123+
np.testing.assert_array_equal(in_4tensor, out_4tensor)

0 commit comments

Comments
 (0)