已合并
test: add ShapeEnv API alignment tests for symbolic_shapes #38160
test: add ShapeEnv API alignment tests for symbolic_shapes #38160
已合并
liuhaodong-2026创建于 6月10日
1 个文件变更+102-0
Atest/fx/test_shape_env_apis.py+102-0
@@ -0,0 +1,102 @@
1+"""
2+Add validation cases for torch.fx.experimental.symbolic_shapes.ShapeEnv APIs on NPU:
3+1. PyTorch community lacks sufficient and direct API validations for these ShapeEnv
4+ symbolic expression methods, so this file is added.
5+2. This file validates ShapeEnv.deserialize_symexpr, ShapeEnv.evaluate_symexpr,
6+ ShapeEnv.evaluate_guards_expression, ShapeEnv.evaluate_guards_for_args,
7+ ShapeEnv.evaluate_sym_node (extendable).
8+"""
9+ 
10+import torch
11+from torch._dynamo.source import LocalSource, TensorProperty, TensorPropertySource
12+from torch._subclasses.fake_tensor import FakeTensorMode
13+from torch.fx.experimental.symbolic_shapes import DimDynamic, ShapeEnv
14+from torch.testing._internal.common_utils import run_tests, TestCase
15+ 
16+device_type = acc.type if (acc := torch.accelerator.current_accelerator()) else "cpu"
17+ 
18+ 
19+class TestShapeEnvAPIs(TestCase):
20+ 
21+ def test_deserialize_symexpr_constant(self):
22+ env = ShapeEnv()
23+ self.assertEqual(int(env.deserialize_symexpr("5")), 5)
24+ 
25+ def test_deserialize_symexpr_expression(self):
26+ env = ShapeEnv()
27+ self.assertEqual(int(env.deserialize_symexpr("2 + 3")), 5)
28+ 
29+ def test_deserialize_symexpr_with_symbol(self):
30+ env = ShapeEnv()
31+ source = TensorPropertySource(LocalSource("x"), TensorProperty.SIZE, 0)
32+ s = env.create_symbol(5, source=source, dynamic_dim=DimDynamic.DYNAMIC)
33+ self.assertEqual(str(env.deserialize_symexpr(str(s))), str(s))
34+ 
35+ def test_evaluate_symexpr_constant(self):
36+ env = ShapeEnv()
37+ self.assertEqual(env.evaluate_symexpr("10"), 10)
38+ 
39+ def test_evaluate_symexpr_addition(self):
40+ env = ShapeEnv()
41+ self.assertEqual(env.evaluate_symexpr("3 + 4"), 7)
42+ 
43+ def test_evaluate_symexpr_multiplication(self):
44+ env = ShapeEnv()
45+ self.assertEqual(env.evaluate_symexpr("6 * 7"), 42)
46+ 
47+ def test_evaluate_guards_expression_true(self):
48+ env = ShapeEnv()
49+ self.assertTrue(env.evaluate_guards_expression("True", []))
50+ 
51+ def test_evaluate_guards_expression_false(self):
52+ env = ShapeEnv()
53+ self.assertFalse(env.evaluate_guards_expression("False", []))
54+ 
55+ def test_evaluate_guards_expression_returns_bool(self):
56+ env = ShapeEnv()
57+ self.assertIsInstance(env.evaluate_guards_expression("True", []), bool)
58+ 
59+ def test_evaluate_guards_for_args_basic(self):
60+ env = ShapeEnv()
61+ fake_mode = FakeTensorMode(shape_env=env, allow_non_fake_inputs=True)
62+ with fake_mode:
63+ placeholder = torch.empty(3, 4)
64+ real_tensor = torch.randn(3, 4).to(device_type)
65+ result = env.evaluate_guards_for_args([placeholder], [real_tensor])
66+ self.assertIsInstance(result, bool)
67+ 
68+ def test_evaluate_guards_for_args_multi_placeholders(self):
69+ env = ShapeEnv()
70+ fake_mode = FakeTensorMode(shape_env=env, allow_non_fake_inputs=True)
71+ with fake_mode:
72+ p0 = torch.empty(3, 4)
73+ p1 = torch.empty(5, 6)
74+ real0 = torch.randn(3, 4).to(device_type)
75+ real1 = torch.randn(5, 6).to(device_type)
76+ result = env.evaluate_guards_for_args([p0, p1], [real0, real1])
77+ self.assertIsInstance(result, bool)
78+ 
79+ def test_evaluate_sym_node_basic(self):
80+ env = ShapeEnv()
81+ source = TensorPropertySource(LocalSource("x"), TensorProperty.SIZE, 0)
82+ s = env.create_symbol(5, source=source, dynamic_dim=DimDynamic.DYNAMIC)
83+ sym = env.create_symintnode(s, hint=5, source=source)
84+ self.assertEqual(env.evaluate_sym_node(sym.node, size_oblivious=False), 5)
85+ 
86+ def test_evaluate_sym_node_size_oblivious(self):
87+ env = ShapeEnv()
88+ source = TensorPropertySource(LocalSource("x"), TensorProperty.SIZE, 0)
89+ s = env.create_symbol(5, source=source, dynamic_dim=DimDynamic.DYNAMIC)
90+ sym = env.create_symintnode(s, hint=5, source=source)
91+ self.assertEqual(env.evaluate_sym_node(sym.node, size_oblivious=True), 5)
92+ 
93+ def test_evaluate_sym_node_different_hint(self):
94+ env = ShapeEnv()
95+ source = TensorPropertySource(LocalSource("y"), TensorProperty.SIZE, 0)
96+ s = env.create_symbol(7, source=source, dynamic_dim=DimDynamic.DYNAMIC)
97+ sym = env.create_symintnode(s, hint=7, source=source)
98+ self.assertEqual(env.evaluate_sym_node(sym.node, size_oblivious=False), 7)
99+ 
100+ 
101+if __name__ == "__main__":
102+ run_tests()