19d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
29d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner
39d57702513001bfded19e72c76a986cce56d5f00Benoit SteinerLicensed under the Apache License, Version 2.0 (the "License");
49d57702513001bfded19e72c76a986cce56d5f00Benoit Steineryou may not use this file except in compliance with the License.
59d57702513001bfded19e72c76a986cce56d5f00Benoit SteinerYou may obtain a copy of the License at
69d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner
79d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner    http://www.apache.org/licenses/LICENSE-2.0
89d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner
99d57702513001bfded19e72c76a986cce56d5f00Benoit SteinerUnless required by applicable law or agreed to in writing, software
109d57702513001bfded19e72c76a986cce56d5f00Benoit Steinerdistributed under the License is distributed on an "AS IS" BASIS,
119d57702513001bfded19e72c76a986cce56d5f00Benoit SteinerWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
129d57702513001bfded19e72c76a986cce56d5f00Benoit SteinerSee the License for the specific language governing permissions and
139d57702513001bfded19e72c76a986cce56d5f00Benoit Steinerlimitations under the License.
149d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner==============================================================================*/
159d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner
16c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower#include <unordered_set>
17c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower
1850efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower#include "tensorflow/core/framework/attr_value.pb.h"
19be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner#include "tensorflow/core/framework/op.h"
20c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower#include "tensorflow/core/framework/types.h"
21c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower#include "tensorflow/core/grappler/op_types.h"
22c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower#include "tensorflow/core/grappler/utils.h"
23be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner#include "tensorflow/core/lib/core/status.h"
249d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner
259d57702513001bfded19e72c76a986cce56d5f00Benoit Steinernamespace tensorflow {
269d57702513001bfded19e72c76a986cce56d5f00Benoit Steinernamespace grappler {
279d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner
2828ee7877a9df4e66f81d31d48b067091726c71abA. Unique TensorFlowerbool IsAdd(const NodeDef& node) {
29481b5f4410b34b65570f9dce62b34e9199769a38A. Unique TensorFlower  if (node.op() == "AddV2" || node.op() == "Add") {
30481b5f4410b34b65570f9dce62b34e9199769a38A. Unique TensorFlower    DataType type = node.attr().at("T").type();
31481b5f4410b34b65570f9dce62b34e9199769a38A. Unique TensorFlower    return type != DT_STRING;
32481b5f4410b34b65570f9dce62b34e9199769a38A. Unique TensorFlower  }
33481b5f4410b34b65570f9dce62b34e9199769a38A. Unique TensorFlower  return false;
3428ee7877a9df4e66f81d31d48b067091726c71abA. Unique TensorFlower}
351ffb45e7112addad325084084b93897918ed9a54Yao Zhang
36cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsAddN(const NodeDef& node) { return node.op() == "AddN"; }
37136494d3295a23e3ed0612773f224243915463b7Benoit Steiner
38d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsAll(const NodeDef& node) { return node.op() == "All"; }
39d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang
40ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsAngle(const NodeDef& node) { return node.op() == "Angle"; }
41ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
42d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsAny(const NodeDef& node) { return node.op() == "Any"; }
43d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang
44634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlowerbool IsAnyDiv(const NodeDef& node) {
45634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower  return node.op() == "RealDiv" || node.op() == "Div" ||
46634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower         node.op() == "FloorDiv" || node.op() == "TruncateDiv";
47634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower}
48634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower
49ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsApproximateEqual(const NodeDef& node) {
50ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang  return node.op() == "ApproximateEqual";
51ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang}
52ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
53cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsAvgPoolGrad(const NodeDef& node) { return node.op() == "AvgPoolGrad"; }
541ffb45e7112addad325084084b93897918ed9a54Yao Zhang
55cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsAssert(const NodeDef& node) { return node.op() == "Assert"; }
561ffb45e7112addad325084084b93897918ed9a54Yao Zhang
57ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsAtan2(const NodeDef& node) { return node.op() == "Atan2"; }
58ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
5932ee432d9674567e80771b070e68e7f565d4fd2cYao Zhangbool IsBetainc(const NodeDef& node) { return node.op() == "Betainc"; }
6032ee432d9674567e80771b070e68e7f565d4fd2cYao Zhang
61b8368b721a2679fb68c014dc6fe890dc167dff14A. Unique TensorFlowerbool IsBiasAdd(const NodeDef& node) {
62b8368b721a2679fb68c014dc6fe890dc167dff14A. Unique TensorFlower  return node.op() == "BiasAdd" || node.op() == "BiasAddV1";
63b8368b721a2679fb68c014dc6fe890dc167dff14A. Unique TensorFlower}
64b8368b721a2679fb68c014dc6fe890dc167dff14A. Unique TensorFlower
65cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsBiasAddGrad(const NodeDef& node) { return node.op() == "BiasAddGrad"; }
6665044bc25981e4e060ad5c34d9a520a0561775c3Yao Zhang
67ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsBitcast(const NodeDef& node) { return node.op() == "Bitcast"; }
68ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
69fe613b051b5732f06af586f7b4f0ca28121f1eccYao Zhangbool IsCast(const NodeDef& node) { return node.op() == "Cast"; }
70fe613b051b5732f06af586f7b4f0ca28121f1eccYao Zhang
71ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsComplex(const NodeDef& node) { return node.op() == "Complex"; }
72ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
73ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsComplexAbs(const NodeDef& node) { return node.op() == "ComplexAbs"; }
74ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
75cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsConcatOffset(const NodeDef& node) { return node.op() == "ConcatOffset"; }
761a0f2fa7b0f4be4c0196c22b5c6ae717a8361ccaBenoit Steiner
77cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsConstant(const NodeDef& node) { return node.op() == "Const"; }
78cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower
79ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsConj(const NodeDef& node) { return node.op() == "Conj"; }
80ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
81cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsConv2D(const NodeDef& node) { return node.op() == "Conv2D"; }
821ffb45e7112addad325084084b93897918ed9a54Yao Zhang
831ffb45e7112addad325084084b93897918ed9a54Yao Zhangbool IsConv2DBackpropFilter(const NodeDef& node) {
84cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower  return node.op() == "Conv2DBackpropFilter";
851ffb45e7112addad325084084b93897918ed9a54Yao Zhang}
861ffb45e7112addad325084084b93897918ed9a54Yao Zhang
871ffb45e7112addad325084084b93897918ed9a54Yao Zhangbool IsConv2DBackpropInput(const NodeDef& node) {
88cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower  return node.op() == "Conv2DBackpropInput";
891ffb45e7112addad325084084b93897918ed9a54Yao Zhang}
901ffb45e7112addad325084084b93897918ed9a54Yao Zhang
916ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhangbool IsDepthwiseConv2dNative(const NodeDef& node) {
92cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower  return node.op() == "DepthwiseConv2dNative";
936ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang}
946ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang
956ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhangbool IsDepthwiseConv2dNativeBackpropFilter(const NodeDef& node) {
96cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower  return node.op() == "DepthwiseConv2dNativeBackpropFilter";
976ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang}
986ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang
996ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhangbool IsDepthwiseConv2dNativeBackpropInput(const NodeDef& node) {
100cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower  return node.op() == "DepthwiseConv2dNativeBackpropInput";
1016ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang}
1026ad9e45abf68f62caf7a9fe7adb7ef30da5ea6caYao Zhang
1037bc6271055714f3d4d0b957a2f4c6a910ea20388Yuefeng Zhoubool IsDequeueOp(const NodeDef& node) {
1049ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner  const auto& op = node.op();
1059ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner  return op == "QueueDequeueManyV2" || op == "QueueDequeueMany" ||
1069ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner         op == "QueueDequeueV2" || op == "QueueDequeue" ||
1079ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner         op == "QueueDequeueUpToV2" || op == "QueueDequeueUpTo";
1087bc6271055714f3d4d0b957a2f4c6a910ea20388Yuefeng Zhou}
1097bc6271055714f3d4d0b957a2f4c6a910ea20388Yuefeng Zhou
110634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlowerbool IsDiv(const NodeDef& node) { return node.op() == "Div"; }
111634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower
112bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsEluGrad(const NodeDef& node) { return node.op() == "EluGrad"; }
113bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang
114c247826219dd2541c6aba4578a03a171375d9290Benoit Steinerbool IsEnter(const NodeDef& node) {
115c247826219dd2541c6aba4578a03a171375d9290Benoit Steiner  const auto& op = node.op();
116c247826219dd2541c6aba4578a03a171375d9290Benoit Steiner  return op == "Enter" || op == "RefEnter";
117c247826219dd2541c6aba4578a03a171375d9290Benoit Steiner}
118c247826219dd2541c6aba4578a03a171375d9290Benoit Steiner
119ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsEqual(const NodeDef& node) { return node.op() == "Equal"; }
120ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
121c4a58e3fdd9880d424f639502e93a8298a965467Yao Zhangbool IsExit(const NodeDef& node) {
122c4a58e3fdd9880d424f639502e93a8298a965467Yao Zhang  const auto& op = node.op();
123c4a58e3fdd9880d424f639502e93a8298a965467Yao Zhang  return op == "Exit" || op == "RefExit";
124c4a58e3fdd9880d424f639502e93a8298a965467Yao Zhang}
125c4a58e3fdd9880d424f639502e93a8298a965467Yao Zhang
1264b66819917856d5534cecffc02ed495e59fe5953Yao Zhangbool IsFill(const NodeDef& node) { return node.op() == "Fill"; }
1274b66819917856d5534cecffc02ed495e59fe5953Yao Zhang
128ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsFloorDiv(const NodeDef& node) { return node.op() == "FloorDiv"; }
129ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
130cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsFloorMod(const NodeDef& node) { return node.op() == "FloorMod"; }
1311ffb45e7112addad325084084b93897918ed9a54Yao Zhang
132a313da5c81babbbf9049c03aba8f078448dd9c9cYao Zhangbool IsFusedBatchNormGrad(const NodeDef& node) {
133a313da5c81babbbf9049c03aba8f078448dd9c9cYao Zhang  const auto& op = node.op();
134a313da5c81babbbf9049c03aba8f078448dd9c9cYao Zhang  return op == "FusedBatchNormGrad" || op == "FusedBatchNormGradV2";
1351ffb45e7112addad325084084b93897918ed9a54Yao Zhang}
1361ffb45e7112addad325084084b93897918ed9a54Yao Zhang
137ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsGreater(const NodeDef& node) { return node.op() == "Greater"; }
138ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
139ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsGreaterEqual(const NodeDef& node) { return node.op() == "GreaterEqual"; }
140ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
141d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsHistogramSummary(const NodeDef& node) {
142d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang  return node.op() == "HistogramSummary";
143d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang}
144d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang
14593c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steinerbool IsIdentity(const NodeDef& node) {
14693c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner  const auto& op = node.op();
147bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steiner  return op == "Identity" || op == "RefIdentity";
14893c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner}
14993c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner
1501d651f18ae84c20d71ddfddc32e4495e00902440Yao Zhangbool IsIdentityN(const NodeDef& node) {
1511d651f18ae84c20d71ddfddc32e4495e00902440Yao Zhang  const auto& op = node.op();
1521d651f18ae84c20d71ddfddc32e4495e00902440Yao Zhang  return op == "IdentityN";
1531d651f18ae84c20d71ddfddc32e4495e00902440Yao Zhang}
1541d651f18ae84c20d71ddfddc32e4495e00902440Yao Zhang
155ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsIgamma(const NodeDef& node) { return node.op() == "Igamma"; }
156ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
157ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsIgammac(const NodeDef& node) { return node.op() == "Igammac"; }
158ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
159ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsImag(const NodeDef& node) { return node.op() == "Imag"; }
160ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
161bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsInvGrad(const NodeDef& node) { return node.op() == "InvGrad"; }
162bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang
163ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsLess(const NodeDef& node) { return node.op() == "Less"; }
164ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
165ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsLessEqual(const NodeDef& node) { return node.op() == "LessEqual"; }
166ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
167ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsLogicalAnd(const NodeDef& node) { return node.op() == "LogicalAnd"; }
168ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
169ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsLogicalNot(const NodeDef& node) { return node.op() == "LogicalNot"; }
170ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
171ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsLogicalOr(const NodeDef& node) { return node.op() == "LogicalOr"; }
172ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
17359ae88dac4399a8719aebe1b90f87f61fd1fd7e5A. Unique TensorFlowerbool IsMatMul(const NodeDef& node) {
174634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower  const auto& op = node.op();
17559ae88dac4399a8719aebe1b90f87f61fd1fd7e5A. Unique TensorFlower  return op == "MatMul" || op == "BatchMatMul" || op == "QuantizedMatMul" ||
17659ae88dac4399a8719aebe1b90f87f61fd1fd7e5A. Unique TensorFlower         op == "SparseMatMul";
17759ae88dac4399a8719aebe1b90f87f61fd1fd7e5A. Unique TensorFlower}
17859ae88dac4399a8719aebe1b90f87f61fd1fd7e5A. Unique TensorFlower
179d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsMax(const NodeDef& node) { return node.op() == "Max"; }
180d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang
181ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsMaximum(const NodeDef& node) { return node.op() == "Maximum"; }
182ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
183d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsMean(const NodeDef& node) { return node.op() == "Mean"; }
184d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang
1851a0f2fa7b0f4be4c0196c22b5c6ae717a8361ccaBenoit Steinerbool IsMerge(const NodeDef& node) {
186634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower  const auto& op = node.op();
18768eba33d21f692f6d9fe606d27f99387cac4dd18Benoit Steiner  return op == "Merge" || op == "RefMerge";
1881a0f2fa7b0f4be4c0196c22b5c6ae717a8361ccaBenoit Steiner}
1891a0f2fa7b0f4be4c0196c22b5c6ae717a8361ccaBenoit Steiner
190d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsMin(const NodeDef& node) { return node.op() == "Min"; }
191d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang
192ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsMinimum(const NodeDef& node) { return node.op() == "Minimum"; }
193ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
194e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhangbool IsMirrorPad(const NodeDef& node) { return node.op() == "MirrorPad"; }
195e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang
196e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhangbool IsMirrorPadGrad(const NodeDef& node) {
197e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang  return node.op() == "MirrorPadGrad";
198e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang}
199e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang
200ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsMod(const NodeDef& node) { return node.op() == "Mod"; }
201ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
202cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsMul(const NodeDef& node) { return node.op() == "Mul"; }
2031ffb45e7112addad325084084b93897918ed9a54Yao Zhang
204cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsNoOp(const NodeDef& node) { return node.op() == "NoOp"; }
2058f89b654f4d49a1b5d4462303ef27f7f7a2958b3A. Unique TensorFlower
206ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsNotEqual(const NodeDef& node) { return node.op() == "NotEqual"; }
207ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
2081fa8b4247a15079cb60da74a3c86ed5eef7f1b93Benoit Steinerbool IsNextIteration(const NodeDef& node) {
2091fa8b4247a15079cb60da74a3c86ed5eef7f1b93Benoit Steiner  const auto& op = node.op();
2101fa8b4247a15079cb60da74a3c86ed5eef7f1b93Benoit Steiner  return op == "NextIteration" || op == "RefNextIteration";
2111fa8b4247a15079cb60da74a3c86ed5eef7f1b93Benoit Steiner}
2121fa8b4247a15079cb60da74a3c86ed5eef7f1b93Benoit Steiner
213e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhangbool IsPad(const NodeDef& node) {
214e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang  const auto& op = node.op();
215e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang  return op == "Pad" || op == "PadV2";
216e0b647e10ae1e96e350b2ae75d14fd35fd3a0557Yao Zhang}
2171ffb45e7112addad325084084b93897918ed9a54Yao Zhang
2189d57702513001bfded19e72c76a986cce56d5f00Benoit Steinerbool IsPlaceholder(const NodeDef& node) {
219634515e14e8bf5aa4bdfe149b77c9aa53383891eA. Unique TensorFlower  const auto& op = node.op();
220b09932d749cdd8a9a78180820091dac924d18b8dBenoit Steiner  return op == "Placeholder" || op == "PlaceholderV2" ||
221b09932d749cdd8a9a78180820091dac924d18b8dBenoit Steiner         op == "PlaceholderWithDefault";
2229d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner}
2239d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner
224ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsPolygamma(const NodeDef& node) { return node.op() == "Polygamma"; }
225ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
226ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsPow(const NodeDef& node) { return node.op() == "Pow"; }
227ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
228d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhangbool IsProd(const NodeDef& node) { return node.op() == "Prod"; }
229d723bdb0051b4dc3b88dae459de2a18ea33441faYao Zhang
230ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsReal(const NodeDef& node) { return node.op() == "Real"; }
231ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
232cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsRealDiv(const NodeDef& node) { return node.op() == "RealDiv"; }
2331ffb45e7112addad325084084b93897918ed9a54Yao Zhang
234bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsReciprocalGrad(const NodeDef& node) {
235bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang  return node.op() == "ReciprocalGrad";
236bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang}
2371ffb45e7112addad325084084b93897918ed9a54Yao Zhang
238cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlowerbool IsRecv(const NodeDef& node) {
239cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlower  return node.op() == "_Recv" || node.op() == "_HostRecv";
240cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlower}
2418f89b654f4d49a1b5d4462303ef27f7f7a2958b3A. Unique TensorFlower
2429ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steinerbool IsReduction(const NodeDef& node) {
2439ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner  const auto& op = node.op();
2449ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner  return op == "Sum" || op == "Prod" || op == "Min" || op == "Max" ||
2459ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner         op == "Mean" || op == "Any" || op == "All";
2469ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner}
2479ae941c4a8c2d6e5a87c7a200ebde5bd0b07e5b2Benoit Steiner
248bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsReluGrad(const NodeDef& node) { return node.op() == "ReluGrad"; }
249bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang
250bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsRelu6Grad(const NodeDef& node) { return node.op() == "Relu6Grad"; }
251bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang
25259d37536717f08dd6e462ed785ee0e912ff344f5Benoit Steinerbool IsReshape(const NodeDef& node) { return (node.op() == "Reshape"); }
25359d37536717f08dd6e462ed785ee0e912ff344f5Benoit Steiner
25438445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhoubool IsRestore(const NodeDef& node) {
25538445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhou  return (node.op() == "Restore" || node.op() == "RestoreV2" ||
25638445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhou          node.op() == "RestoreSlice");
25738445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhou}
25838445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhou
2597989a3aa026f93c1f45e1baf4ac37ad2a79156f9A. Unique TensorFlowerbool IsReverseV2(const NodeDef& node) { return node.op() == "ReverseV2"; }
2607989a3aa026f93c1f45e1baf4ac37ad2a79156f9A. Unique TensorFlower
261bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsRsqrtGrad(const NodeDef& node) { return node.op() == "RsqrtGrad"; }
262bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang
26332ee432d9674567e80771b070e68e7f565d4fd2cYao Zhangbool IsSelect(const NodeDef& node) { return node.op() == "Select"; }
26432ee432d9674567e80771b070e68e7f565d4fd2cYao Zhang
265bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsSeluGrad(const NodeDef& node) { return node.op() == "SeluGrad"; }
266bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang
267cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlowerbool IsSend(const NodeDef& node) {
268cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlower  return node.op() == "_Send" || node.op() == "_HostSend";
269cb8dbae09f8be7a159cff7381f8f70871450e8afA. Unique TensorFlower}
2708f89b654f4d49a1b5d4462303ef27f7f7a2958b3A. Unique TensorFlower
271ea78050f20f7508537ccd1dee6dd60f0f40829ccYao Zhangbool IsShape(const NodeDef& node) { return node.op() == "Shape"; }
272ea78050f20f7508537ccd1dee6dd60f0f40829ccYao Zhang
273ea78050f20f7508537ccd1dee6dd60f0f40829ccYao Zhangbool IsShapeN(const NodeDef& node) { return node.op() == "ShapeN"; }
274ea78050f20f7508537ccd1dee6dd60f0f40829ccYao Zhang
275bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsSigmoidGrad(const NodeDef& node) { return node.op() == "SigmoidGrad"; }
276bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang
277cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsSlice(const NodeDef& node) { return node.op() == "Slice"; }
2781ffb45e7112addad325084084b93897918ed9a54Yao Zhang
279bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsSoftplusGrad(const NodeDef& node) { return node.op() == "SoftplusGrad"; }
280bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang
281bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsSoftsignGrad(const NodeDef& node) { return node.op() == "SoftsignGrad"; }
282bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang
2836c5ccadd434f2e6ed9634031bac2682c3dfe5216Yao Zhangbool IsSplit(const NodeDef& node) { return node.op() == "Split"; }
2846c5ccadd434f2e6ed9634031bac2682c3dfe5216Yao Zhang
285fa96f2595fa073a6bc943dfabea6852d41a706a3Yao Zhangbool IsSplitV(const NodeDef& node) { return node.op() == "SplitV"; }
286fa96f2595fa073a6bc943dfabea6852d41a706a3Yao Zhang
287bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsSqrtGrad(const NodeDef& node) { return node.op() == "SqrtGrad"; }
288bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang
2891ffb45e7112addad325084084b93897918ed9a54Yao Zhangbool IsSquaredDifference(const NodeDef& node) {
290cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower  return node.op() == "SquaredDifference";
2911ffb45e7112addad325084084b93897918ed9a54Yao Zhang}
2921ffb45e7112addad325084084b93897918ed9a54Yao Zhang
293cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsSqueeze(const NodeDef& node) { return node.op() == "Squeeze"; }
2941ffb45e7112addad325084084b93897918ed9a54Yao Zhang
295bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steinerbool IsStopGradient(const NodeDef& node) {
296bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steiner  const auto& op = node.op();
297bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steiner  return op == "StopGradient" || op == "PreventGradient";
298bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steiner}
299bb4a6168eaa0c6752d19e352f9c9dd53c9c6a6aeBenoit Steiner
300834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhangbool IsStridedSlice(const NodeDef& node) { return node.op() == "StridedSlice"; }
301834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhang
302834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhangbool IsStridedSliceGrad(const NodeDef& node) {
303834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhang  return node.op() == "StridedSliceGrad";
304834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhang}
305834f4558fbc27605cb0717949ddc276fd4c48c83Yao Zhang
306cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsSub(const NodeDef& node) { return node.op() == "Sub"; }
3071ffb45e7112addad325084084b93897918ed9a54Yao Zhang
308cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsSum(const NodeDef& node) { return node.op() == "Sum"; }
3091ffb45e7112addad325084084b93897918ed9a54Yao Zhang
31093c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steinerbool IsSwitch(const NodeDef& node) {
31193c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner  const auto& op = node.op();
31268eba33d21f692f6d9fe606d27f99387cac4dd18Benoit Steiner  return op == "Switch" || op == "RefSwitch";
31393c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner}
31493c57c6e4fe8f3ec1268bf8a947321cc4ba8bfc8Benoit Steiner
315bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhangbool IsTanhGrad(const NodeDef& node) { return node.op() == "TanhGrad"; }
316bb3c383ca03e116a3428bbd885be2f1726ff0c54Yao Zhang
31758a77fad5539454e674629d45df569af35453b02Yao Zhangbool IsTile(const NodeDef& node) { return node.op() == "Tile"; }
31858a77fad5539454e674629d45df569af35453b02Yao Zhang
319cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlowerbool IsTranspose(const NodeDef& node) { return node.op() == "Transpose"; }
32065044bc25981e4e060ad5c34d9a520a0561775c3Yao Zhang
321ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsTruncateDiv(const NodeDef& node) { return node.op() == "TruncateDiv"; }
322ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
323ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsTruncateMod(const NodeDef& node) { return node.op() == "TruncateMod"; }
324ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
3254254fa13de1697226e15df26cc101d00d1cb1a03Benoit Steinerbool IsVariable(const NodeDef& node) {
326cd8ced7a2d48574908d2c9b7127960078cf41690A. Unique TensorFlower  const auto& op = node.op();
3276fede95a1bbf11349a1c44fd1b85ac326cb43915Benoit Steiner  return op == "Variable" || op == "VariableV2" || op == "AutoReloadVariable" ||
32838445f025c4d05f374938e6c6c201dc3c0b20c77Yuefeng Zhou         op == "VarHandleOp" || op == "ReadVariableOp";
3294254fa13de1697226e15df26cc101d00d1cb1a03Benoit Steiner}
3304254fa13de1697226e15df26cc101d00d1cb1a03Benoit Steiner
331ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhangbool IsZeta(const NodeDef& node) { return node.op() == "Zeta"; }
332ab6ac785229336a9339b087bc8ab2c27043be329Yao Zhang
33350efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlowernamespace {
33450efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlowerbool GetBoolAttr(const NodeDef& node, const string& name) {
33550efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower  return node.attr().count(name) > 0 && node.attr().at(name).b();
33650efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower}
33750efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower}  // namespace
33850efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower
3392f2ab4bcba21059d5093eac7170662bc3b44c939Benoit Steinerbool IsPersistent(const NodeDef& node) {
3402f2ab4bcba21059d5093eac7170662bc3b44c939Benoit Steiner  return IsConstant(node) || IsVariable(node);
3412f2ab4bcba21059d5093eac7170662bc3b44c939Benoit Steiner}
3422f2ab4bcba21059d5093eac7170662bc3b44c939Benoit Steiner
343be4295e796437d18ffb7242942c963a8857e5003Benoit Steinerbool IsFreeOfSideEffect(const NodeDef& node) {
344be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  // Placeholders must be preserved to keep the graph feedable.
345be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  if (IsPlaceholder(node)) {
346be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner    return false;
347be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  }
348be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  const OpDef* op_def = nullptr;
349be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  Status status = OpRegistry::Global()->LookUpOpDef(node.op(), &op_def);
350be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  if (!status.ok()) {
351be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner    return false;
352be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  }
353be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  if (op_def->is_stateful()) {
354be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner    return false;
355be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  }
356be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  // Nodes such as Assign or AssignAdd modify one of their inputs.
357be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  for (const auto& input : op_def->input_arg()) {
358be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner    if (input.is_ref()) {
359be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner      return false;
360be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner    }
361be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  }
36250efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower  // Some nodes do in-place updates on regular tensor inputs.
36350efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower  if (GetBoolAttr(node, "in_place") || GetBoolAttr(node, "inplace")) {
36450efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower    return false;
36550efd9202b582900e30d9d4478b5baaf2107d84aA. Unique TensorFlower  }
366be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  return true;
367be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner}
368be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner
369be4295e796437d18ffb7242942c963a8857e5003Benoit Steinerbool ModifiesFrameInfo(const NodeDef& node) {
370be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner  return IsEnter(node) || IsExit(node) || IsNextIteration(node);
371be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner}
372be4295e796437d18ffb7242942c963a8857e5003Benoit Steiner
373c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower#define OPDEF_PROPERTY_HELPER(PROPERTY_CAP, PROPERTY)                      \
374c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower  bool Is##PROPERTY_CAP(const NodeDef& node) {                             \
375c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower    if (node.op() == "Add") {                                              \
376c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower      /* Workaround for "Add" not being marked is_commutative and */       \
377c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower      /* is_aggregate. (See cl/173915048). */                              \
378c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower      const auto type = GetDataTypeFromAttr(node, "T");                    \
379c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower      return type != DT_INVALID && type != DT_STRING;                      \
380c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower    }                                                                      \
381c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower    const OpDef* op_def = nullptr;                                         \
382c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower    Status status = OpRegistry::Global()->LookUpOpDef(node.op(), &op_def); \
383c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower    return status.ok() && op_def->is_##PROPERTY();                         \
384c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower  }
385c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower
386c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlowerOPDEF_PROPERTY_HELPER(Aggregate, aggregate)
387c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlowerOPDEF_PROPERTY_HELPER(Commutative, commutative)
388c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower
389c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlowerbool IsInvolution(const NodeDef& node) {
390c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower  const std::unordered_set<string> involution_ops{
391c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower      "Conj", "Reciprocal", "Invert", "Neg", "LogicalNot"};
392c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower  return involution_ops.count(node.op()) > 0;
393c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower}
394c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower
395c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlowerbool IsValuePreserving(const NodeDef& node) {
396c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower  if (NumNonControlInputs(node) == 1 && IsAggregate(node)) {
397c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower    return true;
398c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower  }
399c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower  const std::unordered_set<string> value_preserving_ops{
400c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower      "Transpose",  "Reshape",      "Identity",        "InvertPermutation",
401c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower      "Reverse",    "StopGradient", "PreventGradient", "CheckNumerics",
402c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower      "ExpandDims", "Squeeze"};
403c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower  return value_preserving_ops.count(node.op()) > 0;
404c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower}
405c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower
406fcf61d57079c8874cd479d4b0dfdb48033e742d8A. Unique TensorFlowerbool HasOpDef(const NodeDef& node) {
407fcf61d57079c8874cd479d4b0dfdb48033e742d8A. Unique TensorFlower  const OpDef* op_def = nullptr;
408fcf61d57079c8874cd479d4b0dfdb48033e742d8A. Unique TensorFlower  return OpRegistry::Global()->LookUpOpDef(node.op(), &op_def).ok();
409fcf61d57079c8874cd479d4b0dfdb48033e742d8A. Unique TensorFlower}
410fcf61d57079c8874cd479d4b0dfdb48033e742d8A. Unique TensorFlower
411c4ec569953069f689fd42bae92e15f6ccf40e364A. Unique TensorFlower}  // namespace grappler
4129d57702513001bfded19e72c76a986cce56d5f00Benoit Steiner}  // end namespace tensorflow
413