Skip to content

Commit 3a7df18

Browse files
authored
[Backend Tester] Add pointwise op tests (#12854)
Add tests for various element-wise ops.
1 parent a7d65c7 commit 3a7df18

File tree

8 files changed

+797
-0
lines changed

8 files changed

+797
-0
lines changed
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
# pyre-unsafe
8+
9+
import torch
10+
from executorch.backends.test.suite.flow import TestFlow
11+
12+
from executorch.backends.test.suite.operators import (
13+
dtype_test,
14+
operator_test,
15+
OperatorTest,
16+
)
17+
18+
19+
class FloorDivideModel(torch.nn.Module):
20+
def __init__(self):
21+
super().__init__()
22+
23+
def forward(self, x, y):
24+
return torch.floor_divide(x, y)
25+
26+
27+
@operator_test
28+
class TestFloorDivide(OperatorTest):
29+
@dtype_test
30+
def test_floor_divide_dtype(self, flow: TestFlow, dtype) -> None:
31+
# Test with different dtypes
32+
model = FloorDivideModel().to(dtype)
33+
# Use values that won't cause division by zero
34+
x = torch.randint(-100, 100, (10, 10)).to(dtype)
35+
y = torch.full_like(x, 2) # Divisor of 2
36+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
37+
38+
def test_floor_divide_scalar_divisors(self, flow: TestFlow) -> None:
39+
# Test with different scalar divisors as tensors
40+
41+
# Positive divisor
42+
x = torch.randint(-100, 100, (10, 10))
43+
y = torch.full_like(x, 3) # Divisor of 3
44+
self._test_op(
45+
FloorDivideModel(), (x, y), flow, generate_random_test_inputs=False
46+
)
47+
48+
# Negative divisor
49+
x = torch.randint(-100, 100, (10, 10))
50+
y = torch.full_like(x, -2) # Divisor of -2
51+
self._test_op(
52+
FloorDivideModel(), (x, y), flow, generate_random_test_inputs=False
53+
)
54+
55+
# Fractional divisor
56+
x = torch.randint(-100, 100, (10, 10)).float()
57+
y = torch.full_like(x, 2.5) # Divisor of 2.5
58+
self._test_op(
59+
FloorDivideModel(), (x, y), flow, generate_random_test_inputs=False
60+
)
61+
62+
# Large divisor
63+
x = torch.randint(-1000, 1000, (10, 10))
64+
y = torch.full_like(x, 100) # Divisor of 100
65+
self._test_op(
66+
FloorDivideModel(), (x, y), flow, generate_random_test_inputs=False
67+
)
68+
69+
# Small divisor
70+
x = torch.randint(-100, 100, (10, 10)).float()
71+
y = torch.full_like(x, 0.5) # Divisor of 0.5
72+
self._test_op(
73+
FloorDivideModel(), (x, y), flow, generate_random_test_inputs=False
74+
)
75+
76+
def test_floor_divide_tensor_divisors(self, flow: TestFlow) -> None:
77+
# Test with tensor divisors
78+
79+
# Constant divisor tensor
80+
x = torch.randint(-100, 100, (10, 10))
81+
y = torch.full_like(x, 2) # All elements are 2
82+
self._test_op(
83+
FloorDivideModel(), (x, y), flow, generate_random_test_inputs=False
84+
)
85+
86+
# Random divisor tensor (non-zero)
87+
x = torch.randint(-100, 100, (10, 10))
88+
y = torch.randint(1, 10, (10, 10)) # Positive divisors
89+
self._test_op(
90+
FloorDivideModel(), (x, y), flow, generate_random_test_inputs=False
91+
)
92+
93+
# Mixed positive and negative divisors
94+
x = torch.randint(-100, 100, (10, 10))
95+
y = torch.randint(-10, 10, (10, 10))
96+
# Replace zeros to avoid division by zero
97+
y[y == 0] = 1
98+
self._test_op(
99+
FloorDivideModel(), (x, y), flow, generate_random_test_inputs=False
100+
)
101+
102+
# Broadcasting: scalar dividend, tensor divisor
103+
x = torch.tensor([10])
104+
y = torch.arange(1, 5) # [1, 2, 3, 4]
105+
self._test_op(
106+
FloorDivideModel(), (x, y), flow, generate_random_test_inputs=False
107+
)
108+
109+
# Broadcasting: tensor dividend, scalar divisor
110+
x = torch.arange(-10, 10)
111+
y = torch.tensor([2])
112+
self._test_op(
113+
FloorDivideModel(), (x, y), flow, generate_random_test_inputs=False
114+
)
115+
116+
def test_floor_divide_shapes(self, flow: TestFlow) -> None:
117+
# Test with different tensor shapes
118+
model = FloorDivideModel()
119+
120+
# 1D tensor
121+
x = torch.randint(-100, 100, (20,))
122+
y = torch.full_like(x, 2) # Divisor of 2
123+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
124+
125+
# 2D tensor
126+
x = torch.randint(-100, 100, (5, 10))
127+
y = torch.full_like(x, 2) # Divisor of 2
128+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
129+
130+
# 3D tensor
131+
x = torch.randint(-100, 100, (3, 4, 5))
132+
y = torch.full_like(x, 2) # Divisor of 2
133+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
134+
135+
# 4D tensor
136+
x = torch.randint(-100, 100, (2, 3, 4, 5))
137+
y = torch.full_like(x, 2) # Divisor of 2
138+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
139+
140+
# 5D tensor
141+
x = torch.randint(-100, 100, (2, 2, 3, 4, 5))
142+
y = torch.full_like(x, 2) # Divisor of 2
143+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
144+
145+
def test_floor_divide_values(self, flow: TestFlow) -> None:
146+
# Test with different value ranges
147+
model = FloorDivideModel()
148+
149+
# Test with specific dividend values
150+
x = torch.tensor([-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7])
151+
152+
# Divide by 2
153+
y = torch.tensor([2]).expand_as(x).clone()
154+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
155+
156+
# Divide by -2
157+
y = torch.tensor([-2]).expand_as(x).clone()
158+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
159+
160+
# Divide by 3
161+
y = torch.tensor([3]).expand_as(x).clone()
162+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
163+
164+
# Divide by -3
165+
y = torch.tensor([-3]).expand_as(x).clone()
166+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
167+
168+
# Test with floating point values
169+
x = torch.tensor(
170+
[-3.8, -3.5, -3.2, -0.8, -0.5, -0.2, 0.0, 0.2, 0.5, 0.8, 3.2, 3.5, 3.8]
171+
)
172+
173+
# Divide by 2.0
174+
y = torch.tensor([2.0]).expand_as(x).clone()
175+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
176+
177+
# Divide by -2.0
178+
y = torch.tensor([-2.0]).expand_as(x).clone()
179+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
180+
181+
def test_floor_divide_edge_cases(self, flow: TestFlow) -> None:
182+
# Test edge cases
183+
model = FloorDivideModel()
184+
185+
# Zero dividend
186+
x = torch.zeros(10)
187+
y = torch.full_like(x, 2)
188+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
189+
190+
# Division with remainder
191+
x = torch.tensor([1, 3, 5, 7, 9])
192+
y = torch.full_like(x, 2)
193+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
194+
195+
# Tensor with infinity
196+
x = torch.tensor([float("inf"), float("-inf"), 10.0, -10.0])
197+
y = torch.full_like(x, 2)
198+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
199+
200+
# Tensor with NaN
201+
x = torch.tensor([float("nan"), 10.0, -10.0])
202+
y = torch.full_like(x, 2)
203+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
204+
205+
# Very large values
206+
x = torch.tensor([1e10, -1e10])
207+
y = torch.full_like(x, 3)
208+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
209+
210+
# Very small values
211+
x = torch.tensor([1e-10, -1e-10])
212+
y = torch.full_like(x, 2)
213+
self._test_op(model, (x, y), flow, generate_random_test_inputs=False)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
# pyre-unsafe
8+
9+
import torch
10+
from executorch.backends.test.suite.flow import TestFlow
11+
12+
from executorch.backends.test.suite.operators import (
13+
dtype_test,
14+
operator_test,
15+
OperatorTest,
16+
)
17+
18+
19+
class NegModel(torch.nn.Module):
20+
def __init__(self):
21+
super().__init__()
22+
23+
def forward(self, x):
24+
return torch.neg(x)
25+
26+
27+
@operator_test
28+
class TestNeg(OperatorTest):
29+
@dtype_test
30+
def test_neg_dtype(self, flow: TestFlow, dtype) -> None:
31+
# Test with different dtypes
32+
model = NegModel().to(dtype)
33+
self._test_op(
34+
model,
35+
(torch.rand(10, 10).to(dtype) * 2 - 1,),
36+
flow,
37+
generate_random_test_inputs=False,
38+
)
39+
40+
def test_neg_shapes(self, flow: TestFlow) -> None:
41+
# Test with different tensor shapes
42+
43+
# 1D tensor
44+
self._test_op(
45+
NegModel(), (torch.randn(20),), flow, generate_random_test_inputs=False
46+
)
47+
48+
# 2D tensor
49+
self._test_op(
50+
NegModel(), (torch.randn(5, 10),), flow, generate_random_test_inputs=False
51+
)
52+
53+
# 3D tensor
54+
self._test_op(
55+
NegModel(), (torch.randn(3, 4, 5),), flow, generate_random_test_inputs=False
56+
)
57+
58+
def test_neg_edge_cases(self, flow: TestFlow) -> None:
59+
# Test edge cases
60+
61+
# Tensor with infinity
62+
x = torch.tensor([float("inf"), float("-inf"), 1.0, -1.0])
63+
self._test_op(NegModel(), (x,), flow, generate_random_test_inputs=False)
64+
65+
# Tensor with NaN
66+
x = torch.tensor([float("nan"), 1.0, -1.0])
67+
self._test_op(NegModel(), (x,), flow, generate_random_test_inputs=False)

0 commit comments

Comments
 (0)