| @@ -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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 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 | + | ||
| 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); | ||
| 131 | + delete[] pData; | ||
| 132 | + return SUCCESS; | ||
🟡 Medium Priority 在 触发条件:每次调用 ![]() ![]() | |||
| 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; | ||
🟡 Medium Priority 变更行: 受影响行为:当文件无法创建时(如目录不存在、权限不足、磁盘满), 失败模式:运行示例程序的用户目录权限不足时程序崩溃,无法完成验证。 建议:添加 fopen 返回值检查: ![]() ![]() | |||
| 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 | + | ||
| 12 | + | ||
| 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 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 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 | + | ||
| @@ -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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 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); | ||
🟡 Medium Priority
这意味着:用户传入 0 维(标量)或 1 维输入时,infershape 会返回成功,图构建通过,但执行阶段 kernel 返回 PARAM_INVALID,用户得到运行时错误而非早期的图编译错误,排查困难。 建议:在获取 xShape 并 null-check 之后、perm size 校验之前,增加对 inputDimSize > 1 的校验;同时可增设 dim ≤ 7 的校验以与 README 上限一致。失败时使用 OP_LOGE 输出明确错误后返回 GRAPH_FAILED。 ![]() ![]() | |||
| 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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 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 | + | ||
| 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 | + | ||
| 43 | + for (size_t i = 0; i < (input_dims); ++i) { \ | ||
| 44 | + (perm_nd)[i] = perm.at(i); \ | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + | ||
| 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 | + | ||
| 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 | + | ||
| 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 | + | ||
| 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 | + | ||
| 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 | + | ||
| 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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 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 | + | ||
| @@ -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 | + | ||
| 12 | + | ||
| 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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | +using namespace std; | ||
| 23 | +using namespace aicpu; | ||
| 24 | + | ||
| 25 | +class TEST_CONJUGATETRANSPOSE_UT : public testing::Test {}; | ||
| 26 | + | ||
| 27 | + | ||
| 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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 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 | + | ||
| 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); | ||
🟡 Medium Priority 在 触发条件:当系统内存不足导致 建议:在 new 之后添加空指针检查: ![]() ![]() | |||
| 95 | + delete[] pData; | ||
| 96 | + return SUCCESS; | ||
🟡 Medium Priority 在 触发条件:每次调用 ![]() ![]() | |||
| 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; | ||
🟡 Medium Priority 变更行: 建议:添加 fopen 返回值检查: ![]() ![]() | |||
| 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 | + | ||
| 12 | + | ||
| 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 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 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 | + | ||
| @@ -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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 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 | + | ||
| 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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 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 | + | ||
| @@ -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 | + | ||
| 12 | + | ||
| 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 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | +using namespace std; | ||
| 24 | +using namespace aicpu; | ||
| 25 | + | ||
| 26 | +class TEST_CONJ_UT : public testing::Test {}; | ||
| 27 | + | ||
| 28 | + | ||
| 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 | +} | ||


🟡 Medium Priority
在
conversion/conjugate_transpose/examples/test_geir_conjugate_transpose.cpp第 122 行,GenComplexData使用new (std::nothrow)分配内存,但未检查pData是否为nullptr。紧接着在第 123-125 行通过pData[i]写入数据。触发条件:当系统内存不足导致
new失败时,pData为nullptr。 失败模式:访问空指针导致段错误(segfault),程序崩溃。同一文件中
test_geir_conj.cpp第 86 行存在相同问题。建议:在 new 之后添加空指针检查:
if (pData == nullptr) { return FAILED; }