Skip to content

Commit de402e6

Browse files
committed
[Backend Tester] Add pointwise op tests
ghstack-source-id: 725e60f ghstack-comment-id: 3116316934 Pull-Request: #12854
1 parent 1a4e6de commit de402e6

File tree

8 files changed

+1093
-0
lines changed

8 files changed

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

0 commit comments

Comments
 (0)