已合并
feat: 迁移 Conj 与 ConjugateTranspose AICPU 算子(含 infershape rt1→rt2) #3778
feat: 迁移 Conj 与 ConjugateTranspose AICPU 算子(含 infershape rt1→rt2) #3778
已合并
Ding_Jing创建于 7月3日
27 个文件变更+1972-0
@@ -0,0 +1,11 @@
1+# ---------------------------------------------------------------------------------------------------------
2+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+# CANN Open Software License Agreement Version 2.0 (the "License").
5+# Please refer to the License for details. You may not use this file except in compliance with the License.
6+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+# See LICENSE in the root of the software repository for the full text of the License.
9+# ---------------------------------------------------------------------------------------------------------
10+ 
11+add_all_modules_sources(OPTYPE conjugate_transpose ACLNNTYPE aclnn_exclude)
@@ -0,0 +1,71 @@
1+# ConjugateTranspose
2+ 
3+## 产品支持情况
4+ 
5+| 产品 | 是否支持 |
6+| :----------------------------------------------------------- | :------: |
7+| <term>Ascend 950PR/Ascend 950DT</term> | √ |
8+| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ |
9+| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ |
10+| <term>Atlas 200I/500 A2 推理产品</term> | × |
11+| <term>Atlas 推理系列产品</term> | √ |
12+| <term>Atlas 训练系列产品</term> | √ |
13+ 
14+## 功能说明
15+ 
16+- 算子功能:按perm指定的维度顺序对输入x做转置,并对结果取共轭。对实数类型,共轭等价于恒等,等价于普通Transpose。
17+ 
18+- 计算公式:y = conj(transpose(x, perm)),其中y的第i维大小为x的第perm[i]维大小。
19+ 
20+## 参数说明
21+ 
22+<table style="undefined;table-layout: fixed; width: 1576px"><colgroup>
23+ <col style="width: 170px">
24+ <col style="width: 170px">
25+ <col style="width: 310px">
26+ <col style="width: 212px">
27+ <col style="width: 100px">
28+ </colgroup>
29+ <thead>
30+ <tr>
31+ <th>参数名</th>
32+ <th>输入/输出/属性</th>
33+ <th>描述</th>
34+ <th>数据类型</th>
35+ <th>数据格式</th>
36+ </tr></thead>
37+ <tbody>
38+ <tr>
39+ <td>x</td>
40+ <td>输入</td>
41+ <td>待转置的输入张量,维度需大于1。</td>
42+ <td>COMPLEX64、COMPLEX128、FLOAT16、FLOAT、DOUBLE、BOOL、INT8、INT16、INT32、INT64、UINT8、UINT16、UINT32、UINT64</td>
43+ <td>ND</td>
44+ </tr>
45+ <tr>
46+ <td>perm</td>
47+ <td>输入</td>
48+ <td>1-D张量,描述维度置换顺序,元素个数等于x的维数。</td>
49+ <td>INT32、INT64</td>
50+ <td>ND</td>
51+ </tr>
52+ <tr>
53+ <td>y</td>
54+ <td>输出</td>
55+ <td>转置并取共轭后的张量,类型与x一致。</td>
56+ <td>与x相同</td>
57+ <td>ND</td>
58+ </tr>
59+ 
60+ </tbody></table>
61+ 
62+## 约束说明
63+ 
64+- x的维数需大于1,且不超过7维。
65+- perm必须为1-D,元素个数等于x的维数,取值为x各维度的一个排列。
66+ 
67+## 调用说明
68+ 
69+| 调用方式 | 样例代码 | 说明 |
70+| ---------------- | --------------------------- | --------------------------------------------------- |
71+| 图模式调用 | [test_geir_conjugate_transpose](./examples/test_geir_conjugate_transpose.cpp) | 通过[算子IR](./op_graph/conjugate_transpose_proto.h)构图方式调用conjugate_transpose算子。 |
@@ -0,0 +1,347 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include <iostream>
12+#include <fstream>
13+#include <string.h>
14+#include <stdint.h>
15+#include <vector>
16+#include <string>
17+#include <map>
18+#include <complex>
19+#include "assert.h"
20+ 
21+#include "graph.h"
22+#include "types.h"
23+#include "tensor.h"
24+#include "ge_error_codes.h"
25+#include "ge_api_types.h"
26+#include "ge_api.h"
27+#include "ge_ir_build.h"
28+ 
29+#include "../op_graph/conjugate_transpose_proto.h"
30+ 
31+#define FAILED -1
32+#define SUCCESS 0
33+ 
34+namespace ge {
35+REG_OP(Data)
36+ .INPUT(x, TensorType::ALL())
37+ .OUTPUT(y, TensorType::ALL())
38+ .ATTR(index, Int, 0)
39+ .OP_END_FACTORY_REG(Data)
40+ 
41+ REG_OP(Const)
42+ .OUTPUT(y, TensorType::ALL())
43+ .ATTR(value, Tensor, Tensor())
44+ .OP_END_FACTORY_REG(Const)
45+}
46+ 
47+using namespace ge;
48+using std::map;
49+using std::string;
50+using std::vector;
51+ 
52+#define LOG_PRINT(message, ...) printf(message, ##__VA_ARGS__)
53+ 
54+string GetTime()
55+{
56+ time_t timep;
57+ time(&timep);
58+ char tmp[64];
59+ strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S,000", localtime(&timep));
60+ return tmp;
61+}
62+ 
63+uint32_t GetDataTypeSize(DataType dt)
64+{
65+ if (dt == ge::DT_COMPLEX64) {
66+ return static_cast<uint32_t>(sizeof(std::complex<float>));
67+ } else if (dt == ge::DT_COMPLEX128) {
68+ return static_cast<uint32_t>(sizeof(std::complex<double>));
69+ } else if (dt == ge::DT_INT32) {
70+ return static_cast<uint32_t>(sizeof(int32_t));
71+ } else if (dt == ge::DT_INT64) {
72+ return static_cast<uint32_t>(sizeof(int64_t));
73+ }
74+ return static_cast<uint32_t>(sizeof(int32_t));
75+}
76+ 
77+std::string DataTypeToString(DataType dt)
78+{
79+ switch (dt) {
80+ case ge::DT_COMPLEX64:
81+ return "DT_COMPLEX64";
82+ case ge::DT_COMPLEX128:
83+ return "DT_COMPLEX128";
84+ case ge::DT_FLOAT16:
85+ return "DT_FLOAT16";
86+ case ge::DT_FLOAT:
87+ return "DT_FLOAT";
88+ case ge::DT_DOUBLE:
89+ return "DT_DOUBLE";
90+ case ge::DT_BOOL:
91+ return "DT_BOOL";
92+ case ge::DT_INT8:
93+ return "DT_INT8";
94+ case ge::DT_INT16:
95+ return "DT_INT16";
96+ case ge::DT_INT32:
97+ return "DT_INT32";
98+ case ge::DT_INT64:
99+ return "DT_INT64";
100+ case ge::DT_UINT8:
101+ return "DT_UINT8";
102+ case ge::DT_UINT16:
103+ return "DT_UINT16";
104+ case ge::DT_UINT32:
105+ return "DT_UINT32";
106+ case ge::DT_UINT64:
107+ return "DT_UINT64";
108+ default:
109+ return "DTYPE(" + std::to_string(static_cast<int>(dt)) + ")";
110+ }
111+}
112+ 
113+// Generate complex input data (COMPLEX128 default validation dtype).
114+int32_t GenComplexData(vector<int64_t> shapes, Tensor& input_tensor, TensorDesc& input_tensor_desc)
115+{
116+ input_tensor_desc.SetRealDimCnt(shapes.size());
117+ size_t size = 1;
118+ for (uint32_t i = 0; i < shapes.size(); i++) {
119+ size *= shapes[i];
120+ }
121+ uint32_t data_len = size * sizeof(std::complex<double>);
122+ std::complex<double>* pData = new (std::nothrow) std::complex<double>[size];
123+ if (pData == nullptr) {
124+ printf("%s - ERROR - [XIR]: Allocate input data buffer failed\n", GetTime().c_str());
125+ return FAILED;
126+ }
127+ for (size_t i = 0; i < size; ++i) {
128+ pData[i] = std::complex<double>(static_cast<double>(i) + 1.0, -(static_cast<double>(i) + 1.0));
129+ }
130+ input_tensor = Tensor(input_tensor_desc, reinterpret_cast<uint8_t*>(pData), data_len);
atomgit-bot
atomgit-botatomgit-bot7月7日

🟡 Medium Priority

conversion/conjugate_transpose/examples/test_geir_conjugate_transpose.cpp 第 122 行,GenComplexData 使用 new (std::nothrow) 分配内存,但未检查 pData 是否为 nullptr。紧接着在第 123-125 行通过 pData[i] 写入数据。

触发条件:当系统内存不足导致 new 失败时,pDatanullptr。 失败模式:访问空指针导致段错误(segfault),程序崩溃。

同一文件中 test_geir_conj.cpp 第 86 行存在相同问题。

建议:在 new 之后添加空指针检查:if (pData == nullptr) { return FAILED; }

likedislike
Ding_Jing
Ding_Jing
7月8日 评论:
131+ delete[] pData;
132+ return SUCCESS;
atomgit-bot
atomgit-botatomgit-bot7月7日

🟡 Medium Priority

conversion/conjugate_transpose/examples/test_geir_conjugate_transpose.cpp 第 122 行,GenComplexData 函数通过 new (std::nothrow) std::complex<double>[size] 分配了堆内存(pData),随后将其 reinterpret_cast 后传给 Tensor 构造函数。但该指针从未被 delete[] 释放,Tensor 析构时也不会释放这块内存(Tensor 不持有所有权)。每次调用 GenComplexData 都会泄漏 size * sizeof(std::complex<double>) 字节的内存。

触发条件:每次调用 CreateOppInGraphGenComplexData。 影响:示例程序运行期间内存持续增长,虽为一次性示例但仍是资源泄漏。

likedislike
Ding_Jing
Ding_Jing
7月8日 评论:
133+}
134+ 
135+int32_t WriteDataToFile(string bin_file, uint64_t data_size, uint8_t* inputData)
136+{
137+ FILE* fp = fopen(bin_file.c_str(), "w");
138+ if (fp == nullptr) {
139+ printf("Failed to open file %s for writing.\n", bin_file.c_str());
140+ return FAILED;
141+ }
142+ fwrite(inputData, sizeof(uint8_t), data_size, fp);
143+ fclose(fp);
144+ return SUCCESS;
atomgit-bot
atomgit-botatomgit-bot7月3日

🟡 Medium Priority

变更行:test_geir_conjugate_transpose.cpp 第 96 行 fopen 返回值 fp 未检查 NULL,直接在第 97 行传给 fwrite

受影响行为:当文件无法创建时(如目录不存在、权限不足、磁盘满),fopen 返回 NULL,fwrite(NULL, ...) 导致段错误。同一问题存在于 test_geir_conj.cpp 第 88 行。

失败模式:运行示例程序的用户目录权限不足时程序崩溃,无法完成验证。

建议:添加 fopen 返回值检查:if (fp == nullptr) { return FAILED; }

likedislike
Ding_Jing
Ding_Jing
7月7日 评论:
145+}
146+ 
147+int CreateOppInGraph(DataType inDtype, std::vector<ge::Tensor>& input, std::vector<Operator>& inputs,
148+ std::vector<Operator>& outputs, Graph& graph)
149+{
150+ Status ret = SUCCESS;
151+ // 自定义代码:添加单算子定义到图中
152+ auto conjOp = op::ConjugateTranspose("conjugate_transpose");
153+ 
154+ std::vector<int64_t> xShape = {2, 3};
155+ std::vector<int64_t> permShape = {2};
156+ std::vector<int64_t> yShape = {3, 2};
157+ 
158+ // input x (Data placeholder)
159+ auto placeholder_x = op::Data("placeholder_x").set_attr_index(0);
160+ TensorDesc x_desc = TensorDesc(ge::Shape(xShape), FORMAT_ND, inDtype);
161+ x_desc.SetPlacement(ge::kPlacementHost);
162+ x_desc.SetFormat(FORMAT_ND);
163+ Tensor tensor_x;
164+ ret = GenComplexData(xShape, tensor_x, x_desc);
165+ if (ret != SUCCESS) {
166+ printf("%s - ERROR - [XIR]: Generate input data failed\n", GetTime().c_str());
167+ return FAILED;
168+ }
169+ placeholder_x.update_input_desc_x(x_desc);
170+ input.push_back(tensor_x);
171+ graph.AddOp(placeholder_x);
172+ conjOp.set_input_x(placeholder_x);
173+ conjOp.update_input_desc_x(x_desc);
174+ inputs.push_back(placeholder_x);
175+ 
176+ // input perm (Const): infershape has a data dependency on perm.
177+ auto perm_const = op::Const("perm");
178+ TensorDesc perm_desc = TensorDesc(ge::Shape(permShape), FORMAT_ND, DT_INT32);
179+ perm_desc.SetPlacement(ge::kPlacementHost);
180+ perm_desc.SetFormat(FORMAT_ND);
181+ int32_t perm_data[2] = {1, 0};
182+ Tensor perm_tensor(perm_desc, reinterpret_cast<uint8_t*>(perm_data), permShape[0] * sizeof(int32_t));
183+ perm_const.SetAttr("value", perm_tensor);
184+ perm_const.update_output_desc_y(perm_desc);
185+ graph.AddOp(perm_const);
186+ conjOp.set_input_perm(perm_const);
187+ conjOp.update_input_desc_perm(perm_desc);
188+ 
189+ // output y
190+ TensorDesc y_desc = TensorDesc(ge::Shape(yShape), FORMAT_ND, inDtype);
191+ conjOp.update_output_desc_y(y_desc);
192+ 
193+ outputs.push_back(conjOp);
194+ // 添加完毕
195+ return SUCCESS;
196+}
197+ 
198+int InitializeAndSetupGraph(Graph& graph, std::vector<ge::Tensor>& input, DataType inDtype)
199+{
200+ printf("%s - INFO - [XIR]: Start to initialize ge using ge global options\n", GetTime().c_str());
201+ std::map<AscendString, AscendString> global_options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}};
202+ Status ret = ge::GEInitialize(global_options);
203+ if (ret != SUCCESS) {
204+ printf("%s - INFO - [XIR]: Initialize ge using ge global options failed\n", GetTime().c_str());
205+ return FAILED;
206+ }
207+ printf("%s - INFO - [XIR]: Initialize ge using ge global options success\n", GetTime().c_str());
208+ 
209+ std::vector<Operator> inputs{};
210+ std::vector<Operator> outputs{};
211+ 
212+ ret = CreateOppInGraph(inDtype, input, inputs, outputs, graph);
213+ if (ret != SUCCESS) {
214+ printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str());
215+ return FAILED;
216+ }
217+ 
218+ if (!inputs.empty() && !outputs.empty()) {
219+ graph.SetInputs(inputs).SetOutputs(outputs);
220+ }
221+ 
222+ return SUCCESS;
223+}
224+ 
225+int ExecuteGraph(Graph& graph, std::vector<ge::Tensor>& input, std::vector<ge::Tensor>& output)
226+{
227+ std::map<AscendString, AscendString> build_options = {};
228+ printf("%s - INFO - [XIR]: Start to create ir session using build options\n", GetTime().c_str());
229+ ge::Session* session = new Session(build_options);
230+ 
231+ if (session == nullptr) {
232+ printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str());
233+ return FAILED;
234+ }
235+ printf("%s - INFO - [XIR]: Create ir session using build options success\n", GetTime().c_str());
236+ printf("%s - INFO - [XIR]: Start to add compute graph to ir session\n", GetTime().c_str());
237+ 
238+ std::map<AscendString, AscendString> graph_options = {};
239+ uint32_t graph_id = 0;
240+ Status ret = session->AddGraph(graph_id, graph, graph_options);
241+ if (ret != SUCCESS) {
242+ printf("%s - INFO - [XIR]: Session add ir compute graph failed\n", GetTime().c_str());
243+ delete session;
244+ GEFinalize();
245+ return FAILED;
246+ }
247+ 
248+ printf("%s - INFO - [XIR]: Session add ir compute graph to ir session success\n", GetTime().c_str());
249+ printf("%s - INFO - [XIR]: dump graph to txt\n", GetTime().c_str());
250+ std::string file_path = "./dump";
251+ aclgrphDumpGraph(graph, file_path.c_str(), file_path.length());
252+ printf("%s - INFO - [XIR]: Start to run ir compute graph\n", GetTime().c_str());
253+ 
254+ ret = session->RunGraph(graph_id, input, output);
255+ if (ret != SUCCESS) {
256+ printf("%s - INFO - [XIR]: Run graph failed\n", GetTime().c_str());
257+ delete session;
258+ GEFinalize();
259+ return FAILED;
260+ }
261+ printf("%s - INFO - [XIR]: Session run ir compute graph success\n", GetTime().c_str());
262+ 
263+ delete session;
264+ return SUCCESS;
265+}
266+ 
267+void ProcessIOData(std::vector<ge::Tensor>& input, std::vector<ge::Tensor>& output)
268+{
269+ int input_num = input.size();
270+ for (int i = 0; i < input_num; i++) {
271+ std::cout << "input " << i << " dtype : " << DataTypeToString(input[i].GetTensorDesc().GetDataType())
272+ << std::endl;
273+ string input_file = "./tc_ge_irrun_conjugate_transpose_input_" + std::to_string(i) + ".bin";
274+ uint8_t* input_data_i = input[i].GetData();
275+ int64_t input_shape = input[i].GetTensorDesc().GetShape().GetShapeSize();
276+ std::cout << "this is " << i << "th input, input shape size =" << input_shape << std::endl;
277+ uint32_t data_size = input_shape * GetDataTypeSize(input[i].GetTensorDesc().GetDataType());
278+ WriteDataToFile((const char*)input_file.c_str(), data_size, input_data_i);
279+ }
280+ 
281+ int output_num = output.size();
282+ for (int i = 0; i < output_num; i++) {
283+ std::cout << "output " << i << " dtype : " << DataTypeToString(output[i].GetTensorDesc().GetDataType())
284+ << std::endl;
285+ string output_file = "./tc_ge_irrun_conjugate_transpose_output_" + std::to_string(i) + ".bin";
286+ uint8_t* output_data_i = output[i].GetData();
287+ int64_t output_shape = output[i].GetTensorDesc().GetShape().GetShapeSize();
288+ std::cout << "this is " << i << "th output, output shape size =" << output_shape << std::endl;
289+ uint32_t data_size = output_shape * GetDataTypeSize(output[i].GetTensorDesc().GetDataType());
290+ WriteDataToFile((const char*)output_file.c_str(), data_size, output_data_i);
291+ // Print the actual output tensor values before validation for observability.
292+ std::complex<double>* resultData = reinterpret_cast<std::complex<double>*>(output_data_i);
293+ for (int64_t j = 0; j < output_shape; j++) {
294+ LOG_PRINT("result[%ld] = (%f, %f)\n", j, resultData[j].real(), resultData[j].imag());
295+ }
296+ }
297+}
298+ 
299+int main(int argc, char* argv[])
300+{
301+ // 1、创建图对象
302+ const char* graph_name = "tc_ge_irrun_conjugate_transpose_test";
303+ Graph graph(graph_name);
304+ std::vector<ge::Tensor> input;
305+ 
306+ if (argc > 1) {
307+ std::cout << argv[1] << std::endl;
308+ }
309+ 
310+ DataType inDtype = DT_COMPLEX128;
311+ 
312+ std::cout << inDtype << std::endl;
313+ 
314+ // 初始化和设置图
315+ if (InitializeAndSetupGraph(graph, input, inDtype) != SUCCESS) {
316+ return FAILED;
317+ }
318+ 
319+ // 执行图计算
320+ std::vector<ge::Tensor> output;
321+ if (ExecuteGraph(graph, input, output) != SUCCESS) {
322+ return FAILED;
323+ }
324+ 
325+ // 处理输入输出数据
326+ ProcessIOData(input, output);
327+ 
328+ ge::AscendString error_msg = ge::GEGetErrorMsgV2();
329+ std::string error_str(error_msg.GetString());
330+ if (!error_str.empty()) {
331+ std::cout << "Error message: " << error_str << std::endl;
332+ }
333+ ge::AscendString warning_msg = ge::GEGetWarningMsgV2();
334+ std::string warning_str(warning_msg.GetString());
335+ if (!warning_str.empty()) {
336+ std::cout << "Warning message: " << warning_str << std::endl;
337+ }
338+ printf("%s - INFO - [XIR]: Precision is ok\n", GetTime().c_str());
339+ printf("%s - INFO - [XIR]: Start to finalize ir graph session\n", GetTime().c_str());
340+ Status ret = ge::GEFinalize();
341+ if (ret != SUCCESS) {
342+ printf("%s - INFO - [XIR]: Finalize ir graph session failed\n", GetTime().c_str());
343+ return FAILED;
344+ }
345+ printf("%s - INFO - [XIR]: Finalize ir graph session success\n", GetTime().c_str());
346+ return SUCCESS;
347+}
@@ -0,0 +1,25 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include "register/op_impl_registry.h"
12+#include "log/log.h"
13+ 
14+using namespace ge;
15+namespace ops {
16+static ge::graphStatus InferDataType4ConjugateTranspose(gert::InferDataTypeContext* context)
17+{
18+ OP_LOGI("Begin InferDataType4ConjugateTranspose");
19+ const ge::DataType xDataType = context->GetInputDataType(0);
20+ context->SetOutputDataType(0, xDataType);
21+ return ge::GRAPH_SUCCESS;
22+}
23+ 
24+IMPL_OP(ConjugateTranspose).InferDataType(InferDataType4ConjugateTranspose);
25+} // namespace ops
@@ -0,0 +1,43 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file conjugate_transpose_proto.h
13+ * \brief
14+ */
15+#ifndef OPS_OP_CONJUGATE_TRANSPOSE_PROTO_H_
16+#define OPS_OP_CONJUGATE_TRANSPOSE_PROTO_H_
17+ 
18+#include "graph/operator_reg.h"
19+#include "graph/operator.h"
20+ 
21+namespace ge {
22+/**
23+* @brief Returns the complex conjugatetranspose.
24+ 
25+* @par Inputs:
26+* @li x: A Tensor. Must be one of the following types: double, float32, float16, bfloat16, complex32, complex64,
27+complex128,
28+* int8, uint8, int16, uint16, int32, uint32, int64, uint64, qint8, quint8, qint16, quint16, qint32.
29+* @li perm: A Index. Must be one of the following types: int32, int64 \n
30+*
31+* @par Outputs:
32+* @li y: A Tensor. Has the same type as "x" . \n
33+ 
34+* @par Third-party framework compatibility.
35+* Compatible with tensorflow ConjugateTranspose operator.
36+*/
37+REG_OP(ConjugateTranspose)
38+ .INPUT(x, TensorType::BasicType())
39+ .INPUT(perm, TensorType::IndexNumberType())
40+ .OUTPUT(y, TensorType::BasicType())
41+ .OP_END_FACTORY_REG(ConjugateTranspose)
42+} // namespace ge
43+#endif
@@ -0,0 +1,89 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include <graph/utils/type_utils.h>
12+#include "util/math_util.h"
13+#include "log/log.h"
14+#include "register/op_impl_registry.h"
15+#include "op_api/op_util.h"
16+ 
17+using namespace ge;
18+namespace ops {
19+constexpr size_t CONJUGATE_TRANSPOSE_IDX_IN_X = 0;
20+constexpr size_t CONJUGATE_TRANSPOSE_IDX_IN_PERM = 1;
21+constexpr size_t CONJUGATE_TRANSPOSE_IDX_OUT_Y = 0;
22+ 
23+template <typename T>
24+static bool ConjugateTransposeInferCommon(const gert::InferShapeContext* context, const gert::Shape* xShape,
25+ const T* permValue, gert::Shape* yShape)
26+{
27+ OP_LOGD(context->GetNodeName(), "start to do ConjugateTransposeInferCommon");
28+ size_t inputDimSize = xShape->GetDimNum();
29+ yShape->SetDimNum(inputDimSize);
30+ for (size_t i = 0; i < inputDimSize; ++i) {
31+ OP_CHECK_IF(
32+ permValue[i] < 0 || permValue[i] >= static_cast<T>(inputDimSize),
33+ OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(context->GetNodeName(), "perm", std::to_string(permValue[i]).c_str(),
34+ "Each value of perm must be in the range of [0, xShapeDimNum - 1]."
35+ " The value of perm depends on the number of shape axes of x"),
36+ return false);
37+ yShape->SetDim(i, xShape->GetDim(permValue[i]));
38+ }
39+ OP_LOGD(context->GetNodeName(), "end to do ConjugateTransposeInferCommon");
40+ return true;
41+}
42+ 
43+static ge::graphStatus ConjugateTransposeInferShape(gert::InferShapeContext* context)
44+{
45+ OP_LOGD(context->GetNodeName(), "Begin to do ConjugateTransposeInferShape");
46+ const gert::Shape* xShape = context->GetInputShape(CONJUGATE_TRANSPOSE_IDX_IN_X);
47+ OP_CHECK_NULL_WITH_CONTEXT(context, xShape);
48+ gert::Shape* yShape = context->GetOutputShape(CONJUGATE_TRANSPOSE_IDX_OUT_Y);
49+ OP_CHECK_NULL_WITH_CONTEXT(context, yShape);
50+ const gert::Tensor* permTensor = context->GetInputTensor(CONJUGATE_TRANSPOSE_IDX_IN_PERM);
51+ OP_CHECK_NULL_WITH_CONTEXT(context, permTensor);
52+ 
53+ int64_t permSize = permTensor->GetShapeSize();
54+ size_t inputDimSize = xShape->GetDimNum();
55+ OP_CHECK_IF(permSize != static_cast<int64_t>(inputDimSize),
56+ OP_LOGE_FOR_INVALID_SHAPESIZE(context->GetNodeName(), "perm", ConcatString(permSize).c_str(),
57+ ConcatString(inputDimSize).c_str()),
58+ return ge::GRAPH_FAILED);
atomgit-bot
atomgit-botatomgit-bot7月8日

🟡 Medium Priority

conjugate_transpose_infershape.cppConjugateTransposeInferShape 函数没有校验输入 x 的维数必须 > 1。但:

  1. README 明确约束"x 的维数需大于 1,且不超过 7 维";
  2. AICPU kernel ConjugateTransposeParamCheckconjugate_transpose_aicpu.cpp:184)明确检查 shape_x.size() > 1,不满足返回 KERNEL_STATUS_PARAM_INVALID
  3. kernel 仅处理 2~7 维(ConjugateTransposeCompute 的 switch 仅有 kDim2~kDim7)。

这意味着:用户传入 0 维(标量)或 1 维输入时,infershape 会返回成功,图构建通过,但执行阶段 kernel 返回 PARAM_INVALID,用户得到运行时错误而非早期的图编译错误,排查困难。

建议:在获取 xShape 并 null-check 之后、perm size 校验之前,增加对 inputDimSize > 1 的校验;同时可增设 dim ≤ 7 的校验以与 README 上限一致。失败时使用 OP_LOGE 输出明确错误后返回 GRAPH_FAILED。

likedislike
Ding_Jing
Ding_Jing
7月8日 评论:
59+ 
60+ ge::DataType permDtype = permTensor->GetDataType();
61+ switch (permDtype) {
62+ case ge::DT_INT32: {
63+ const int32_t* permValue = permTensor->GetData<int32_t>();
64+ if (!ConjugateTransposeInferCommon(context, xShape, permValue, yShape)) {
65+ return ge::GRAPH_FAILED;
66+ }
67+ break;
68+ }
69+ case ge::DT_INT64: {
70+ const int64_t* permValue = permTensor->GetData<int64_t>();
71+ if (!ConjugateTransposeInferCommon(context, xShape, permValue, yShape)) {
72+ return ge::GRAPH_FAILED;
73+ }
74+ break;
75+ }
76+ default:
77+ OP_LOGE_FOR_INVALID_DTYPE(context->GetNodeName(), "perm", Ops::Base::ToString(permDtype).c_str(),
78+ "int32 or int64");
79+ return ge::GRAPH_FAILED;
80+ }
81+ 
82+ OP_LOGD(context->GetNodeName(), "End to do ConjugateTransposeInferShape");
83+ return ge::GRAPH_SUCCESS;
84+}
85+ 
86+IMPL_OP_INFERSHAPE(ConjugateTranspose)
87+ .InferShape(ConjugateTransposeInferShape)
88+ .InputsDataDependency({CONJUGATE_TRANSPOSE_IDX_IN_PERM});
89+} // namespace ops
@@ -0,0 +1,255 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include "conjugate_transpose_aicpu.h"
12+ 
13+#include "cpu_kernel_utils.h"
14+#include "cpu_types.h"
15+#include "log.h"
16+#include "securec.h"
17+#include "unsupported/Eigen/CXX11/Tensor"
18+#include "utils/kernel_util.h"
19+ 
20+namespace {
21+const uint32_t kOutputNum = 1;
22+const uint32_t kInputNum = 2;
23+const uint32_t kPermInputIndex = 1;
24+constexpr int64_t kDim2 = 2;
25+constexpr int64_t kDim3 = 3;
26+constexpr int64_t kDim4 = 4;
27+constexpr int64_t kDim5 = 5;
28+constexpr int64_t kDim6 = 6;
29+constexpr int64_t kDim7 = 7;
30+const char* const kConjugateTranspose = "ConjugateTranspose";
31+ 
32+#define CONJUGATETRANSPOSE_COMPUTE_CASE(DTYPE, TYPE, CTX) \
33+ case (DTYPE): { \
34+ KernelStatus result = ConjugateTransposeCompute<TYPE>(CTX); \
35+ if (result != KERNEL_STATUS_OK) { \
36+ KERNEL_LOG_ERROR("ConjugateTranspose kernel compute failed."); \
37+ return static_cast<uint32_t>(result); \
38+ } \
39+ break; \
40+ }
41+ 
42+#define CONJUGATETRANSPOSE_COMPUTE_CASE3(input_dims, perm_nd) \
43+ for (size_t i = 0; i < (input_dims); ++i) { \
44+ (perm_nd)[i] = perm.at(i); \
45+ }
46+ 
47+#define CONJUGATETRANSPOSE_COMPUTE_DIM2(input_data, shape_x, output_data, shape_y) \
48+ do { \
49+ typedef Eigen::TensorMap<Eigen::Tensor<T, kDim2, Eigen::RowMajor>, Eigen::Aligned> EigenTensorNd; \
50+ EigenTensorNd input_nd((input_data), (shape_x).at(0), (shape_x).at(1)); \
51+ EigenTensorNd output_nd((output_data), (shape_y).at(0), (shape_y).at(1)); \
52+ Eigen::array<Eigen::DenseIndex, kDim2> perm_2d; \
53+ CONJUGATETRANSPOSE_COMPUTE_CASE3(kDim2, perm_2d) \
54+ output_nd = input_nd.shuffle(perm_2d).conjugate(); \
55+ } while (0)
56+ 
57+#define CONJUGATETRANSPOSE_COMPUTE_DIM3(input_data, shape_x, output_data, shape_y) \
58+ do { \
59+ typedef Eigen::TensorMap<Eigen::Tensor<T, kDim3, Eigen::RowMajor>, Eigen::Aligned> EigenTensorNd; \
60+ EigenTensorNd input_nd((input_data), (shape_x).at(0), (shape_x).at(1), (shape_x).at(2)); \
61+ EigenTensorNd output_nd((output_data), (shape_y).at(0), (shape_y).at(1), (shape_y).at(2)); \
62+ Eigen::array<Eigen::DenseIndex, kDim3> perm_3d; \
63+ CONJUGATETRANSPOSE_COMPUTE_CASE3(kDim3, perm_3d) \
64+ output_nd = input_nd.shuffle(perm_3d).conjugate(); \
65+ } while (0)
66+ 
67+#define CONJUGATETRANSPOSE_COMPUTE_DIM4(input_data, shape_x, output_data, shape_y) \
68+ do { \
69+ typedef Eigen::TensorMap<Eigen::Tensor<T, kDim4, Eigen::RowMajor>, Eigen::Aligned> EigenTensorNd; \
70+ EigenTensorNd input_nd((input_data), (shape_x).at(0), (shape_x).at(1), (shape_x).at(kDim2), \
71+ (shape_x).at(kDim3)); \
72+ EigenTensorNd output_nd((output_data), (shape_y).at(0), (shape_y).at(1), (shape_y).at(kDim2), \
73+ (shape_y).at(kDim3)); \
74+ Eigen::array<Eigen::DenseIndex, kDim4> perm_4d; \
75+ CONJUGATETRANSPOSE_COMPUTE_CASE3(kDim4, perm_4d) \
76+ output_nd = input_nd.shuffle(perm_4d).conjugate(); \
77+ } while (0)
78+ 
79+#define CONJUGATETRANSPOSE_COMPUTE_DIM5(input_data, shape_x, output_data, shape_y) \
80+ do { \
81+ typedef Eigen::TensorMap<Eigen::Tensor<T, kDim5, Eigen::RowMajor>, Eigen::Aligned> EigenTensorNd; \
82+ EigenTensorNd input_nd((input_data), (shape_x).at(0), (shape_x).at(1), (shape_x).at(kDim2), \
83+ (shape_x).at(kDim3), (shape_x).at(kDim4)); \
84+ EigenTensorNd output_nd((output_data), (shape_y).at(0), (shape_y).at(1), (shape_y).at(kDim2), \
85+ (shape_y).at(kDim3), (shape_y).at(kDim4)); \
86+ Eigen::array<Eigen::DenseIndex, kDim5> perm_5d; \
87+ CONJUGATETRANSPOSE_COMPUTE_CASE3(kDim5, perm_5d) \
88+ output_nd = input_nd.shuffle(perm_5d).conjugate(); \
89+ } while (0)
90+ 
91+#define CONJUGATETRANSPOSE_COMPUTE_DIM6(input_data, shape_x, output_data, shape_y) \
92+ do { \
93+ typedef Eigen::TensorMap<Eigen::Tensor<T, kDim6, Eigen::RowMajor>, Eigen::Aligned> EigenTensorNd; \
94+ EigenTensorNd input_nd((input_data), (shape_x).at(0), (shape_x).at(1), (shape_x).at(kDim2), \
95+ (shape_x).at(kDim3), (shape_x).at(kDim4), (shape_x).at(kDim5)); \
96+ EigenTensorNd output_nd((output_data), (shape_y).at(0), (shape_y).at(1), (shape_y).at(kDim2), \
97+ (shape_y).at(kDim3), (shape_y).at(kDim4), (shape_y).at(kDim5)); \
98+ Eigen::array<Eigen::DenseIndex, kDim6> perm_6d; \
99+ CONJUGATETRANSPOSE_COMPUTE_CASE3(kDim6, perm_6d) \
100+ output_nd = input_nd.shuffle(perm_6d).conjugate(); \
101+ } while (0)
102+ 
103+#define CONJUGATETRANSPOSE_COMPUTE_DIM7(input_data, shape_x, output_data, shape_y) \
104+ do { \
105+ typedef Eigen::TensorMap<Eigen::Tensor<T, kDim7, Eigen::RowMajor>, Eigen::Aligned> EigenTensorNd; \
106+ EigenTensorNd input_nd((input_data), (shape_x).at(0), (shape_x).at(1), (shape_x).at(kDim2), \
107+ (shape_x).at(kDim3), (shape_x).at(kDim4), (shape_x).at(kDim5), (shape_x).at(kDim6)); \
108+ EigenTensorNd output_nd((output_data), (shape_y).at(0), (shape_y).at(1), (shape_y).at(kDim2), \
109+ (shape_y).at(kDim3), (shape_y).at(kDim4), (shape_y).at(kDim5), (shape_y).at(kDim6)); \
110+ Eigen::array<Eigen::DenseIndex, kDim7> perm_7d; \
111+ CONJUGATETRANSPOSE_COMPUTE_CASE3(kDim7, perm_7d) \
112+ output_nd = input_nd.shuffle(perm_7d).conjugate(); \
113+ } while (0)
114+} // namespace
115+ 
116+namespace aicpu {
117+KernelStatus ConjugateTranspose::GetConjugateTransposeValue(Tensor* tensor, std::vector<int64_t>& value)
118+{
119+ value.clear();
120+ auto type = tensor->GetDataType();
121+ if (type == DT_INT32) {
122+ auto data = reinterpret_cast<int32_t*>(tensor->GetData());
123+ for (unsigned int i = 0; i < tensor->NumElements(); i++) {
124+ value.push_back(static_cast<int64_t>(*(data + i)));
125+ }
126+ } else if (type == DT_INT64) {
127+ auto data = reinterpret_cast<int64_t*>(tensor->GetData());
128+ for (unsigned int i = 0; i < tensor->NumElements(); i++) {
129+ value.push_back(*(data + i));
130+ }
131+ } else {
132+ return KERNEL_STATUS_PARAM_INVALID;
133+ }
134+ return KERNEL_STATUS_OK;
135+}
136+ 
137+uint32_t ConjugateTranspose::Compute(CpuKernelContext& ctx)
138+{
139+ KERNEL_HANDLE_ERROR(NormalCheck(ctx, kInputNum, kOutputNum), "[%s] check input and output failed.",
140+ kConjugateTranspose);
141+ KERNEL_HANDLE_ERROR(ConjugateTransposeParamCheck(ctx), "[%s] check params failed.", kConjugateTranspose);
142+ auto x_type = ctx.Input(0)->GetDataType();
143+ switch (x_type) {
144+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_COMPLEX64, std::complex<float>, ctx)
145+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_COMPLEX128, std::complex<double>, ctx)
146+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_FLOAT16, Eigen::half, ctx)
147+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_FLOAT, float, ctx)
148+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_DOUBLE, double, ctx)
149+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_BOOL, bool, ctx)
150+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_INT8, std::int8_t, ctx)
151+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_INT16, std::int16_t, ctx)
152+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_INT32, std::int32_t, ctx)
153+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_INT64, std::int64_t, ctx)
154+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_UINT8, std::uint8_t, ctx)
155+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_UINT16, std::uint16_t, ctx)
156+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_UINT32, std::uint32_t, ctx)
157+ CONJUGATETRANSPOSE_COMPUTE_CASE(DT_UINT64, std::uint64_t, ctx)
158+ default:
159+ KERNEL_LOG_ERROR("ConjugateTranspose kernel data type [%s] not support.", DTypeStr(x_type).c_str());
160+ return static_cast<uint32_t>(KERNEL_STATUS_PARAM_INVALID);
161+ }
162+ 
163+ return static_cast<uint32_t>(KERNEL_STATUS_OK);
164+}
165+ 
166+KernelStatus ConjugateTranspose::ConjugateTransposeParamCheck(const CpuKernelContext& ctx)
167+{
168+ std::vector<int64_t> shape_x = ctx.Input(0)->GetTensorShape()->GetDimSizes();
169+ std::vector<int64_t> shape_perm = ctx.Input(kPermInputIndex)->GetTensorShape()->GetDimSizes();
170+ auto perm_tensor = ctx.Input(kPermInputIndex);
171+ auto y_tensor = ctx.Output(0);
172+ KERNEL_CHECK_FALSE((shape_perm.size() == 1), KERNEL_STATUS_PARAM_INVALID,
173+ "Expected perm to "
174+ "be 1-D tensors , but got [%zu]-D tensors.",
175+ shape_perm.size())
176+ KERNEL_CHECK_FALSE((perm_tensor->NumElements() == (unsigned int)shape_x.size()), KERNEL_STATUS_PARAM_INVALID,
177+ "Expected the size of perm to be [%zu], but "
178+ "got [%ld].",
179+ shape_x.size(), perm_tensor->NumElements())
180+ KERNEL_CHECK_FALSE((GetConjugateTransposeValue(perm_tensor, perm) == KERNEL_STATUS_OK), KERNEL_STATUS_PARAM_INVALID,
181+ "perm must be either int32 or int64, "
182+ "but got [%s].",
183+ DTypeStr(perm_tensor->GetDataType()).c_str())
184+ KERNEL_CHECK_FALSE((shape_x.size() > 1), KERNEL_STATUS_PARAM_INVALID,
185+ "Expected the dimension of x to be greater than 1-D, but got [%zu].", shape_x.size())
186+ std::vector<int64_t> shape_y;
187+ for (size_t i = 0; i < shape_x.size(); ++i) {
188+ int64_t perm_value = perm.at(i);
189+ if (shape_x.at(i) == 0) {
190+ KERNEL_CHECK_FALSE((perm_value == 0), KERNEL_STATUS_PARAM_INVALID,
191+ "Expected perm[%zu] == 0 (got %ld), when x shape[%zu] == 0.", i, perm_value, i)
192+ } else {
193+ KERNEL_CHECK_FALSE((0 <= perm_value && perm_value <= (unsigned int)shape_x.size() - 1),
194+ KERNEL_STATUS_PARAM_INVALID, "Expected perm[%zu] in [0, %zu], but got %ld.", i,
195+ shape_x.size(), perm_value)
196+ }
197+ int64_t temp_value = 0;
198+ for (size_t j = 0; j < shape_x.size(); ++j) {
199+ if ((unsigned int)perm.at(j) == i) {
200+ break;
201+ } else {
202+ temp_value = j + 1;
203+ KERNEL_CHECK_FALSE((temp_value < (unsigned int)shape_x.size()), KERNEL_STATUS_PARAM_INVALID,
204+ "Expected perm value is unique.")
205+ }
206+ }
207+ shape_y.push_back(shape_x.at(perm_value));
208+ }
209+ y_tensor->GetTensorShape()->SetDimSizes(shape_y);
210+ return KERNEL_STATUS_OK;
211+}
212+ 
213+template <typename T>
214+KernelStatus ConjugateTranspose::ConjugateTransposeCompute(const CpuKernelContext& ctx)
215+{
216+ auto x_data = ctx.Input(0)->GetData();
217+ auto y_data = ctx.Output(0)->GetData();
218+ std::vector<int64_t> shape_x = ctx.Input(0)->GetTensorShape()->GetDimSizes();
219+ std::vector<int64_t> shape_y = ctx.Output(0)->GetTensorShape()->GetDimSizes();
220+ auto input_data = reinterpret_cast<T*>(x_data);
221+ auto output_data = reinterpret_cast<T*>(y_data);
222+ int64_t input_dims = static_cast<int64_t>(shape_x.size());
223+ switch (input_dims) {
224+ case kDim2: {
225+ CONJUGATETRANSPOSE_COMPUTE_DIM2(input_data, shape_x, output_data, shape_y);
226+ break;
227+ }
228+ case kDim3: {
229+ CONJUGATETRANSPOSE_COMPUTE_DIM3(input_data, shape_x, output_data, shape_y);
230+ break;
231+ }
232+ case kDim4: {
233+ CONJUGATETRANSPOSE_COMPUTE_DIM4(input_data, shape_x, output_data, shape_y);
234+ break;
235+ }
236+ case kDim5: {
237+ CONJUGATETRANSPOSE_COMPUTE_DIM5(input_data, shape_x, output_data, shape_y);
238+ break;
239+ }
240+ case kDim6: {
241+ CONJUGATETRANSPOSE_COMPUTE_DIM6(input_data, shape_x, output_data, shape_y);
242+ break;
243+ }
244+ case kDim7: {
245+ CONJUGATETRANSPOSE_COMPUTE_DIM7(input_data, shape_x, output_data, shape_y);
246+ break;
247+ }
248+ default:
249+ KERNEL_LOG_ERROR("[%s] : Unhandled input dimensions [%ld].", kConjugateTranspose, input_dims);
250+ return KERNEL_STATUS_INNER_ERROR;
251+ }
252+ return KERNEL_STATUS_OK;
253+}
254+REGISTER_CPU_KERNEL(kConjugateTranspose, ConjugateTranspose);
255+} // namespace aicpu
@@ -0,0 +1,34 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+#ifndef AICPU_KERNELS_NORMALIZED_CONJUGATETRANSPOSE_H_
11+#define AICPU_KERNELS_NORMALIZED_CONJUGATETRANSPOSE_H_
12+ 
13+#include <vector>
14+ 
15+#include "cpu_kernel.h"
16+#include "utils/status.h"
17+ 
18+namespace aicpu {
19+class ConjugateTranspose : public CpuKernel {
20+public:
21+ ~ConjugateTranspose() = default;
22+ 
23+ uint32_t Compute(CpuKernelContext& ctx) override;
24+ 
25+private:
26+ std::vector<int64_t> perm;
27+ KernelStatus ConjugateTransposeParamCheck(const CpuKernelContext& ctx);
28+ KernelStatus GetConjugateTransposeValue(Tensor* tensor, std::vector<int64_t>& value);
29+ 
30+ template <typename T>
31+ KernelStatus ConjugateTransposeCompute(const CpuKernelContext& ctx);
32+};
33+} // namespace aicpu
34+#endif // AICPU_KERNELS_NORMALIZED_CONJUGATETRANSPOSE_H_
@@ -0,0 +1,33 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include "register/op_def_registry.h"
12+#include "../../../common/inc/aicpu/aicpu_op_def.h"
13+ 
14+namespace ops {
15+class ConjugateTranspose : public OpDef {
16+public:
17+ explicit ConjugateTranspose(const char* name) : OpDef(name)
18+ {
19+ this->Input("x").DataType({ge::DT_COMPLEX64, ge::DT_COMPLEX128, ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_DOUBLE,
20+ ge::DT_BOOL, ge::DT_INT8, ge::DT_INT16, ge::DT_INT32, ge::DT_INT64, ge::DT_UINT8,
21+ ge::DT_UINT16, ge::DT_UINT32, ge::DT_UINT64});
22+ this->Input("perm").DataType({ge::DT_INT32, ge::DT_INT64});
23+ this->Output("y").DataType({ge::DT_COMPLEX64, ge::DT_COMPLEX128, ge::DT_FLOAT16, ge::DT_FLOAT, ge::DT_DOUBLE,
24+ ge::DT_BOOL, ge::DT_INT8, ge::DT_INT16, ge::DT_INT32, ge::DT_INT64, ge::DT_UINT8,
25+ ge::DT_UINT16, ge::DT_UINT32, ge::DT_UINT64});
26+ 
27+ ApplyMathAicpuDefaultCfg(*this);
28+ this->AICPU().ExtendCfgInfo(OP_INFO_OPS_FLAG.c_str(), OPEN_OPS_FLAG.c_str());
29+ }
30+};
31+ 
32+OP_ADD(ConjugateTranspose);
33+} // namespace ops
@@ -0,0 +1,17 @@
1+# ----------------------------------------------------------------------------
2+# This program is free software, you can redistribute it and/or modify it.
3+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
4+# This file is a part of the CANN Open Software.
5+# Licensed under CANN Open Software License Agreement Version 2.0 (the "License").
6+# Please refer to the License for details. You may not use this file except in compliance with the License.
7+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
8+# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
9+# See LICENSE in the root of the software repository for the full text of the License.
10+# ----------------------------------------------------------------------------
11+ 
12+file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)
13+foreach(SUB_DIR ${CURRENT_DIRS})
14+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt")
15+ add_subdirectory(${SUB_DIR})
16+ endif()
17+endforeach()
@@ -0,0 +1,13 @@
1+# ----------------------------------------------------------------------------
2+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+# CANN Open Software License Agreement Version 2.0 (the "License").
5+# Please refer to the License for details. You may not use this file except in compliance with the License.
6+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+# See LICENSE in the root of the software repository for the full text of the License.
9+# ----------------------------------------------------------------------------
10+ 
11+if(UT_TEST_ALL OR OP_HOST_UT)
12+ add_modules_ut_sources(UT_NAME ${OP_INFERSHAPE_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR})
13+endif()
@@ -0,0 +1,81 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include <gtest/gtest.h>
12+#include <iostream>
13+#include "infershape_context_faker.h"
14+#include "infershape_case_executor.h"
15+ 
16+using namespace ge;
17+class ConjugateTransposeInferShapeTest : public testing::Test {
18+protected:
19+ static void SetUpTestCase() { std::cout << "ConjugateTransposeInferShapeTest SetUp" << std::endl; }
20+ 
21+ static void TearDownTestCase() { std::cout << "ConjugateTransposeInferShapeTest TearDown" << std::endl; }
22+};
23+ 
24+TEST_F(ConjugateTransposeInferShapeTest, conjugate_transpose_int32_perm)
25+{
26+ int32_t perm_value[3] = {0, 2, 1};
27+ gert::InfershapeContextPara::TensorDescription x({{3, 2, 4}, {3, 2, 4}}, ge::DT_COMPLEX128, ge::FORMAT_ND);
28+ gert::InfershapeContextPara::TensorDescription perm({{3}, {3}}, ge::DT_INT32, ge::FORMAT_ND, true, &perm_value);
29+ gert::InfershapeContextPara::TensorDescription out({{1}, {1}}, ge::DT_COMPLEX128, ge::FORMAT_ND);
30+ gert::InfershapeContextPara infershapeContextPara("ConjugateTranspose", {x, perm}, {out});
31+ std::vector<std::vector<int64_t>> expectOutputShape = {{3, 4, 2}};
32+ ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape);
33+}
34+ 
35+TEST_F(ConjugateTransposeInferShapeTest, conjugate_transpose_int64_perm)
36+{
37+ int64_t perm_value[2] = {1, 0};
38+ gert::InfershapeContextPara::TensorDescription x({{2, 3}, {2, 3}}, ge::DT_COMPLEX64, ge::FORMAT_ND);
39+ gert::InfershapeContextPara::TensorDescription perm({{2}, {2}}, ge::DT_INT64, ge::FORMAT_ND, true, &perm_value);
40+ gert::InfershapeContextPara::TensorDescription out({{1}, {1}}, ge::DT_COMPLEX64, ge::FORMAT_ND);
41+ gert::InfershapeContextPara infershapeContextPara("ConjugateTranspose", {x, perm}, {out});
42+ std::vector<std::vector<int64_t>> expectOutputShape = {{3, 2}};
43+ ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape);
44+}
45+ 
46+// negative perm is not supported by ConjugateTranspose (perm must be in [0, rank-1],
47+// aligned with the AICPU kernel and the canndev rt1 contract) -> failure
48+TEST_F(ConjugateTransposeInferShapeTest, conjugate_transpose_negative_perm_rejected)
49+{
50+ int64_t perm_value[3] = {-1, -2, 0};
51+ gert::InfershapeContextPara::TensorDescription x({{10, 20, 30}, {10, 20, 30}}, ge::DT_DOUBLE, ge::FORMAT_ND);
52+ gert::InfershapeContextPara::TensorDescription perm({{3}, {3}}, ge::DT_INT64, ge::FORMAT_ND, true, &perm_value);
53+ gert::InfershapeContextPara::TensorDescription out({{1}, {1}}, ge::DT_DOUBLE, ge::FORMAT_ND);
54+ gert::InfershapeContextPara infershapeContextPara("ConjugateTranspose", {x, perm}, {out});
55+ std::vector<std::vector<int64_t>> expectOutputShape = {};
56+ ExecuteTestCase(infershapeContextPara, ge::GRAPH_FAILED, expectOutputShape);
57+}
58+ 
59+// perm size mismatch with input dims -> failure
60+TEST_F(ConjugateTransposeInferShapeTest, conjugate_transpose_perm_size_mismatch)
61+{
62+ int64_t perm_value[3] = {0, 1, 2};
63+ gert::InfershapeContextPara::TensorDescription x({{10, 20, 30, 40}, {10, 20, 30, 40}}, ge::DT_FLOAT, ge::FORMAT_ND);
64+ gert::InfershapeContextPara::TensorDescription perm({{3}, {3}}, ge::DT_INT64, ge::FORMAT_ND, true, &perm_value);
65+ gert::InfershapeContextPara::TensorDescription out({{1}, {1}}, ge::DT_FLOAT, ge::FORMAT_ND);
66+ gert::InfershapeContextPara infershapeContextPara("ConjugateTranspose", {x, perm}, {out});
67+ std::vector<std::vector<int64_t>> expectOutputShape = {};
68+ ExecuteTestCase(infershapeContextPara, ge::GRAPH_FAILED, expectOutputShape);
69+}
70+ 
71+// perm value out of valid range (perm[i] >= dimSize) -> failure
72+TEST_F(ConjugateTransposeInferShapeTest, conjugate_transpose_perm_out_of_range)
73+{
74+ int32_t perm_value[3] = {0, 3, 1};
75+ gert::InfershapeContextPara::TensorDescription x({{3, 2, 4}, {3, 2, 4}}, ge::DT_COMPLEX128, ge::FORMAT_ND);
76+ gert::InfershapeContextPara::TensorDescription perm({{3}, {3}}, ge::DT_INT32, ge::FORMAT_ND, true, &perm_value);
77+ gert::InfershapeContextPara::TensorDescription out({{1}, {1}}, ge::DT_COMPLEX128, ge::FORMAT_ND);
78+ gert::InfershapeContextPara infershapeContextPara("ConjugateTranspose", {x, perm}, {out});
79+ std::vector<std::vector<int64_t>> expectOutputShape = {};
80+ ExecuteTestCase(infershapeContextPara, ge::GRAPH_FAILED, expectOutputShape);
81+}
@@ -0,0 +1,113 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+#include "gtest/gtest.h"
11+#ifndef private
12+#define private public
13+#define protected public
14+#endif
15+#include "utils/aicpu_test_utils.h"
16+#include "cpu_kernel_utils.h"
17+#include "node_def_builder.h"
18+#undef private
19+#undef protected
20+#include <complex>
21+ 
22+using namespace std;
23+using namespace aicpu;
24+ 
25+class TEST_CONJUGATETRANSPOSE_UT : public testing::Test {};
26+ 
27+#define CREATE_NODEDEF(node_def, shapes, data_types, datas) \
28+ NodeDefBuilder(node_def.get(), "ConjugateTranspose", "ConjugateTranspose") \
29+ .Input({"x", data_types[0], shapes[0], datas[0]}) \
30+ .Input({"perm", data_types[1], shapes[1], datas[1]}) \
31+ .Output({"y", data_types[2], shapes[2], datas[2]})
32+ 
33+// x {2,3} complex128, perm {1,0} -> y {3,2}: transpose then conjugate.
34+TEST_F(TEST_CONJUGATETRANSPOSE_UT, DATA_TYPE_COMPLEX128_SUCC)
35+{
36+ vector<DataType> data_types = {DT_COMPLEX128, DT_INT32, DT_COMPLEX128};
37+ vector<vector<int64_t>> shapes = {{2, 3}, {2}, {3, 2}};
38+ complex<double> input0[6] = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}};
39+ int32_t input1[2] = {1, 0};
40+ complex<double> output_exp[6] = {{1, -1}, {4, -4}, {2, -2}, {5, -5}, {3, -3}, {6, -6}};
41+ complex<double> output[6];
42+ vector<void*> datas = {(void*)input0, (void*)input1, (void*)output};
43+ auto node_def = CpuKernelUtils::CreateNodeDef();
44+ CREATE_NODEDEF(node_def, shapes, data_types, datas);
45+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
46+ bool compare = CompareResult(output, output_exp, 6);
47+ EXPECT_EQ(compare, true);
48+}
49+ 
50+// x {2,3} complex64, perm {1,0} -> y {3,2}.
51+TEST_F(TEST_CONJUGATETRANSPOSE_UT, DATA_TYPE_COMPLEX64_SUCC)
52+{
53+ vector<DataType> data_types = {DT_COMPLEX64, DT_INT64, DT_COMPLEX64};
54+ vector<vector<int64_t>> shapes = {{2, 3}, {2}, {3, 2}};
55+ complex<float> input0[6] = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}};
56+ int64_t input1[2] = {1, 0};
57+ complex<float> output_exp[6] = {{1, -1}, {4, -4}, {2, -2}, {5, -5}, {3, -3}, {6, -6}};
58+ complex<float> output[6];
59+ vector<void*> datas = {(void*)input0, (void*)input1, (void*)output};
60+ auto node_def = CpuKernelUtils::CreateNodeDef();
61+ CREATE_NODEDEF(node_def, shapes, data_types, datas);
62+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
63+ bool compare = CompareResult(output, output_exp, 6);
64+ EXPECT_EQ(compare, true);
65+}
66+ 
67+// x {2,3} bool, perm {1,0} -> y {3,2}: conjugate is identity for real types.
68+TEST_F(TEST_CONJUGATETRANSPOSE_UT, DATA_TYPE_BOOL_SUCC)
69+{
70+ vector<DataType> data_types = {DT_BOOL, DT_INT32, DT_BOOL};
71+ vector<vector<int64_t>> shapes = {{2, 3}, {2}, {3, 2}};
72+ bool input0[6] = {false, false, false, true, true, true};
73+ int32_t input1[2] = {1, 0};
74+ bool output_exp[6] = {false, true, false, true, false, true};
75+ bool output[6];
76+ vector<void*> datas = {(void*)input0, (void*)input1, (void*)output};
77+ auto node_def = CpuKernelUtils::CreateNodeDef();
78+ CREATE_NODEDEF(node_def, shapes, data_types, datas);
79+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
80+ bool compare = CompareResult(output, output_exp, 6);
81+ EXPECT_EQ(compare, true);
82+}
83+ 
84+// x {2,2,2} int32, perm {0,2,1} -> swap last two axes.
85+TEST_F(TEST_CONJUGATETRANSPOSE_UT, DATA_TYPE_INT32_3D_SUCC)
86+{
87+ vector<DataType> data_types = {DT_INT32, DT_INT32, DT_INT32};
88+ vector<vector<int64_t>> shapes = {{2, 2, 2}, {3}, {2, 2, 2}};
89+ int32_t input0[8] = {0, 1, 2, 3, 4, 5, 6, 7};
90+ int32_t input1[3] = {0, 2, 1};
91+ int32_t output_exp[8] = {0, 2, 1, 3, 4, 6, 5, 7};
92+ int32_t output[8];
93+ vector<void*> datas = {(void*)input0, (void*)input1, (void*)output};
94+ auto node_def = CpuKernelUtils::CreateNodeDef();
95+ CREATE_NODEDEF(node_def, shapes, data_types, datas);
96+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
97+ bool compare = CompareResult(output, output_exp, 8);
98+ EXPECT_EQ(compare, true);
99+}
100+ 
101+// perm is not 1-D -> param invalid.
102+TEST_F(TEST_CONJUGATETRANSPOSE_UT, PERM_NOT_1D_EXCEPTION)
103+{
104+ vector<DataType> data_types = {DT_COMPLEX128, DT_INT32, DT_COMPLEX128};
105+ vector<vector<int64_t>> shapes = {{2, 3}, {2, 1}, {3, 2}};
106+ complex<double> input0[6] = {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}};
107+ int32_t input1[2] = {1, 0};
108+ complex<double> output[6];
109+ vector<void*> datas = {(void*)input0, (void*)input1, (void*)output};
110+ auto node_def = CpuKernelUtils::CreateNodeDef();
111+ CREATE_NODEDEF(node_def, shapes, data_types, datas);
112+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID);
113+}
@@ -486,6 +486,16 @@
486 <td> </td>486 <td> </td>
487 <td> </td>487 <td> </td>
488 </tr>488 </tr>
489+ <tr>
490+ <td>math</td>
491+ <td><a href="../../math/conj/README.md">conj</a></td>
492+ <td>√</td>
493+ <td>√</td>
494+ <td>×</td>
495+ <td>√</td>
496+ <td>AI CPU</td>
497+ <td>返回复数张量的共轭,对输入每个复数元素取共轭(实部不变、虚部取反)。</td>
498+ </tr>
489 <tr>499 <tr>
490 <td>math</td>500 <td>math</td>
491 <td><a href="../../math/cos/README.md">cos</a></td>501 <td><a href="../../math/cos/README.md">cos</a></td>
@@ -2376,6 +2386,16 @@
2376 <td>AI CPU</td>2386 <td>AI CPU</td>
2377 <td>该算子暂无Ascend C代码实现,欢迎开发者补充贡献,贡献方式参考<a href="../../CONTRIBUTING.md">贡献指南</a>。</td>2387 <td>该算子暂无Ascend C代码实现,欢迎开发者补充贡献,贡献方式参考<a href="../../CONTRIBUTING.md">贡献指南</a>。</td>
2378 </tr>2388 </tr>
2389+ <tr>
2390+ <td>conversion</td>
2391+ <td><a href="../../conversion/conjugate_transpose/README.md">conjugate_transpose</a></td>
2392+ <td>√</td>
2393+ <td>√</td>
2394+ <td>×</td>
2395+ <td>√</td>
2396+ <td>AI CPU</td>
2397+ <td>按perm指定的维度顺序对输入x做转置并取共轭,实数类型等价于普通Transpose。</td>
2398+ </tr>
2379 <tr>2399 <tr>
2380 <td>conversion</td>2400 <td>conversion</td>
2381 <td><a href="../../conversion/unpack/README.md">unpack</a></td>2401 <td><a href="../../conversion/unpack/README.md">unpack</a></td>
@@ -0,0 +1,11 @@
1+# ---------------------------------------------------------------------------------------------------------
2+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+# CANN Open Software License Agreement Version 2.0 (the "License").
5+# Please refer to the License for details. You may not use this file except in compliance with the License.
6+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+# See LICENSE in the root of the software repository for the full text of the License.
9+# ---------------------------------------------------------------------------------------------------------
10+ 
11+add_all_modules_sources(OPTYPE conj ACLNNTYPE aclnn_exclude)
@@ -0,0 +1,63 @@
1+# Conj
2+ 
3+## 产品支持情况
4+ 
5+| 产品 | 是否支持 |
6+| :----------------------------------------------------------- | :------: |
7+| <term>Ascend 950PR/Ascend 950DT</term> | √ |
8+| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ |
9+| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ |
10+| <term>Atlas 200I/500 A2 推理产品</term> | × |
11+| <term>Atlas 推理系列产品</term> | √ |
12+| <term>Atlas 训练系列产品</term> | √ |
13+ 
14+## 功能说明
15+ 
16+- 算子功能:返回复数张量的共轭。对输入的每个复数元素取共轭(实部不变、虚部取反)。
17+ 
18+- 计算公式:output = conj(input),即output = a - bi,其中input = a + bi
19+ 
20+## 参数说明
21+ 
22+<table style="undefined;table-layout: fixed; width: 1576px"><colgroup>
23+ <col style="width: 170px">
24+ <col style="width: 170px">
25+ <col style="width: 310px">
26+ <col style="width: 212px">
27+ <col style="width: 100px">
28+ </colgroup>
29+ <thead>
30+ <tr>
31+ <th>参数名</th>
32+ <th>输入/输出/属性</th>
33+ <th>描述</th>
34+ <th>数据类型</th>
35+ <th>数据格式</th>
36+ </tr></thead>
37+ <tbody>
38+ <tr>
39+ <td>input</td>
40+ <td>输入</td>
41+ <td>输入复数张量。</td>
42+ <td>COMPLEX64、COMPLEX128</td>
43+ <td>ND</td>
44+ </tr>
45+ <tr>
46+ <td>output</td>
47+ <td>输出</td>
48+ <td>输入张量的共轭,shape与input一致。</td>
49+ <td>COMPLEX64、COMPLEX128</td>
50+ <td>ND</td>
51+ </tr>
52+ 
53+ </tbody></table>
54+ 
55+## 约束说明
56+ 
57+- 无。
58+ 
59+## 调用说明
60+ 
61+| 调用方式 | 样例代码 | 说明 |
62+| ---------------- | --------------------------- | --------------------------------------------------- |
63+| 图模式调用 | [test_geir_conj](./examples/test_geir_conj.cpp) | 通过[算子IR](./op_graph/conj_proto.h)构图方式调用conj算子。 |
@@ -0,0 +1,296 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include <iostream>
12+#include <fstream>
13+#include <string.h>
14+#include <stdint.h>
15+#include <vector>
16+#include <string>
17+#include <map>
18+#include <complex>
19+#include "assert.h"
20+ 
21+#include "graph.h"
22+#include "types.h"
23+#include "tensor.h"
24+#include "ge_error_codes.h"
25+#include "ge_api_types.h"
26+#include "ge_api.h"
27+#include "ge_ir_build.h"
28+ 
29+#include "../op_graph/conj_proto.h"
30+ 
31+#define FAILED -1
32+#define SUCCESS 0
33+ 
34+namespace ge {
35+REG_OP(Data).INPUT(x, TensorType::ALL()).OUTPUT(y, TensorType::ALL()).ATTR(index, Int, 0).OP_END_FACTORY_REG(Data)
36+}
37+ 
38+using namespace ge;
39+using std::map;
40+using std::string;
41+using std::vector;
42+ 
43+#define LOG_PRINT(message, ...) printf(message, ##__VA_ARGS__)
44+ 
45+string GetTime()
46+{
47+ time_t timep;
48+ time(&timep);
49+ char tmp[64];
50+ strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S,000", localtime(&timep));
51+ return tmp;
52+}
53+ 
54+uint32_t GetDataTypeSize(DataType dt)
55+{
56+ if (dt == ge::DT_COMPLEX64) {
57+ return static_cast<uint32_t>(sizeof(std::complex<float>));
58+ } else if (dt == ge::DT_COMPLEX128) {
59+ return static_cast<uint32_t>(sizeof(std::complex<double>));
60+ }
61+ return static_cast<uint32_t>(sizeof(int32_t));
62+}
63+ 
64+std::string DataTypeToString(DataType dt)
65+{
66+ switch (dt) {
67+ case ge::DT_COMPLEX64:
68+ return "DT_COMPLEX64";
69+ case ge::DT_COMPLEX128:
70+ return "DT_COMPLEX128";
71+ default:
72+ return "DTYPE(" + std::to_string(static_cast<int>(dt)) + ")";
73+ }
74+}
75+ 
76+// Generate complex input data. Uses COMPLEX128 (std::complex<double>) as the
77+// default validation dtype (COMPLEX128 > COMPLEX64 > DOUBLE priority).
78+int32_t GenComplexData(vector<int64_t> shapes, Tensor& input_tensor, TensorDesc& input_tensor_desc)
79+{
80+ input_tensor_desc.SetRealDimCnt(shapes.size());
81+ size_t size = 1;
82+ for (uint32_t i = 0; i < shapes.size(); i++) {
83+ size *= shapes[i];
84+ }
85+ uint32_t data_len = size * sizeof(std::complex<double>);
86+ std::complex<double>* pData = new (std::nothrow) std::complex<double>[size];
87+ if (pData == nullptr) {
88+ printf("%s - ERROR - [XIR]: Allocate input data buffer failed\n", GetTime().c_str());
89+ return FAILED;
90+ }
91+ for (size_t i = 0; i < size; ++i) {
92+ pData[i] = std::complex<double>(static_cast<double>(i) + 1.0, -(static_cast<double>(i) + 1.0));
93+ }
94+ input_tensor = Tensor(input_tensor_desc, reinterpret_cast<uint8_t*>(pData), data_len);
atomgit-bot
atomgit-botatomgit-bot7月7日

🟡 Medium Priority

math/conj/examples/test_geir_conj.cpp 第 86 行,GenComplexData 使用 new (std::nothrow) 分配内存,但未检查 pData 是否为 nullptr。紧接着在第 87-89 行通过 pData[i] 写入数据。

触发条件:当系统内存不足导致 new 失败时,pDatanullptr。 失败模式:访问空指针导致段错误(segfault),程序崩溃。

建议:在 new 之后添加空指针检查:if (pData == nullptr) { return FAILED; }

likedislike
Ding_Jing
Ding_Jing
7月8日 评论:
95+ delete[] pData;
96+ return SUCCESS;
atomgit-bot
atomgit-botatomgit-bot7月7日

🟡 Medium Priority

math/conj/examples/test_geir_conj.cpp 第 86 行,GenComplexData 函数通过 new (std::nothrow) std::complex<double>[size] 分配了堆内存(pData),随后将其 reinterpret_cast 后传给 Tensor 构造函数。但该指针从未被 delete[] 释放,Tensor 析构时也不会释放这块内存(Tensor 不持有所有权)。每次调用 GenComplexData 都会泄漏 size * sizeof(std::complex<double>) 字节的内存。

触发条件:每次调用 CreateOppInGraphGenComplexData。 影响:示例程序运行期间内存持续增长,虽为一次性示例但仍是资源泄漏。

likedislike
Ding_Jing
Ding_Jing
7月8日 评论:
97+}
98+ 
99+int32_t WriteDataToFile(string bin_file, uint64_t data_size, uint8_t* inputData)
100+{
101+ FILE* fp = fopen(bin_file.c_str(), "w");
102+ if (fp == nullptr) {
103+ printf("Failed to open file %s for writing.\n", bin_file.c_str());
104+ return FAILED;
105+ }
106+ fwrite(inputData, sizeof(uint8_t), data_size, fp);
107+ fclose(fp);
108+ return SUCCESS;
atomgit-bot
atomgit-botatomgit-bot7月3日

🟡 Medium Priority

变更行:test_geir_conj.cpp 第 88 行 fopen 返回值未检查,与 test_geir_conjugate_transpose.cpp 第 96 行相同的缺陷。

建议:添加 fopen 返回值检查:if (fp == nullptr) { printf("Failed to open file %s\n", bin_file.c_str()); return FAILED; }

likedislike
Ding_Jing
Ding_Jing
7月7日 评论:
109+}
110+ 
111+int CreateOppInGraph(DataType inDtype, std::vector<ge::Tensor>& input, std::vector<Operator>& inputs,
112+ std::vector<Operator>& outputs, Graph& graph)
113+{
114+ Status ret = SUCCESS;
115+ // 自定义代码:添加单算子定义到图中
116+ auto conjOp = op::Conj("conj");
117+ 
118+ std::vector<int64_t> xShape = {2, 3};
119+ 
120+ // input
121+ auto placeholder = op::Data("placeholder0").set_attr_index(0);
122+ TensorDesc placeholder_desc = TensorDesc(ge::Shape(xShape), FORMAT_ND, inDtype);
123+ placeholder_desc.SetPlacement(ge::kPlacementHost);
124+ placeholder_desc.SetFormat(FORMAT_ND);
125+ Tensor tensor_placeholder;
126+ ret = GenComplexData(xShape, tensor_placeholder, placeholder_desc);
127+ if (ret != SUCCESS) {
128+ printf("%s - ERROR - [XIR]: Generate input data failed\n", GetTime().c_str());
129+ return FAILED;
130+ }
131+ placeholder.update_input_desc_x(placeholder_desc);
132+ input.push_back(tensor_placeholder);
133+ graph.AddOp(placeholder);
134+ conjOp.set_input_input(placeholder);
135+ conjOp.update_input_desc_input(placeholder_desc);
136+ inputs.push_back(placeholder);
137+ 
138+ // output
139+ TensorDesc output_desc = TensorDesc(ge::Shape(xShape), FORMAT_ND, inDtype);
140+ conjOp.update_output_desc_output(output_desc);
141+ 
142+ outputs.push_back(conjOp);
143+ // 添加完毕
144+ return SUCCESS;
145+}
146+ 
147+int InitializeAndSetupGraph(Graph& graph, std::vector<ge::Tensor>& input, DataType inDtype)
148+{
149+ printf("%s - INFO - [XIR]: Start to initialize ge using ge global options\n", GetTime().c_str());
150+ std::map<AscendString, AscendString> global_options = {{"ge.exec.deviceId", "0"}, {"ge.graphRunMode", "1"}};
151+ Status ret = ge::GEInitialize(global_options);
152+ if (ret != SUCCESS) {
153+ printf("%s - INFO - [XIR]: Initialize ge using ge global options failed\n", GetTime().c_str());
154+ return FAILED;
155+ }
156+ printf("%s - INFO - [XIR]: Initialize ge using ge global options success\n", GetTime().c_str());
157+ 
158+ std::vector<Operator> inputs{};
159+ std::vector<Operator> outputs{};
160+ 
161+ ret = CreateOppInGraph(inDtype, input, inputs, outputs, graph);
162+ if (ret != SUCCESS) {
163+ printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str());
164+ return FAILED;
165+ }
166+ 
167+ if (!inputs.empty() && !outputs.empty()) {
168+ graph.SetInputs(inputs).SetOutputs(outputs);
169+ }
170+ 
171+ return SUCCESS;
172+}
173+ 
174+int ExecuteGraph(Graph& graph, std::vector<ge::Tensor>& input, std::vector<ge::Tensor>& output)
175+{
176+ std::map<AscendString, AscendString> build_options = {};
177+ printf("%s - INFO - [XIR]: Start to create ir session using build options\n", GetTime().c_str());
178+ ge::Session* session = new Session(build_options);
179+ 
180+ if (session == nullptr) {
181+ printf("%s - ERROR - [XIR]: Create ir session using build options failed\n", GetTime().c_str());
182+ return FAILED;
183+ }
184+ printf("%s - INFO - [XIR]: Create ir session using build options success\n", GetTime().c_str());
185+ printf("%s - INFO - [XIR]: Start to add compute graph to ir session\n", GetTime().c_str());
186+ 
187+ std::map<AscendString, AscendString> graph_options = {};
188+ uint32_t graph_id = 0;
189+ Status ret = session->AddGraph(graph_id, graph, graph_options);
190+ if (ret != SUCCESS) {
191+ printf("%s - INFO - [XIR]: Session add ir compute graph failed\n", GetTime().c_str());
192+ delete session;
193+ GEFinalize();
194+ return FAILED;
195+ }
196+ 
197+ printf("%s - INFO - [XIR]: Session add ir compute graph to ir session success\n", GetTime().c_str());
198+ printf("%s - INFO - [XIR]: dump graph to txt\n", GetTime().c_str());
199+ std::string file_path = "./dump";
200+ aclgrphDumpGraph(graph, file_path.c_str(), file_path.length());
201+ printf("%s - INFO - [XIR]: Start to run ir compute graph\n", GetTime().c_str());
202+ 
203+ ret = session->RunGraph(graph_id, input, output);
204+ if (ret != SUCCESS) {
205+ printf("%s - INFO - [XIR]: Run graph failed\n", GetTime().c_str());
206+ delete session;
207+ GEFinalize();
208+ return FAILED;
209+ }
210+ printf("%s - INFO - [XIR]: Session run ir compute graph success\n", GetTime().c_str());
211+ 
212+ delete session;
213+ return SUCCESS;
214+}
215+ 
216+void ProcessIOData(std::vector<ge::Tensor>& input, std::vector<ge::Tensor>& output)
217+{
218+ int input_num = input.size();
219+ for (int i = 0; i < input_num; i++) {
220+ std::cout << "input " << i << " dtype : " << DataTypeToString(input[i].GetTensorDesc().GetDataType())
221+ << std::endl;
222+ string input_file = "./tc_ge_irrun_conj_input_" + std::to_string(i) + ".bin";
223+ uint8_t* input_data_i = input[i].GetData();
224+ int64_t input_shape = input[i].GetTensorDesc().GetShape().GetShapeSize();
225+ std::cout << "this is " << i << "th input, input shape size =" << input_shape << std::endl;
226+ uint32_t data_size = input_shape * GetDataTypeSize(input[i].GetTensorDesc().GetDataType());
227+ WriteDataToFile((const char*)input_file.c_str(), data_size, input_data_i);
228+ }
229+ 
230+ int output_num = output.size();
231+ for (int i = 0; i < output_num; i++) {
232+ std::cout << "output " << i << " dtype : " << DataTypeToString(output[i].GetTensorDesc().GetDataType())
233+ << std::endl;
234+ string output_file = "./tc_ge_irrun_conj_output_" + std::to_string(i) + ".bin";
235+ uint8_t* output_data_i = output[i].GetData();
236+ int64_t output_shape = output[i].GetTensorDesc().GetShape().GetShapeSize();
237+ std::cout << "this is " << i << "th output, output shape size =" << output_shape << std::endl;
238+ uint32_t data_size = output_shape * GetDataTypeSize(output[i].GetTensorDesc().GetDataType());
239+ WriteDataToFile((const char*)output_file.c_str(), data_size, output_data_i);
240+ // Print the actual output tensor values before validation for observability.
241+ std::complex<double>* resultData = reinterpret_cast<std::complex<double>*>(output_data_i);
242+ for (int64_t j = 0; j < output_shape; j++) {
243+ LOG_PRINT("result[%ld] = (%f, %f)\n", j, resultData[j].real(), resultData[j].imag());
244+ }
245+ }
246+}
247+ 
248+int main(int argc, char* argv[])
249+{
250+ // 1、创建图对象
251+ const char* graph_name = "tc_ge_irrun_conj_test";
252+ Graph graph(graph_name);
253+ std::vector<ge::Tensor> input;
254+ 
255+ if (argc > 1) {
256+ std::cout << argv[1] << std::endl;
257+ }
258+ 
259+ DataType inDtype = DT_COMPLEX128;
260+ 
261+ std::cout << inDtype << std::endl;
262+ 
263+ // 初始化和设置图
264+ if (InitializeAndSetupGraph(graph, input, inDtype) != SUCCESS) {
265+ return FAILED;
266+ }
267+ 
268+ // 执行图计算
269+ std::vector<ge::Tensor> output;
270+ if (ExecuteGraph(graph, input, output) != SUCCESS) {
271+ return FAILED;
272+ }
273+ 
274+ // 处理输入输出数据
275+ ProcessIOData(input, output);
276+ 
277+ ge::AscendString error_msg = ge::GEGetErrorMsgV2();
278+ std::string error_str(error_msg.GetString());
279+ if (!error_str.empty()) {
280+ std::cout << "Error message: " << error_str << std::endl;
281+ }
282+ ge::AscendString warning_msg = ge::GEGetWarningMsgV2();
283+ std::string warning_str(warning_msg.GetString());
284+ if (!warning_str.empty()) {
285+ std::cout << "Warning message: " << warning_str << std::endl;
286+ }
287+ printf("%s - INFO - [XIR]: Precision is ok\n", GetTime().c_str());
288+ printf("%s - INFO - [XIR]: Start to finalize ir graph session\n", GetTime().c_str());
289+ Status ret = ge::GEFinalize();
290+ if (ret != SUCCESS) {
291+ printf("%s - INFO - [XIR]: Finalize ir graph session failed\n", GetTime().c_str());
292+ return FAILED;
293+ }
294+ printf("%s - INFO - [XIR]: Finalize ir graph session success\n", GetTime().c_str());
295+ return SUCCESS;
296+}
@@ -0,0 +1,25 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include "register/op_impl_registry.h"
12+#include "log/log.h"
13+ 
14+using namespace ge;
15+namespace ops {
16+static ge::graphStatus InferDataType4Conj(gert::InferDataTypeContext* context)
17+{
18+ OP_LOGI("Begin InferDataType4Conj");
19+ const ge::DataType inputDataType = context->GetInputDataType(0);
20+ context->SetOutputDataType(0, inputDataType);
21+ return ge::GRAPH_SUCCESS;
22+}
23+ 
24+IMPL_OP(Conj).InferDataType(InferDataType4Conj);
25+} // namespace ops
@@ -0,0 +1,39 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+/*!
12+ * \file conj_proto.h
13+ * \brief
14+ */
15+#ifndef OPS_OP_CONJ_PROTO_H_
16+#define OPS_OP_CONJ_PROTO_H_
17+ 
18+#include "graph/operator_reg.h"
19+#include "graph/operator.h"
20+ 
21+namespace ge {
22+/**
23+ *@brief Returns the complex conjugate of a complex number.
24+ 
25+ *@par Inputs:
26+ *input:A Tensor.
27+ 
28+ *@par Outputs:
29+ *output:A Tensor. Has the same shape as input.
30+ 
31+ *@par Third-party framework compatibility.
32+ *Compatible with tensorflow output operator.
33+ */
34+REG_OP(Conj)
35+ .INPUT(input, TensorType({DT_COMPLEX64, DT_COMPLEX128}))
36+ .OUTPUT(output, TensorType({DT_COMPLEX64, DT_COMPLEX128}))
37+ .OP_END_FACTORY_REG(Conj)
38+} // namespace ge
39+#endif
@@ -0,0 +1,23 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+#include "infershape_elewise_util.h"
11+#include "register/op_impl_registry.h"
12+#include "log/log.h"
13+ 
14+using namespace ge;
15+namespace ops {
16+static ge::graphStatus InferShape4Conj(gert::InferShapeContext* context)
17+{
18+ OP_LOGI("Begin InferShape4Conj");
19+ return Ops::Base::InferShape4Elewise(context);
20+}
21+ 
22+IMPL_OP_INFERSHAPE(Conj).InferShape(InferShape4Conj);
23+} // namespace ops
@@ -0,0 +1,93 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+#include "conj_aicpu.h"
11+ 
12+#include <complex>
13+ 
14+#include "cpu_kernel_utils.h"
15+#include "cpu_types.h"
16+#include "log.h"
17+#include "status.h"
18+#include "utils/kernel_util.h"
19+ 
20+namespace {
21+const uint32_t kOutputNum = 1;
22+const uint32_t kInputNum = 1;
23+const char* const kConj = "Conj";
24+constexpr int64_t kParallelDataNums = 512 * 1024;
25+ 
26+#define CONJ_COMPUTE_CASE(DTYPE, TYPE, CTX) \
27+ case (DTYPE): { \
28+ uint32_t result = ConjCompute<TYPE>(CTX); \
29+ if (result != KERNEL_STATUS_OK) { \
30+ KERNEL_LOG_ERROR("Conj kernel compute failed."); \
31+ return result; \
32+ } \
33+ break; \
34+ }
35+} // namespace
36+ 
37+namespace aicpu {
38+uint32_t Conj::Compute(CpuKernelContext& ctx)
39+{
40+ KERNEL_HANDLE_ERROR(NormalCheck(ctx, kInputNum, kOutputNum), "[%s] check input and output failed.", kConj);
41+ KERNEL_HANDLE_ERROR(ConjCheck(ctx), "[%s] check params failed.", kConj);
42+ DataType data_type = ctx.Input(0)->GetDataType();
43+ switch (data_type) {
44+ CONJ_COMPUTE_CASE(DT_COMPLEX64, std::complex<float>, ctx)
45+ CONJ_COMPUTE_CASE(DT_COMPLEX128, std::complex<double>, ctx)
46+ default:
47+ KERNEL_LOG_ERROR("Conj kernel data type [%s] not support.", DTypeStr(data_type).c_str());
48+ return KERNEL_STATUS_PARAM_INVALID;
49+ }
50+ return KERNEL_STATUS_OK;
51+}
52+ 
53+uint32_t Conj::ConjCheck(const CpuKernelContext& ctx) const
54+{
55+ auto input = ctx.Input(0);
56+ auto output = ctx.Output(0);
57+ KERNEL_CHECK_NULLPTR(input->GetData(), KERNEL_STATUS_PARAM_INVALID, "Get input data failed.")
58+ KERNEL_CHECK_NULLPTR(output->GetData(), KERNEL_STATUS_PARAM_INVALID, "Get output data failed")
59+ return KERNEL_STATUS_OK;
60+}
61+ 
62+template <typename T>
63+uint32_t Conj::ConjCompute(const CpuKernelContext& ctx) const
64+{
65+ auto input_x = reinterpret_cast<T*>(ctx.Input(0)->GetData());
66+ auto output_y = reinterpret_cast<T*>(ctx.Output(0)->GetData());
67+ int64_t data_num = ctx.Input(0)->NumElements();
68+ int64_t data_size = data_num * static_cast<int64_t>(sizeof(T));
69+ if (data_size <= kParallelDataNums) {
70+ for (int64_t i = 0; i < data_num; i++) {
71+ *(output_y + i) = std::conj(*(input_x + i));
72+ }
73+ } else {
74+ uint32_t min_core_num = 1;
75+ int64_t max_core_num = std::max(min_core_num, aicpu::CpuKernelUtils::GetCPUNum(ctx) - kResvCpuNum);
76+ if (max_core_num > data_num) {
77+ max_core_num = data_num;
78+ }
79+ auto shard_conj = [&input_x, &output_y](size_t start, size_t end) {
80+ for (size_t i = start; i < end; i++) {
81+ *(output_y + i) = std::conj(*(input_x + i));
82+ }
83+ };
84+ KERNEL_CHECK_FALSE((max_core_num != 0), KERNEL_STATUS_PARAM_INVALID,
85+ "The max core num is zero, please check input 0 elements num.");
86+ KERNEL_HANDLE_ERROR(CpuKernelUtils::ParallelFor(ctx, data_num, data_num / max_core_num, shard_conj),
87+ "Conj Compute failed.")
88+ }
89+ return KERNEL_STATUS_OK;
90+}
91+ 
92+REGISTER_CPU_KERNEL(kConj, Conj);
93+} // namespace aicpu
@@ -0,0 +1,31 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#ifndef AICPU_KERNELS_NORMALIZED_CONJ_H_
12+#define AICPU_KERNELS_NORMALIZED_CONJ_H_
13+ 
14+#include "cpu_kernel.h"
15+ 
16+namespace aicpu {
17+class Conj : public CpuKernel {
18+public:
19+ Conj() = default;
20+ ~Conj() override = default;
21+ 
22+ uint32_t Compute(CpuKernelContext& ctx) override;
23+ 
24+private:
25+ uint32_t ConjCheck(const CpuKernelContext& ctx) const;
26+ 
27+ template <typename T>
28+ uint32_t ConjCompute(const CpuKernelContext& ctx) const;
29+};
30+} // namespace aicpu
31+#endif
@@ -0,0 +1,28 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include "register/op_def_registry.h"
12+#include "../../../common/inc/aicpu/aicpu_op_def.h"
13+ 
14+namespace ops {
15+class Conj : public OpDef {
16+public:
17+ explicit Conj(const char* name) : OpDef(name)
18+ {
19+ this->Input("input").DataType({ge::DT_COMPLEX64, ge::DT_COMPLEX128});
20+ this->Output("output").DataType({ge::DT_COMPLEX64, ge::DT_COMPLEX128});
21+ 
22+ ApplyMathAicpuDefaultCfg(*this);
23+ this->AICPU().ExtendCfgInfo(OP_INFO_OPS_FLAG.c_str(), OPEN_OPS_FLAG.c_str());
24+ }
25+};
26+ 
27+OP_ADD(Conj);
28+} // namespace ops
@@ -0,0 +1,17 @@
1+# ----------------------------------------------------------------------------
2+# This program is free software, you can redistribute it and/or modify it.
3+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
4+# This file is a part of the CANN Open Software.
5+# Licensed under CANN Open Software License Agreement Version 2.0 (the "License").
6+# Please refer to the License for details. You may not use this file except in compliance with the License.
7+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
8+# BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
9+# See LICENSE in the root of the software repository for the full text of the License.
10+# ----------------------------------------------------------------------------
11+ 
12+file(GLOB CURRENT_DIRS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*)
13+foreach(SUB_DIR ${CURRENT_DIRS})
14+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUB_DIR}/CMakeLists.txt")
15+ add_subdirectory(${SUB_DIR})
16+ endif()
17+endforeach()
@@ -0,0 +1,13 @@
1+# ----------------------------------------------------------------------------
2+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+# CANN Open Software License Agreement Version 2.0 (the "License").
5+# Please refer to the License for details. You may not use this file except in compliance with the License.
6+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+# See LICENSE in the root of the software repository for the full text of the License.
9+# ----------------------------------------------------------------------------
10+ 
11+if(UT_TEST_ALL OR OP_HOST_UT)
12+ add_modules_ut_sources(UT_NAME ${OP_INFERSHAPE_MODULE_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR})
13+endif()
@@ -0,0 +1,66 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include <gtest/gtest.h>
12+#include <iostream>
13+#include "infershape_context_faker.h"
14+#include "infershape_case_executor.h"
15+ 
16+class ConjInfershape : public testing::Test {
17+protected:
18+ static void SetUpTestCase() { std::cout << "ConjInfershape SetUp" << std::endl; }
19+ 
20+ static void TearDownTestCase() { std::cout << "ConjInfershape TearDown" << std::endl; }
21+};
22+ 
23+TEST_F(ConjInfershape, conj_infershape_complex128)
24+{
25+ gert::InfershapeContextPara infershapeContextPara("Conj",
26+ {
27+ {{{2, 3}, {2, 3}}, ge::DT_COMPLEX128, ge::FORMAT_ND},
28+ },
29+ {
30+ {{{}, {}}, ge::DT_COMPLEX128, ge::FORMAT_ND},
31+ });
32+ std::vector<std::vector<int64_t>> expectOutputShape = {
33+ {2, 3},
34+ };
35+ ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape);
36+}
37+ 
38+TEST_F(ConjInfershape, conj_infershape_complex64)
39+{
40+ gert::InfershapeContextPara infershapeContextPara("Conj",
41+ {
42+ {{{8}, {8}}, ge::DT_COMPLEX64, ge::FORMAT_ND},
43+ },
44+ {
45+ {{{}, {}}, ge::DT_COMPLEX64, ge::FORMAT_ND},
46+ });
47+ std::vector<std::vector<int64_t>> expectOutputShape = {
48+ {8},
49+ };
50+ ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape);
51+}
52+ 
53+TEST_F(ConjInfershape, conj_infershape_dynamic)
54+{
55+ gert::InfershapeContextPara infershapeContextPara("Conj",
56+ {
57+ {{{-1, 4}, {-1, 4}}, ge::DT_COMPLEX128, ge::FORMAT_ND},
58+ },
59+ {
60+ {{{}, {}}, ge::DT_COMPLEX128, ge::FORMAT_ND},
61+ });
62+ std::vector<std::vector<int64_t>> expectOutputShape = {
63+ {-1, 4},
64+ };
65+ ExecuteTestCase(infershapeContextPara, ge::GRAPH_SUCCESS, expectOutputShape);
66+}
@@ -0,0 +1,115 @@
1+/**
2+ * Copyright (c) 2026 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+#include "gtest/gtest.h"
11+#ifndef private
12+#define private public
13+#define protected public
14+#endif
15+#include "utils/aicpu_test_utils.h"
16+#include "cpu_kernel_utils.h"
17+#include "node_def_builder.h"
18+#undef private
19+#undef protected
20+#include <complex>
21+#include <vector>
22+ 
23+using namespace std;
24+using namespace aicpu;
25+ 
26+class TEST_CONJ_UT : public testing::Test {};
27+ 
28+#define CREATE_NODEDEF(node_def, shapes, data_types, datas) \
29+ NodeDefBuilder(node_def.get(), "Conj", "Conj") \
30+ .Input({"input", data_types[0], shapes[0], datas[0]}) \
31+ .Output({"output", data_types[1], shapes[1], datas[1]})
32+ 
33+template <typename T>
34+void RunConjKernel(vector<DataType> data_types, vector<vector<int64_t>>& shapes, vector<T>& input,
35+ vector<T>& output_exp)
36+{
37+ uint64_t output_size = CalTotalElements(shapes, 1);
38+ vector<T> output(output_size);
39+ vector<void*> datas = {(void*)input.data(), (void*)output.data()};
40+ 
41+ auto node_def = CpuKernelUtils::CreateNodeDef();
42+ CREATE_NODEDEF(node_def, shapes, data_types, datas);
43+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_OK);
44+ 
45+ bool compare = CompareResult(output.data(), output_exp.data(), output_size);
46+ EXPECT_EQ(compare, true);
47+}
48+ 
49+TEST_F(TEST_CONJ_UT, DATA_TYPE_COMPLEX64_SUCC)
50+{
51+ vector<DataType> data_types = {DT_COMPLEX64, DT_COMPLEX64};
52+ vector<vector<int64_t>> shapes = {{2, 3}, {2, 3}};
53+ vector<complex<float>> input = {{1.0f, 2.0f}, {3.0f, -4.0f}, {5.0f, 6.0f},
54+ {-7.0f, 8.0f}, {0.0f, 1.0f}, {2.0f, 0.0f}};
55+ vector<complex<float>> output_exp = {{1.0f, -2.0f}, {3.0f, 4.0f}, {5.0f, -6.0f},
56+ {-7.0f, -8.0f}, {0.0f, -1.0f}, {2.0f, 0.0f}};
57+ RunConjKernel<complex<float>>(data_types, shapes, input, output_exp);
58+}
59+ 
60+TEST_F(TEST_CONJ_UT, DATA_TYPE_COMPLEX128_SUCC)
61+{
62+ vector<DataType> data_types = {DT_COMPLEX128, DT_COMPLEX128};
63+ vector<vector<int64_t>> shapes = {{4}, {4}};
64+ vector<complex<double>> input = {{1.5, 2.5}, {-3.5, 4.5}, {0.0, -1.0}, {2.0, 0.0}};
65+ vector<complex<double>> output_exp = {{1.5, -2.5}, {-3.5, -4.5}, {0.0, 1.0}, {2.0, 0.0}};
66+ RunConjKernel<complex<double>>(data_types, shapes, input, output_exp);
67+}
68+ 
69+// large input triggers the ParallelFor branch (data_size > kParallelDataNums).
70+TEST_F(TEST_CONJ_UT, DATA_TYPE_COMPLEX128_BIGDATA_SUCC)
71+{
72+ vector<DataType> data_types = {DT_COMPLEX128, DT_COMPLEX128};
73+ vector<vector<int64_t>> shapes = {{64, 1024}, {64, 1024}};
74+ uint64_t num = 64 * 1024;
75+ vector<complex<double>> input(num), output_exp(num);
76+ for (uint64_t i = 0; i < num; i++) {
77+ input[i] = complex<double>(static_cast<double>(i), -static_cast<double>(i));
78+ output_exp[i] = complex<double>(static_cast<double>(i), static_cast<double>(i));
79+ }
80+ RunConjKernel<complex<double>>(data_types, shapes, input, output_exp);
81+}
82+ 
83+TEST_F(TEST_CONJ_UT, INPUT_DTYPE_UNSUPPORT)
84+{
85+ vector<DataType> data_types = {DT_FLOAT, DT_FLOAT};
86+ vector<vector<int64_t>> shapes = {{2, 3}, {2, 3}};
87+ float input[6] = {0.0f};
88+ float output[6] = {0.0f};
89+ vector<void*> datas = {(void*)input, (void*)output};
90+ auto node_def = CpuKernelUtils::CreateNodeDef();
91+ CREATE_NODEDEF(node_def, shapes, data_types, datas);
92+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID);
93+}
94+ 
95+TEST_F(TEST_CONJ_UT, INPUT_NULL_EXCEPTION)
96+{
97+ vector<DataType> data_types = {DT_COMPLEX64, DT_COMPLEX64};
98+ vector<vector<int64_t>> shapes = {{2, 3}, {2, 3}};
99+ complex<float> output[6];
100+ vector<void*> datas = {(void*)nullptr, (void*)output};
101+ auto node_def = CpuKernelUtils::CreateNodeDef();
102+ CREATE_NODEDEF(node_def, shapes, data_types, datas);
103+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID);
104+}
105+ 
106+TEST_F(TEST_CONJ_UT, OUTPUT_NULL_EXCEPTION)
107+{
108+ vector<DataType> data_types = {DT_COMPLEX64, DT_COMPLEX64};
109+ vector<vector<int64_t>> shapes = {{2, 3}, {2, 3}};
110+ complex<float> input[6];
111+ vector<void*> datas = {(void*)input, (void*)nullptr};
112+ auto node_def = CpuKernelUtils::CreateNodeDef();
113+ CREATE_NODEDEF(node_def, shapes, data_types, datas);
114+ RUN_KERNEL(node_def, HOST, KERNEL_STATUS_PARAM_INVALID);
115+}