63 if (!model.CheckIfTensorAlreadyExist(
fNX)){
64 throw std::runtime_error(std::string(
"TMVA SOFIE Where Op Input Tensor ") +
fNX +
"is not found in model");
66 if (!model.CheckIfTensorAlreadyExist(
fNY)) {
67 throw std::runtime_error(std::string(
"TMVA SOFIE Where Op Input Tensor ") +
fNY +
"is not found in model");
69 if (!model.CheckIfTensorAlreadyExist(
fNC)) {
70 throw std::runtime_error(std::string(
"TMVA SOFIE Where Op Input Tensor ") +
fNC +
"is not found in model");
73 if (model.IsReadyInputTensor(
fNC))
79 int dynamicInputs = 0;
81 if (model.IsDynamicTensor(
fNC)) {
88 if (model.IsDynamicTensor(
fNX)) {
95 if (model.IsDynamicTensor(
fNY)) {
104 if (model.Verbose()) {
105 if (dynamicInputs & 1)
107 if (dynamicInputs & 2)
109 if (dynamicInputs & 4)
116 if (dynamicInputs == 0) {
127 auto padToRank = [&](std::vector<size_t> &shape) {
128 if (shape.size() <
fShapeZ.size()) {
129 size_t nPrepend =
fShapeZ.size() - shape.size();
130 shape.insert(shape.begin(), nPrepend, 1);
144 if (model.IsInitializedTensor(
fNX)) {
145 auto data = model.GetInitializedTensorData(
fNX);
146 std::shared_ptr<void> broadcastedData(
148 std::default_delete<T[]>());
157 if (model.IsInitializedTensor(
fNY)) {
158 auto data = model.GetInitializedTensorData(
fNY);
159 std::shared_ptr<void> broadcastedData(
161 std::default_delete<T[]>());
170 if (model.IsInitializedTensor(
fNC)) {
171 auto data = model.GetInitializedTensorData(
fNC);
172 std::shared_ptr<void> broadcastedData(
174 std::default_delete<T[]>());
184 if (model.IsInitializedTensor(
fNC)) {
186 auto dataC =
static_cast<bool *
>(model.GetInitializedTensorData(nameC).get());
187 model.SetNotWritableInitializedTensor(nameC);
190 std::vector<Dim> shapeDataX;
191 std::vector<Dim> shapeDataY;
192 if (model.IsInitializedTensor(
fNX)) {
194 dataX =
static_cast<T *
>(model.GetInitializedTensorData(nameX).get());
196 model.SetNotWritableInitializedTensor(nameX);
197 }
else if (model.IsShapeTensor(
fNX)) {
198 shapeDataX = model.GetShapeTensorValues(
fNX);
200 if (model.IsInitializedTensor(
fNY)) {
202 dataY =
static_cast<T *
>(model.GetInitializedTensorData(nameY).get());
203 model.SetNotWritableInitializedTensor(nameY);
204 }
else if (model.IsShapeTensor(
fNY)) {
205 shapeDataY = model.GetShapeTensorValues(
fNY);
207 std::vector<T> dataZ;
208 std::vector<Dim> shapeDataZ;
213 bool isOutputConstantTensor =
true;
214 if (dataX && dataY) {
216 for (
size_t i = 0; i < dataZ.size(); i++)
217 dataZ[i] = (dataC[i]) ? dataX[i] : dataY[i];
220 }
else if (dataX && shapeDataY.size() > 0) {
222 for (
size_t i = 0; i < shapeDataZ.size(); i++) {
223 shapeDataZ[i] = (dataC[i]) ?
Dim{size_t(dataX[i])} : shapeDataY[i];
224 isOutputConstantTensor &= !shapeDataZ[i].isParam;
228 << isOutputConstantTensor << std::endl;
229 }
else if (dataY && shapeDataX.size() > 0) {
231 for (
size_t i = 0; i < shapeDataZ.size(); i++) {
232 shapeDataZ[i] = (dataC[i]) ? shapeDataY[i] :
Dim{size_t(dataY[i])};
233 isOutputConstantTensor &= !shapeDataZ[i].isParam;
237 << isOutputConstantTensor << std::endl;
238 }
else if (shapeDataY.size() > 0 && shapeDataX.size() > 0) {
240 for (
size_t i = 0; i < shapeDataZ.size(); i++) {
241 shapeDataZ[i] = (dataC[i]) ? shapeDataX[i] : shapeDataY[i];
242 isOutputConstantTensor &= !shapeDataZ[i].isParam;
250 if (dataZ.size() > 0)
251 model.AddConstantTensor<T>(
fNZ,
fShapeZ, dataZ.data());
252 else if (shapeDataZ.size() > 0)
253 model.AddShapeTensor(
fNZ, shapeDataZ,
fShapeZ.size() == 0);
260 << ((dataZ.size() > 0) ?
" (constant)" :
" (shape)") << std::endl;
269 model.AddIntermediateTensor(
fNZ, model.GetTensorType(
fNX),
fShapeZ);
290 auto IsInputDimParam = [&](
const std::string &
p) {
291 for (
auto &
input : model.GetInputTensorNames())
292 for (
auto &s : model.GetDimTensorShape(
input))
293 if (s.isParam && s.param ==
p)
return true;
296 for (
size_t i = 0; i <
fDimShapeZ.size(); i++) {
298 if (s.isParam && s.param.find(
"std::max") != std::string::npos) {
337 std::string
Generate(std::string opName)
override {
339 opName =
"op_" + opName;
340 std::stringstream out;
352 out <<
SP <<
"if (" << lengthX <<
" != " << lengthY <<
" || "
353 << lengthX <<
" != " << lengthC <<
") {\n";
354 for (
size_t i = 0; i <
fDimShapeZ.size(); i++) {
360 <<
"throw std::runtime_error(\"SOFIE Where: cannot broadcast A dim " << i <<
" in " << opName <<
"\");\n";
367 <<
"throw std::runtime_error(\"SOFIE Where: cannot broadcast B dim " << i <<
" in " << opName <<
"\");\n";
374 <<
"throw std::runtime_error(\"SOFIE Where: cannot broadcast C dim " << i <<
" in " << opName <<
"\");\n";
388 auto buildIdxExpr = [&](
const std::vector<Dim> &dimShape,
389 const std::vector<Dim> &strides,
390 size_t rankZ) -> std::string {
391 if (dimShape.empty() ||
392 std::all_of(dimShape.begin(), dimShape.end(),
393 [](
Dim d) { return d.dim == 1 || d.GetVal() ==
"1"; }))
396 size_t offset = rankZ - dimShape.size();
397 for (
size_t i = 0; i < dimShape.size(); ++i) {
398 if (dimShape[i].dim == 1 || dimShape[i].GetVal() ==
"1")
continue;
399 expr +=
"idx_" + std::to_string(i +
offset);
400 if (strides[i].GetVal() !=
"1")
401 expr +=
" * " + strides[i].GetVal();
404 if (expr.size() >= 3)
405 for (
int j = 0; j < 3; j++) expr.pop_back();
406 return expr.empty() ?
"0" : expr;
419 [](
Dim d) { return d.dim == 1 || d.GetVal() ==
"1"; })) {
422 for (
size_t i = 0; i <
fDimShapeZ.size(); ++i) {
425 for (
int j = 0; j < nloop; j++) out <<
SP;
426 out <<
"for (size_t idx_" << i <<
" = 0; idx_" << i
427 <<
" < " <<
fDimShapeZ[i] <<
"; ++idx_" << i <<
") {\n";
428 idxZ +=
"idx_" + std::to_string(i);
429 if (stridesZ[i].GetVal() !=
"1")
430 idxZ +=
" * " + stridesZ[i].GetVal();
434 if (idxZ.size() >= 3)
435 for (
int j = 0; j < 3; j++) idxZ.pop_back();
439 for (
int j = 0; j < nloop + 1; j++) out <<
SP;
440 out <<
"tensor_" <<
fNZ <<
"[" << idxZ <<
"] = "
441 <<
"tensor_" <<
fNC <<
"[" << idxC <<
"] ? "
442 <<
"tensor_" <<
fNX <<
"[" << idxX <<
"] : "
443 <<
"tensor_" <<
fNY <<
"[" << idxY <<
"];\n";
446 for (
int i = nloop; i > 0; i--) {
447 for (
int j = 0; j < i; j++) out <<
SP;