81 if (model.CheckIfTensorAlreadyExist(
fNData) ==
false){
82 throw std::runtime_error(
"TMVA Slice Op Input Tensor is not found in model");
85 std::vector<std::vector<Dim>> shapes;
89 std::vector<std::vector<IType>> itensors(4);
93 for (
size_t i = 0; i < 4; ++i) {
95 if (model.IsInitializedTensor(
fNames[i])) {
96 auto dptr = model.GetInitializedTensorData(
fNames[i]);
97 auto tensor =
static_cast<IType *
>(dptr.get());
98 auto vec = model.GetTensorShape(
fNames[i]);
99 assert(vec.size() == 1);
100 itensors[i] = std::vector<IType>(tensor, tensor + vec[0]);
102 }
else if (model.IsShapeTensor(
fNames[i])) {
113 auto shape = model.GetTensorShape(
fNames[i]);
115 for (
size_t k = 0; k < s; k++) {
145 if (itensors[2].empty()) {
150 for (
size_t i = 0; i <
fAxes.size(); i++) {
153 if (
fAxes[i] < 0 ||
fAxes[i] >=
static_cast<IType
>(dim))
154 throw std::runtime_error(
"TMVA Slice Op : invalid axis value " + std::to_string(
fAxes[i]) +
155 " for " + std::to_string(i));
159 for (
size_t i = 0; i <
fAxes.size(); i++) {
160 if (!itensors[0].empty() )
161 fStartDims.push_back(
Dim{
static_cast<size_t>(itensors[0][i])});
163 throw std::runtime_error(
"TMVA Slice Op : Missing start input tensor");
165 if (!itensors[1].empty())
166 fEndDims.push_back(
Dim{
static_cast<size_t>(itensors[1][i])});
168 throw std::runtime_error(
"TMVA Slice Op : Missing end input tensor");
170 if (!itensors[3].empty()) {
171 fStepDims.push_back(
Dim{
static_cast<size_t>(itensors[3][i])});
181 istart =
static_cast<IType
>(
fStartDims[i].dim);
182 if (istart < 0) istart = iAxisDim + istart;
184 IType iend =
static_cast<IType
>(iAxisDim);
186 iend =
static_cast<IType
>(
fEndDims[i].dim);
187 if (iend < 0) iend = iAxisDim + iend;
192 istep =
static_cast<IType
>(
fStepDims[i].dim);
194 throw std::runtime_error(
"TMVA Slice Op : parametric step inputs are not supported");
199 if (istart < 0) istart = 0;
201 if (istart >
static_cast<IType
>(iAxisDim)) istart =
static_cast<IType
>(iAxisDim);
202 if (iend < 0) iend = 0;
203 if (iend >
static_cast<IType
>(iAxisDim)) iend =
static_cast<IType
>(iAxisDim);
204 }
else if (istep < 0) {
205 if (istart >
static_cast<IType
>(iAxisDim)-1) istart =
static_cast<IType
>(iAxisDim) -1;
206 if (iend < -1) iend = -1;
207 if (iend >
static_cast<IType
>(iAxisDim)-1) iend =
static_cast<IType
>(iAxisDim) -1;
209 throw std::runtime_error(
"TMVA Slice Op : invalid step value " + std::to_string(istep) +
210 " for " + std::to_string(i));
227 IType istart =
static_cast<IType
>(
fStartDims[i].dim);
229 std::string sstart = std::string(
"(") +
fShapeInput[
fAxes[i]].param +
"-" + std::to_string(-istart) +
")";
238 IType iend =
static_cast<IType
>(
fEndDims[i].dim);
240 std::string send = std::string(
"(") +
fShapeInput[
fAxes[i]].param +
"-" + std::to_string(-iend) +
")";
242 }
else if (iend == std::numeric_limits<IType>::max()){
256 fShapeOutput.resize(dim);
257 for (
size_t i = 0; i < dim; i++) {
258 if (!fEnd[i].isParam && !fStart[i].isParam && !fSteps[i].isParam) {
259 int64_t istart =
static_cast<int64_t
>(fStart[i].dim);
260 int64_t iend =
static_cast<int64_t
>(fEnd[i].dim);
261 int64_t istep=
static_cast<int64_t
>(fSteps[i].dim);
262 int64_t s = (iend-istart)/istep;
263 fShapeOutput[i] = Dim{
static_cast<size_t>(s)};
266 if (fStart[i].GetVal() !=
"0")
267 s =
"(" + fEnd[i].GetVal() +
"-" + fStart[i].GetVal() +
")";
269 s = fEnd[i].GetVal();
270 if (fSteps[i].GetVal() !=
"1") {
272 s +=
")/" + fSteps[i].GetVal() +
")";
274 fShapeOutput[i] = Dim{s,size_t(-1)};
277 if (fEnd[i].isParam && fEnd[i].dim !=
size_t(-1))
278 model.AddShapeParam(fEnd[i].param,fEnd[i].dim );
279 if (fStart[i].isParam && fStart[i].dim !=
size_t(-1))
280 model.AddShapeParam(fStart[i].param,fStart[i].dim );
281 if (fSteps[i].isParam && fSteps[i].dim !=
size_t(-1))
282 model.AddShapeParam(fSteps[i].param,fSteps[i].dim );
288 fIsOutputConstant =
true;
289 auto inputData =
static_cast<int64_t*
>(model.GetInitializedTensorData(fNData).get());
291 std::vector<int64_t> outputData(outputSize);
293 if (model.Verbose()) {
294 std::cout <<
"Do slice for initialized input ..(start, end, step)\n";
295 for (
size_t ii = 0; ii< fStart.size(); ii++)
296 std::cout << fStart [ii] <<
" " << fEnd[ii] <<
" " << fSteps[ii] << std::endl;
299 auto sliceRecursive = [&](
size_t iaxis,
size_t & outIdx,
size_t & inOffset) {
300 auto slice_impl = [&](
size_t iax,
size_t & outputIdx,
size_t & inputOffset,
auto & sliceRecImpl) {
301 if (fStart[iax].isParam || fEnd[iax].isParam || fSteps[iax].isParam)
302 throw std::runtime_error(
"TMVA Slice Op : cannot have parametric values when input is constant");
304 std::vector<IType> indices;
305 for (IType i = (IType) fStart[iax].dim; (IType(fSteps[iax].dim) > 0) ? i < IType(fEnd[iax].dim) : i > IType(fEnd[iax].dim); i += IType(fSteps[iax].dim) )
306 indices.push_back(i);
308 for (
size_t i = 0; i < indices.size(); i++) {
309 outputData[outputIdx] = inputData[inputOffset + indices[i]];
314 for (
size_t i = 0; i < indices.size(); i++) {
315 size_t offset = inputOffset + inputStride[iax]*indices[i];
316 sliceRecImpl(iax+1, outputIdx,
offset,sliceRecImpl);
320 slice_impl(iaxis, outIdx, inOffset,slice_impl);
324 sliceRecursive(0, idx,
offset);
327 if (model.Verbose()) {
332 else if (model.IsShapeTensor(fNData) && !fStart[0].isParam && !fEnd[0].isParam) {
334 auto inputData = model.GetShapeTensorValues(fNData);
335 fOutputShapeData = std::vector<Dim>(inputData.begin() + fStart[0].dim, inputData.begin() + fEnd[0].dim);
338 fShapeOutput = { Dim{fOutputShapeData.size()}};
339 if (outputData.empty()) {
341 model.AddShapeTensor(fNOutput, fOutputShapeData);
342 fIsOutputParamShape =
true;
343 if (model.Verbose()) {
344 std::cout <<
"Slice: output is a shape tensor -> " << fNOutput <<
" " <<
ConvertDimShapeToString(fShapeOutput) <<
" with values "
348 fIsOutputConstant =
true;
349 std::vector<int64_t>
data(outputData.size());
350 std::copy(outputData.begin(), outputData.end(),
data.begin());
352 if (model.Verbose()) {
353 std::cout <<
"Slice: output is a constant tensor -> " << fNOutput <<
" " <<
ConvertDimShapeToString(fShapeOutput) <<
" with values "
360 size_t ndim = fShapeInput.size();
361 fIdentitySlice = fShapeOutput.size() == ndim;
364 for (
size_t idim = 0; idim < ndim; idim++) {
365 if (!fIdentitySlice)
break;
366 fIdentitySlice &= (fStart[idim].GetVal() ==
"0");
367 fIdentitySlice &= (fSteps[idim].GetVal() ==
"1");
368 fIdentitySlice &= (fEnd[idim].GetVal() == fShapeInput[idim].GetVal());
374 fIsAlias = model.AddAliasTensor(fNOutput, fNData);
376 if (model.Verbose()) {
380 std::cout <<
" (using alias tensor since slice is an identity) ";
381 std::cout << std::endl;
387 std::string
Generate(std::string opName)
override {
389 if (fShapeInput.empty() || fShapeOutput.empty()){
390 throw std::runtime_error(
"TMVA SOFIE Slice Op called to Generate without being initialized first");
393 std::stringstream out;
395 out <<
"///------- Slice operator " << opName <<
"---> " << fNOutput <<
" "
397 if (fIsOutputConstant)
return out.str();
398 if (fIsOutputParamShape) {
401 for (
int i = 0; i < static_cast<int>(fShapeOutput[0].dim); i++) {
402 out <<
SP <<
"tensor_" << fNOutput <<
"[" << i <<
"] = " << fOutputShapeData[i] <<
";\n";
407 size_t ndim = fShapeInput.size();
409 if (fIdentitySlice) {
411 out <<
"/// Slice is just an identity: the output points to the memory of the input\n";
412 out <<
SP <<
"auto * tensor_" << fNOutput <<
" = tensor_" << fNData <<
";\n";
414 out <<
"/// Slice is just an identity (copy) \n";
415 out <<
SP <<
"std::copy(tensor_" << fNData <<
", tensor_" << fNData <<
" + "
422 auto strides = UTILITY::ComputeStrideFromShape(fShapeInput);
426 for (
size_t i = 0; i < fStepDims.size(); i++) {
427 if (fStepDims[i].isParam) {
429 out <<
SP <<
"size_t " << fStepDims[i] <<
" = tensor_" << fNames[3] <<
"[" << i <<
"];\n";
433 for (
size_t i = 0; i < fStartDims.size(); i++) {
434 if (fStartDims[i].isParam && fStartDims[i].param != fShapeInput[fAxes[i]].param) {
435 std::string s_start =
"start_" + std::to_string(i);
437 s_start = fStartDims[i].param;
438 out <<
SP <<
"size_t " << s_start <<
" = tensor_" << fNames[0] <<
"[" << i <<
"];\n";
440 out <<
SP <<
"size_t " << s_start <<
" = " << fStartDims[i] <<
";\n";
441 fStart[fAxes[i]] = s_start;
443 out <<
SP <<
"if (" << s_start <<
" < 0) " << s_start <<
" += " << fShapeInput[fAxes[i]] <<
";\n";
444 out <<
SP <<
"if (" << s_start <<
" < 0) " << s_start <<
" = 0;\n";
445 if (!fStepDims[i].isParam) {
446 if (
static_cast<IType
>(fStepDims[i].dim) > 0 )
447 out <<
SP <<
"if (" << s_start <<
" > " << fShapeInput[fAxes[i]] <<
" ) " << s_start <<
" = " << fShapeInput[fAxes[i]] <<
";\n";
449 out <<
SP <<
"if (" << s_start <<
" > " << fShapeInput[fAxes[i]] <<
" - 1" <<
" ) " << s_start <<
" = " << fShapeInput[fAxes[i]] <<
" - 1;\n";
453 else if (fStartDims[i].isParam && fStartDims[i].param == fShapeInput[fAxes[i]].param && !fStepDims[i].isParam &&
static_cast<IType
>(fStepDims[i].dim) < 0 ) {
454 fStart[fAxes[i]] =
Dim{ fStartDims[i].param +
"-1" };
458 for (
size_t i = 0; i < fEndDims.size(); i++) {
459 if (fEndDims[i].isParam && fEndDims[i].param != fShapeInput[fAxes[i]].param) {
460 std::string s_end =
"end_" + std::to_string(i);
462 s_end = fEndDims[i].param;
463 out <<
SP <<
"size_t " << s_end <<
" = tensor_" << fNames[1] <<
"[" << i <<
"];\n";
465 out <<
SP <<
"size_t " << s_end <<
" = " << fEndDims[i] <<
";\n";
466 fEnd[fAxes[i]] = s_end;
468 out <<
SP <<
"if (" << s_end <<
" < 0) " << s_end <<
" += " << fShapeInput[fAxes[i]] <<
";\n";
469 if (!fStepDims[i].isParam) {
470 if (
static_cast<IType
>(fStepDims[i].dim) > 0 ) {
471 out <<
SP <<
"if (" << s_end <<
" < 0) " << s_end <<
" = 0;\n";
472 out <<
SP <<
"if (" << s_end <<
" > " << fShapeInput[fAxes[i]] <<
" ) " << s_end <<
" = " << fShapeInput[fAxes[i]] <<
";\n";
474 out <<
SP <<
"if (" << s_end <<
" < -1) " << s_end <<
" = -1;\n";
475 out <<
SP <<
"if (" << s_end <<
" > " << fShapeInput[fAxes[i]] <<
" - 1" <<
" ) " << s_end <<
" = " << fShapeInput[fAxes[i]] <<
" - 1;\n";
480 else if (fEndDims[i].isParam && fEndDims[i].param == fShapeInput[fAxes[i]].param && !fStepDims[i].isParam &&
static_cast<IType
>(fStepDims[i].dim) < 0 ) {
481 fEnd[fAxes[i]] =
Dim{ fEndDims[i].param +
"-1" };
485 out <<
SP <<
"size_t iOut = 0;\n";
486 std::string MSP =
SP;
487 for (
size_t idim = 0; idim < ndim; idim++) {
488 out << MSP <<
"for (size_t i" << idim <<
" = " << fStart[idim] <<
"; i" << idim <<
" < " << fEnd[idim]
489 <<
"; i" << idim <<
"+= " << fSteps[idim] <<
") {\n";
491 if (idim < ndim-1) out << MSP <<
"size_t stride" << idim <<
" = " << strides[idim] <<
"*i" << idim <<
";\n";
493 out << MSP <<
"size_t iInput = ";
494 for (
size_t idim = 0; idim < ndim-1; idim++) out <<
" stride" << idim <<
" + ";
496 out <<
"i" << ndim-1 <<
";\n";
497 out << MSP <<
"tensor_" << fNOutput <<
"[iOut++] = tensor_" <<fNData <<
"[iInput];\n";
498 for (
size_t idim = 0; idim < ndim; idim++) {
499 MSP = MSP.replace(0,
SP.length(),
"");