Skip to content

Commit 330d2ac

Browse files
committed
Fix bracketing issue in frontend GOID - cursor assisted testing
1 parent ed9c29e commit 330d2ac

7 files changed

Lines changed: 187 additions & 121 deletions

File tree

frontend/catalyst/decomposition/type_utils.py

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
}
3737

3838
_PY_DTYPES_TO_MLIR_DTYPES = {v: k for k, v in _MLIR_DTYPES_TO_PY_DTYPES.items()} | {
39+
float: "f64",
40+
int: "i64",
41+
complex: "complex<f64>",
3942
(ir.IntegerType, 1): "i1",
4043
(ir.IntegerType, 8): "i8",
4144
(ir.IntegerType, 16): "i16",
@@ -78,30 +81,32 @@ def convert_types_to_mlir_strings(d: dict) -> dict:
7881
"""Convert the values of a dictionary to MLIR type strings."""
7982

8083
def handle_item(item):
81-
if isinstance(item, type):
82-
if item in _PY_DTYPES_TO_MLIR_DTYPES:
84+
match item:
85+
case str():
86+
return item
87+
case type():
8388
return _PY_DTYPES_TO_MLIR_DTYPES[item]
84-
raise TypeError(
85-
f"encountered unknown type {type(item)} of item {item} when converting to mlir strings."
86-
)
87-
elif type(item) in _PY_DTYPES_TO_MLIR_DTYPES:
88-
return _PY_DTYPES_TO_MLIR_DTYPES[type(item)]
89-
elif isinstance(item, str):
90-
return item
91-
elif isinstance(item, (list, tuple)):
92-
return [handle_item(i) for i in item]
93-
elif isinstance(item, (ShapedArray, qp.typing.AbstractArray)):
94-
if item.shape == ():
95-
return [_PY_DTYPES_TO_MLIR_DTYPES[item.dtype.type]]
96-
return convert_shaped_type_to_mlir_string(item)
97-
elif isinstance(item, ir.RankedTensorType):
98-
if len(item.shape) == 0:
99-
return [_PY_DTYPES_TO_MLIR_DTYPES[get_mlir_tensor_type_map_key(item.element_type)]]
100-
return convert_shaped_type_to_mlir_string(item)
101-
else:
102-
raise TypeError(
103-
f"encountered unknown type {type(item)} of item {item} when converting to mlir strings."
104-
)
89+
case ir.RankedTensorType():
90+
if len(item.shape) == 0:
91+
return [
92+
_PY_DTYPES_TO_MLIR_DTYPES[get_mlir_tensor_type_map_key(item.element_type)]
93+
]
94+
return convert_shaped_type_to_mlir_string(item)
95+
case float() | int() | complex():
96+
# these need to be wrapped in an additional list to account for the tensor creation in lowering
97+
return [_PY_DTYPES_TO_MLIR_DTYPES[type(item)]]
98+
case list() | tuple():
99+
return [handle_item(i) for i in item]
100+
case ShapedArray() | qp.typing.AbstractArray():
101+
if item.shape == ():
102+
return [_PY_DTYPES_TO_MLIR_DTYPES[item.dtype.type]]
103+
return convert_shaped_type_to_mlir_string(item)
104+
case _ if type(item) in _PY_DTYPES_TO_MLIR_DTYPES:
105+
return _PY_DTYPES_TO_MLIR_DTYPES[type(item)]
106+
case _:
107+
raise TypeError(
108+
f"encountered unknown type {type(item)} of item {item} when converting to mlir strings."
109+
)
105110

106111
return {k: handle_item(v) for k, v in d.items()}
107112

@@ -110,12 +115,19 @@ def format_dynamic_params_for_id(d):
110115
"""Format a structure for ID, after calling convert_types_to_mlir_string on it."""
111116

112117
def handle_item(item):
113-
if isinstance(item, str):
114-
return item
115-
elif isinstance(item, list):
116-
return "[" + ",".join(handle_item(i) for i in item) + "]"
118+
match item:
119+
case str():
120+
return item
121+
case list() | tuple():
122+
return "[" + ",".join(handle_item(i) for i in item) + "]"
117123

118-
return "{" + ",".join(k + ":" + handle_item(v) for k, v in d.items()) + "}"
124+
return (
125+
"{"
126+
+ ",".join(
127+
k + ":" + "[" + ",".join(handle_item(item) for item in v) + "]" for k, v in d.items()
128+
)
129+
+ "}"
130+
)
119131

120132

121133
def get_dummy_values_for_arg(arg):
@@ -127,21 +139,20 @@ def get_dummy_values_for_arg(arg):
127139
Ex.
128140
[[float, float], [int, int, int], [int32, int32, int32, int32]]
129141
"""
130-
if isinstance(arg, str):
131-
return jnp.zeros((), dtype=_MLIR_DTYPES_TO_PY_DTYPES[arg])
132-
elif isinstance(arg, (list, tuple)):
133-
dtype = get_dummy_values_for_arg(arg[0]).dtype
134-
# NOTE: numpy is required since jax won't create an array of strings
135-
return jnp.zeros(np.array(arg, str).shape, dtype)
136-
elif isinstance(arg, ShapedArray):
137-
return jnp.zeros(arg.shape[0], dtype=arg.dtype)
138-
elif isinstance(arg, str):
139-
return jnp.zeros((), dtype=_MLIR_DTYPES_TO_PY_DTYPES[arg])
140-
elif isinstance(arg, (type, jnp.dtype)):
141-
try:
142-
return jnp.zeros((), jnp.dtype(arg))
143-
except TypeError:
144-
pass
142+
match arg:
143+
case str():
144+
return jnp.zeros((), dtype=_MLIR_DTYPES_TO_PY_DTYPES[arg])
145+
case list() | tuple():
146+
dtype = get_dummy_values_for_arg(arg[0]).dtype
147+
# NOTE: numpy is required since jax won't create an array of strings
148+
return jnp.zeros(np.array(arg, str).shape, dtype)
149+
case ShapedArray():
150+
return jnp.zeros(arg.shape[0], dtype=arg.dtype)
151+
case type() | jnp.dtype():
152+
try:
153+
return jnp.zeros((), jnp.dtype(arg))
154+
except TypeError:
155+
pass
145156

146157
raise TypeError(f"Unexpected type in container when creating dummy values: {type(arg)}")
147158

frontend/catalyst/from_plxpr/qref_operator2_primitives.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ def _process_params(
170170
args_idx += hsize
171171

172172
param_map = get_mlir_attribute_from_pyval(param_map) if param_map else None
173+
for param in params:
174+
assert isinstance(param.type, ir.RankedTensorType)
173175
return params, forward_params, param_map
174176

175177

frontend/test/lit/test_operator2/test_decomposition_rule_entry_point.py

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ def rule(reg):
7474

7575
# CHECK: func.func private @"rule_NoParams{}{reg:2}{}"
7676
# CHECK-SAME: resources = {operations = {
77-
# CHECK-SAME: "SingleParam{x:[f64,f64]}{reg:2}{}" = 1 : i64,
78-
# CHECK-SAME: "SingleParam{x:[f64]}{reg:2}{}" = 2 : i64
77+
# CHECK-SAME: "SingleParam{x:{{\[\[f64,f64\]\]}}}{reg:2}{}" = 1 : i64,
78+
# CHECK-SAME: "SingleParam{x:{{\[\[f64\]\]}}}{reg:2}{}" = 2 : i64
7979
# CHECK-SAME: target_gate = "NoParams{}{reg:2}{}"
8080
test_to_dynamic_argnames()
8181

@@ -96,17 +96,17 @@ def rule(x, reg):
9696
qp.add_decomps(SingleParam, rule)
9797
result = compile_decomposition_rules_wrapper(
9898
"SingleParam",
99-
"SingleParam{x:[f64,f64]}{reg:2}{}",
99+
"SingleParam{x:[[f64,f64]]}{reg:2}{}",
100100
{"x": ["f64", "f64"]},
101101
{"reg": 2},
102102
{},
103103
)
104104
print(result)
105105

106106

107-
# CHECK: func.func private @"rule_SingleParam{x:[f64,f64]}{reg:2}{}"
107+
# CHECK: func.func private @"rule_SingleParam{x:{{\[\[f64,f64\]\]}}}{reg:2}{}"
108108
# CHECK-SAME: resources = {operations = {"NoParams{}{reg:1}{}" = 1 : i64}}
109-
# CHECK-SAME: target_gate = "SingleParam{x:[f64,f64]}{reg:2}{}"
109+
# CHECK-SAME: target_gate = "SingleParam{x:{{\[\[f64,f64\]\]}}}{reg:2}{}"
110110
test_from_dynamic_argnames()
111111

112112

@@ -134,7 +134,7 @@ def rule(reg):
134134

135135
# CHECK: func.func private @"rule_NoParams{}{reg:1}{}"
136136
# CHECK-SAME: resources = {operations =
137-
# CHECK-SAME: "MultiParams{a:[f64],b:{{\[\[}}i64,i64],[i64,i64{{\]\]}},c:[complex<f64>]}{reg:1}{}" = 1 : i64
137+
# CHECK-SAME: "MultiParams{a:{{\[\[f64\]\]}},b:{{\[\[\[i64,i64\],\[i64,i64\]\]\]}},c:{{\[\[complex<f64>\]\]}}}{reg:1}{}" = 1 : i64
138138
# CHECK-SAME: target_gate = "NoParams{}{reg:1}{}"
139139
test_to_multiple_dynamic_argnames()
140140

@@ -155,17 +155,17 @@ def rule(reg, a, b, c):
155155
qp.add_decomps(MultiParams, rule)
156156
result = compile_decomposition_rules_wrapper(
157157
"MultiParams",
158-
"MultiParams{a:[f64],b:[i32,f64],c:[[i32],[f64]]}{reg:2}{}",
158+
"MultiParams{a:[[f64]],b:[[i32,f64]],c:[[[i32],[f64]]]}{reg:2}{}",
159159
{"b": ["i32", "f64"], "c": [["i32"], ["f64"]], "a": ["f64"]},
160160
{"reg": 2},
161161
{},
162162
)
163163
print(result)
164164

165165

166-
# CHECK: func.func private @"rule_MultiParams{a:[f64],b:[i32,f64],c:{{\[\[}}i32],[f64{{\]\]}}}{reg:2}{}"
166+
# CHECK: func.func private @"rule_MultiParams{a:{{\[\[f64\]\]}},b:{{\[\[i32,f64\]\]}},c:{{\[\[\[i32\],\[f64\]\]\]}}}{reg:2}{}"
167167
# CHECK-SAME: resources = {operations = {"NoParamsCustomOp{}{wires:2}{}" = 1 : i64}
168-
# CHECK-SAME: target_gate = "MultiParams{a:[f64],b:[i32,f64],c:{{\[\[}}i32],[f64{{\]\]}}}{reg:2}{}"
168+
# CHECK-SAME: target_gate = "MultiParams{a:{{\[\[f64\]\]}},b:{{\[\[i32,f64\]\]}},c:{{\[\[\[i32\],\[f64\]\]\]}}}{reg:2}{}"
169169
test_from_multiple_dynamic_argnames()
170170

171171

@@ -301,13 +301,13 @@ def rule(a, b, thing, wires):
301301

302302

303303
# CHECK: func.func private @"rule_CompilableData{}{wires:1}{a:1,b:2,thing:3}"
304-
# CHECK-SAME: resources = {operations = {"SingleParam{x:[f64]}{reg:1}{}" = 1 : i64}
304+
# CHECK-SAME: resources = {operations = {"SingleParam{x:{{\[\[f64\]\]}}}{reg:1}{}" = 1 : i64}
305305
# CHECK-SAME: target_gate = "CompilableData{}{wires:1}{a:1,b:2,thing:3}"
306306
# CHECK: stablehlo.constant dense<1.000000e-01> : tensor<f64>
307307
# CHECK-NOT: stablehlo.constant dense<1.100000e+00> : tensor<f64>
308308
#
309309
# CHECK: func.func private @"rule_CompilableData{}{wires:1}{a:10,b:2,thing:3}"
310-
# CHECK-SAME: resources = {operations = {"SingleParam{x:[f64]}{reg:1}{}" = 1 : i64}
310+
# CHECK-SAME: resources = {operations = {"SingleParam{x:{{\[\[f64\]\]}}}{reg:1}{}" = 1 : i64}
311311
# CHECK-SAME: target_gate = "CompilableData{}{wires:1}{a:10,b:2,thing:3}"
312312
# CHECK: stablehlo.constant dense<1.100000e+00> : tensor<f64>
313313
# CHECK-NOT: stablehlo.constant dense<1.000000e-01> : tensor<f64>
@@ -382,12 +382,12 @@ def rule(label, reg):
382382

383383

384384
# CHECK: func.func private @"rule_StaticData{}{reg:1}{}[1234]"
385-
# CHECK-SAME: resources = {operations = {"SingleParam{x:[f64]}{reg:1}{}" = 1 : i64}
385+
# CHECK-SAME: resources = {operations = {"SingleParam{x:{{\[\[f64\]\]}}}{reg:1}{}" = 1 : i64}
386386
# CHECK-SAME: target_gate = "StaticData{}{reg:1}{}[1234]"
387387
# CHECK: stablehlo.constant dense<1.000000e-01> : tensor<f64>
388388
#
389389
# CHECK: func.func private @"rule_StaticData{}{reg:1}{}[4321]"
390-
# CHECK-SAME: resources = {operations = {"SingleParam{x:[f64]}{reg:1}{}" = 2 : i64}
390+
# CHECK-SAME: resources = {operations = {"SingleParam{x:{{\[\[f64\]\]}}}{reg:1}{}" = 2 : i64}
391391
# CHECK-SAME: target_gate = "StaticData{}{reg:1}{}[4321]"
392392
# CHECK: stablehlo.constant dense<1.100000e+00> : tensor<f64>
393393
# CHECK: stablehlo.constant dense<2.200000e+00> : tensor<f64>
@@ -518,8 +518,8 @@ def rule(reg):
518518

519519

520520
# CHECK: func.func private @"rule_NoParams{}{reg:3}{}"
521-
# CHECK-DAG: "HybridOpArg{angle:[f64]}{cwires:1}{}[[[uid_1:[0-9]+]]]" = 1
522-
# CHECK-DAG: "HybridOpArg{angle:[f64]}{cwires:1}{}[[[uid_2:[0-9]+]]]" = 2
521+
# CHECK-DAG: "HybridOpArg{angle:{{\[\[f64\]\]}}}{cwires:1}{}[[[uid_1:[0-9]+]]]" = 1
522+
# CHECK-DAG: "HybridOpArg{angle:{{\[\[f64\]\]}}}{cwires:1}{}[[[uid_2:[0-9]+]]]" = 2
523523
# CHECK-DAG: target_gate = "NoParams{}{reg:3}{}"
524524
# CHECK: "qref.operator"({{%.+}}) {UID = [[uid_2]]
525525
# CHECK: "qref.operator"({{%.+}}) {UID = [[uid_2]]
@@ -544,7 +544,7 @@ def rule(angle, op, cwires, n_iters):
544544
qp.add_decomps(HybridOpArg, rule)
545545
result = compile_decomposition_rules_wrapper(
546546
"HybridOpArg",
547-
"HybridOpArg{angle:[f64]}{cwires:1}{}[5678]",
547+
"HybridOpArg{angle:[[f64]]}{cwires:1}{}[5678]",
548548
{"angle": ["f64"]},
549549
{"cwires": 1},
550550
{},
@@ -556,11 +556,11 @@ def rule(angle, op, cwires, n_iters):
556556
print(result)
557557

558558

559-
# CHECK: func.func private @"rule_HybridOpArg{angle:[f64]}{cwires:1}{}[5678]"
559+
# CHECK: func.func private @"rule_HybridOpArg{angle:{{\[\[f64\]\]}}}{cwires:1}{}[5678]"
560560
# CHECK-SAME: resources = {operations = {
561561
# CHECK-SAME: "NoParams{}{reg:1}{}" = 1 : i64,
562-
# CHECK-SAME: "StaticDataMultiReg{theta:[f64]}{reg:1,reg2:2}{}[[[uid:[0-9]+]]]" = 1 : i64
563-
# CHECK-SAME: target_gate = "HybridOpArg{angle:[f64]}{cwires:1}{}[5678]"
562+
# CHECK-SAME: "StaticDataMultiReg{theta:{{\[\[f64\]\]}}}{reg:1,reg2:2}{}[[[uid:[0-9]+]]]" = 1 : i64
563+
# CHECK-SAME: target_gate = "HybridOpArg{angle:{{\[\[f64\]\]}}}{cwires:1}{}[5678]"
564564
# CHECK: "qref.operator"({{%.+}}) {UID = [[uid]] : i64, op_name = "StaticDataMultiReg"
565565
test_from_hybrid_op()
566566

@@ -608,7 +608,7 @@ def rule(reg):
608608

609609

610610
# CHECK: func.func private @"rule_NoParams{}{reg:3}{}"
611-
# CHECK-SAME: "HybridOpArg{angle:[f64]}{cwires:1}{}[[[uid:[0-9]+]]]" = 1
611+
# CHECK-SAME: "HybridOpArg{angle:{{\[\[f64\]\]}}}{cwires:1}{}[[[uid:[0-9]+]]]" = 1
612612
# CHECK-SAME: target_gate = "NoParams{}{reg:3}{}"
613613
# CHECK: "qref.operator"({{%.+}}) {UID = [[uid]]
614614
test_to_hybrid_op_nested()
@@ -632,7 +632,7 @@ def rule(angle, op, cwires, n_iters):
632632
qp.add_decomps(HybridOpArg, rule)
633633
result = compile_decomposition_rules_wrapper(
634634
"HybridOpArg",
635-
"HybridOpArg{angle:[f64]}{cwires:1}{}[7654]",
635+
"HybridOpArg{angle:[[f64]]}{cwires:1}{}[7654]",
636636
{"angle": ["f64"]},
637637
{"cwires": 1},
638638
{},
@@ -649,12 +649,12 @@ def rule(angle, op, cwires, n_iters):
649649
print(result)
650650

651651

652-
# CHECK: func.func private @"rule_HybridOpArg{angle:[f64]}{cwires:1}{}[7654]"
652+
# CHECK: func.func private @"rule_HybridOpArg{angle:{{\[\[f64\]\]}}}{cwires:1}{}[7654]"
653653
# CHECK-SAME: resources = {operations = {
654-
# CHECK-SAME: "HybridOpArg{angle:[f64]}{cwires:1}{}[[[uid_outer:[0-9]+]]]" = 1 : i64,
654+
# CHECK-SAME: "HybridOpArg{angle:{{\[\[f64\]\]}}}{cwires:1}{}[[[uid_outer:[0-9]+]]]" = 1 : i64,
655655
# CHECK-SAME: "NoParams{}{reg:1}{}" = 1 : i64,
656-
# CHECK-SAME: "StaticDataMultiReg{theta:[f64]}{reg:1,reg2:2}{}[[[uid_inner:[0-9]+]]]" = 1 : i64
657-
# CHECK-SAME: target_gate = "HybridOpArg{angle:[f64]}{cwires:1}{}[7654]"
656+
# CHECK-SAME: "StaticDataMultiReg{theta:{{\[\[f64\]\]}}}{reg:1,reg2:2}{}[[[uid_inner:[0-9]+]]]" = 1 : i64
657+
# CHECK-SAME: target_gate = "HybridOpArg{angle:{{\[\[f64\]\]}}}{cwires:1}{}[7654]"
658658
# CHECK: "qref.operator"({{%.+}}) {UID = [[uid_outer]] : i64, op_name = "HybridOpArg"
659659
# CHECK: "qref.operator"({{%.+}}) {UID = [[uid_inner]] : i64, op_name = "StaticDataMultiReg"
660660
test_from_hybrid_op_nested()
@@ -717,7 +717,7 @@ def rule(reg):
717717

718718

719719
# CHECK: func.func private @"rule_NoParams{}{reg:3}{}"
720-
# CHECK-DAG: "MultipleFullArgs{angles1:[f64],angles2:[f64,f64]}{reg1:1,reg2:2}{}[[[uid:[0-9]+]]]" = 2
720+
# CHECK-DAG: "MultipleFullArgs{angles1:{{\[\[f64\]\]}},angles2:{{\[\[f64,f64\]\]}}}{reg1:1,reg2:2}{}[[[uid:[0-9]+]]]" = 2
721721
# CHECK-DAG: target_gate = "NoParams{}{reg:3}{}"
722722
# CHECK: "qref.operator"({{%.+}}) {UID = [[uid]]
723723
# CHECK: "qref.operator"({{%.+}}) {UID = [[uid]]
@@ -744,7 +744,7 @@ def rule(reg1, reg2, angles1, angles2, pytree1, pytree2, op1, op2, hwires1, hwir
744744
qp.add_decomps(MultipleFullArgs, rule)
745745
result = compile_decomposition_rules_wrapper(
746746
"MultipleFullArgs",
747-
"MultipleFullArgs{angles1:[f64],angles2:[f64,f64]}{reg1:1,reg2:2}{}[-4321]",
747+
"MultipleFullArgs{angles1:[[f64]],angles2:[[f64,f64]]}{reg1:1,reg2:2}{}[-4321]",
748748
{"angles1": ["f64"], "angles2": ["f64", "f64"]},
749749
{"reg1": 1, "reg2": 2},
750750
{},
@@ -760,12 +760,12 @@ def rule(reg1, reg2, angles1, angles2, pytree1, pytree2, op1, op2, hwires1, hwir
760760
print(result)
761761

762762

763-
# CHECK: func.func private @"rule_MultipleFullArgs{angles1:[f64],angles2:[f64,f64]}{reg1:1,reg2:2}{}[-4321]"
763+
# CHECK: func.func private @"rule_MultipleFullArgs{angles1:{{\[\[f64\]\]}},angles2:{{\[\[f64,f64\]\]}}}{reg1:1,reg2:2}{}[-4321]"
764764
# CHECK-SAME: resources = {operations = {
765765
# CHECK-SAME: "NoParams{}{reg:1}{}" = 1 : i64
766-
# CHECK-SAME: "SingleParam{x:[f64]}{reg:1}{}" = 1 : i64
767-
# CHECK-SAME: "SingleParam{x:[i64]}{reg:1}{}" = 1 : i64
768-
# CHECK-SAME: target_gate = "MultipleFullArgs{angles1:[f64],angles2:[f64,f64]}{reg1:1,reg2:2}{}[-4321]"
766+
# CHECK-SAME: "SingleParam{x:{{\[\[f64\]\]}}}{reg:1}{}" = 1 : i64
767+
# CHECK-SAME: "SingleParam{x:{{\[\[i64\]\]}}}{reg:1}{}" = 1 : i64
768+
# CHECK-SAME: target_gate = "MultipleFullArgs{angles1:{{\[\[f64\]\]}},angles2:{{\[\[f64,f64\]\]}}}{reg1:1,reg2:2}{}[-4321]"
769769
# CHECK: "qref.operator"({{%.+}}) {op_name = "SingleParam"
770770
# CHECK: "qref.operator"({{%.+}}) {op_name = "SingleParam"
771771
# CHECK: "qref.operator"({{%.+}}) {op_name = "NoParams"
@@ -805,7 +805,7 @@ def rule2(reg):
805805

806806

807807
# CHECK: func.func private @"rule1_NoParams{}{reg:1}{}"
808-
# CHECK-SAME: resources = {operations = {"SingleParam{x:[f64]}{reg:1}{}" = 1 : i64}}
808+
# CHECK-SAME: resources = {operations = {"SingleParam{x:{{\[\[f64\]\]}}}{reg:1}{}" = 1 : i64}}
809809
# CHECK-SAME: target_gate = "NoParams{}{reg:1}{}"
810810
# CHECK: func.func private @"rule2_NoParams{}{reg:1}{}"
811811
# CHECK-SAME: resources = {operations = {"CompilableData{}{wires:3}{a:a,b:b,thing:thing}" = 1 : i64}}
@@ -848,7 +848,7 @@ def l(i):
848848

849849

850850
# CHECK: func.func private @test_rule_TestID
851-
# CHECK-SAME: resources = {operations = {"TestRX{theta:[f64]}{wires:1}{}" = 3 : i64}}
851+
# CHECK-SAME: resources = {operations = {"TestRX{theta:{{\[\[f64\]\]}}}{wires:1}{}" = 3 : i64}}
852852
# CHECK-SAME: target_gate = "TestID"
853853
# CHECK-DAG: stablehlo.constant dense<0> : tensor<i64>
854854
# CHECK-DAG: stablehlo.constant dense<3> : tensor<i64>

0 commit comments

Comments
 (0)