1c8b59c046895fa5b6d79f73e0b5817330fcfbfc1A. Unique TensorFlower/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
3db7478e8998f7703c57a75a950c905ec0cb59d7bJosh LevenbergLicensed under the Apache License, Version 2.0 (the "License");
4db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergyou may not use this file except in compliance with the License.
5db7478e8998f7703c57a75a950c905ec0cb59d7bJosh LevenbergYou may obtain a copy of the License at
6db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
7db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    http://www.apache.org/licenses/LICENSE-2.0
8db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
9db7478e8998f7703c57a75a950c905ec0cb59d7bJosh LevenbergUnless required by applicable law or agreed to in writing, software
10db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergdistributed under the License is distributed on an "AS IS" BASIS,
11db7478e8998f7703c57a75a950c905ec0cb59d7bJosh LevenbergWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12db7478e8998f7703c57a75a950c905ec0cb59d7bJosh LevenbergSee the License for the specific language governing permissions and
13db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberglimitations under the License.
14db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg==============================================================================*/
15db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
16db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#ifndef TENSORFLOW_CORE_FRAMEWORK_TENSOR_SHAPE_H_
17db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#define TENSORFLOW_CORE_FRAMEWORK_TENSOR_SHAPE_H_
18db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
19db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include <string>
20db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
21db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor"
229934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower#include "tensorflow/core/framework/types.pb.h"
23db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/core/errors.h"
24db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/core/status.h"
25db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/core/stringpiece.h"
26db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/gtl/array_slice.h"
27db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/gtl/inlined_vector.h"
28db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/strings/strcat.h"
29db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/platform/logging.h"
30db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
31db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergnamespace tensorflow {
32db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
33120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower// START_SKIP_DOXYGEN
34f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingtemplate <class Shape>
35f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingclass TensorShapeIter;
36f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingclass TensorShape;
37e85d3df92deb9d717befdf173966a2913ac2aea0Geoffrey Irvingclass TensorShapeProto;
38f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingclass PartialTensorShape;
39120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower// END_SKIP_DOXYGEN
40120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower
41f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// Internal representation for both TensorShape and PartialTensorShape.
42f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingclass TensorShapeRep {
43db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg public:
44f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  ~TensorShapeRep();
45df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
46df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  /// Copy the specified shape
47f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  TensorShapeRep(const TensorShapeRep& b);
48f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void operator=(const TensorShapeRep& b);
49df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
50f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  /// Move the specified shape.  After moving, <b> is safe for destruction and
51f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  // can be reassigned into, but its dimensions and number of elements can be
52f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  // nonsensical (e.g., negative dimension sizes, or number of elements not
53f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  // properly recomputed).
54f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  TensorShapeRep(TensorShapeRep&& b);
55f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void operator=(TensorShapeRep&& b);
56db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
57f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Clear a tensor shape, producing the scalar shape.
58db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  void Clear();
59db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
60ffd88925f4a29e68779f5b95eb99d60b40daf184David G. Andersen  // Maximum number of dimensions in a tensor.
61f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // It's 254 because 255 = kUnknownRank is used to represent unknown rank.
62f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static constexpr int MaxDimensions() { return 254; }
63db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
64db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// \brief Returns the number of elements in the tensor.
65db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  ///
66db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// We use `int64` and not `size_t` to be compatible with `Eigen::Tensor`
67f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// which uses `ptrdiff_t`.  For PartialTensorShape, -1 means not fully
68f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// defined.
69db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  int64 num_elements() const { return num_elements_; }
70db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
71db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// For error messages.
72db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  string DebugString() const;
73d552be23658b3bdd1b7dedd34f25631773e81dffGeoffrey Irving  static string DebugString(const TensorShapeProto& proto);
74d552be23658b3bdd1b7dedd34f25631773e81dffGeoffrey Irving
75df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  void DumpRep() const;  // XXX
76e8ee5286a686c6fc3057ba7cf9ba9ef7003789a6Geoffrey Irving
77f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving protected:
78f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // Constructable only via TensorShapeBase
79f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  TensorShapeRep() = default;
80df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
81f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void ClearAllButDataType();
82e8ee5286a686c6fc3057ba7cf9ba9ef7003789a6Geoffrey Irving
83df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // We use 16 bytes to represent a TensorShape.  Because we need to
84df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // be able to support full 64-bit dimension sizes and an arbitrary
85df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // number of dimensions for a Tensor, but most tensor dimensions are
86df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // significantly smaller than 64 bits and most tensors are 1, 2, or 3
87df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // dimensions, we have several representations.
88f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // Rep16: Supports up to 6 dimensions where each dimension is < 2^16 - 1
89f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // Rep32: Supports up to 3 dimensions where each dimension is < 2^32 - 1
901bcebcc665e7e9c280be65899002fd3d5a7456a5Geoffrey Irving  // Rep64: Supports arbitrary dimensionality, 64-bit dimensions using
91df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  //        an out of line vector.
92f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // For PartialTensorShape, a dimension of static_cast<uint??>(-1) is unknown.
93f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // This value is not allowed in TensorShape either for format compatibility.
94df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  struct Rep16 {
95f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving    uint16 dims_[6];
96df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  };
97df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  struct Rep32 {
98f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving    uint32 dims_[3];
99df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  };
100df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  struct Rep64 {
101df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    gtl::InlinedVector<int64, 4>* dims_;
102df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  };
103df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
104f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // We use the max value of uint16 or uint32 to represent unknown shapes, so
105f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // the maximum representable valid shape in these representations is one less.
106f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static const int64 kMaxRep16 = std::numeric_limits<uint16>::max() - 1;
107f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static const int64 kMaxRep32 = std::numeric_limits<uint32>::max() - 1;
108f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static const uint16 kUnknownRep16 = std::numeric_limits<uint16>::max();
109f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static const uint32 kUnknownRep32 = std::numeric_limits<uint32>::max();
110df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
111df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  Rep16* as16() { return reinterpret_cast<Rep16*>(buf()); }
112df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  Rep32* as32() { return reinterpret_cast<Rep32*>(buf()); }
113df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  Rep64* as64() { return reinterpret_cast<Rep64*>(buf()); }
114df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
115df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  const Rep16* as16() const { return reinterpret_cast<const Rep16*>(buf()); }
116df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  const Rep32* as32() const { return reinterpret_cast<const Rep32*>(buf()); }
117df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  const Rep64* as64() const { return reinterpret_cast<const Rep64*>(buf()); }
118df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
119df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  enum RepTag { REP16 = 0, REP32 = 1, REP_OUT_OF_LINE = 2 };
120df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
1219934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  // Since we have a convenient extra byte available, we allow the
1229934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  // Tensor class to store an 8-bit value in this extra storage.  This
1239934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  // allows it to store the Tensor's datatype enum value here and avoid
1249934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  // an extra word of storage.
1259934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  friend class Tensor;
1269934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  friend class TensorShapeTestHelper;
1279934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  DataType data_type() const { return static_cast<DataType>(buf()[13]); }
1289934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  void set_data_type(DataType dt) {
1299934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower    // We only have 8 bits available to store DataType, so make sure it fits
130f4002dd3cb62d64053bc6097a70f83c718c24af2A. Unique TensorFlower    DCHECK_LT(static_cast<uint32>(dt), 256u);
1319934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower    buf()[13] = static_cast<uint8>(dt);
1329934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  }
1339934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower
134df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // We store the number of dimensions in byte 14, and the RepTag in byte 15.
135f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // Bytes [0..13] vary depending on the representation.
136f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // A value of 255 indicates unknown rank in the PartialTensorShape case.
137f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static const uint8 kUnknownRank = 255;
138df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  uint8 ndims_byte() const { return buf()[14]; }
139df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  void set_ndims_byte(uint8 nd) { buf()[14] = nd; }
140df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
141df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  RepTag tag() const { return static_cast<RepTag>(buf()[15]); }
142df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  void set_tag(RepTag tag) { buf()[15] = static_cast<uint8>(tag); }
143df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
144f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void set_num_elements(int64 n) { num_elements_ = n; }
145f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
146f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving private:
147f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void DestructorOutOfLine();
148f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void SlowCopyFrom(const TensorShapeRep& b);
149f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
150f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  uint8* buf() { return &u_.buf[0]; }
151f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  const uint8* buf() const { return &u_.buf[0]; }
152f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
153df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  union {
154df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    uint8 buf[16];
155df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    // Force data to be aligned enough for a pointer.
156df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    Rep64* unused_aligner;
157df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  } u_;
158db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  int64 num_elements_;
159db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg};
160db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
161f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// Base class for TensorShape and PartialTensorShape.
162f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// The class is templatized by either TensorShape or PartialTensorShape to
163f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// allow skipping known/unknown checks in the TensorShape case, but the
164f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// representation is shared exactly for fast conversion.
165f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingtemplate <class Shape>
166f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingclass TensorShapeBase : public TensorShapeRep {
167f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving public:
168f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// \brief Construct a `TensorShapeBase` from the provided sizes.
169f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// REQUIRES: `dim_sizes[i] >= 0` (or >= -1 for PartialTensorShape)
170f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  explicit TensorShapeBase(gtl::ArraySlice<int64> dim_sizes);
171f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  TensorShapeBase(std::initializer_list<int64> dim_sizes)
172f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving      : TensorShapeBase(gtl::ArraySlice<int64>(dim_sizes)) {}
173f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
174f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Construct an empty TensorShape, or an unknown rank PartialTensorShape
175f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  TensorShapeBase();
176f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
177f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  TensorShapeBase(const TensorShapeProto& proto);
178f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
179f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Returns `true` iff `proto` is a valid tensor shape.
180f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // For TensorShape, the proto shape must be fully defined.
181f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static bool IsValid(const TensorShapeProto& proto);
182f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
183f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Returns `OK` iff `proto` is a valid tensor shape, and a descriptive error
184f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// status otherwise.
185f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static Status IsValidShape(const TensorShapeProto& proto);
186f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
187f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// \brief Add a dimension to the end ("inner-most").
188f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// REQUIRES: `size >= 0`
189f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void AddDim(int64 size);
190f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
191f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Appends all the dimensions from `shape`.
192f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void AppendShape(const TensorShapeBase& shape);
193f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
194f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// \brief Insert a dimension somewhere in the `TensorShape`.
195f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// REQUIRES: `0 <= d <= dims()`
196f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// REQUIRES: `size >= 0`
197f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void InsertDim(int d, int64 size);
198f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
199f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// \brief Modifies the size of the dimension `d` to be `size`
200f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// REQUIRES: `0 <= d < dims()`
201f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// REQUIRES: `size >= 0`
202f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void set_dim(int d, int64 size);
203f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
204f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// \brief Removes dimension `d` from the `TensorShape`.
205f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// REQUIRES: `0 <= d < dims()`
206b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower  void RemoveDim(int d) {
207b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower    CHECK_GE(d, 0);
208b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower    RemoveDimRange(d, d + 1);
209b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower  }
210b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower
211b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower  /// \brief Removes last `n` dimensions from the `TensorShape`.
212b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower  /// REQUIRES: `0 <= n <= dims()`
213b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower  void RemoveLastDims(int n) {
214b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower    CHECK_LE(n, dims());
215b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower    RemoveDimRange(dims() - n, dims());
216b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower  }
217b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower
218b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower  /// \brief Removes the dimensions in range `[begin:end)` from `TensorShape`.
219b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower  /// Negative values of `end` are interpreted as `dims() + end + 1` (as in
220b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower  /// Python). The same is true for negative values of `begin`. REQUIRES:
221b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower  /// `-(dims()+1) <= begin <= dims()` REQUIRES: `-(dims()+1) <= end <= dims()`
222b49aef3c17e39a9c7127477333c7cc76aef57a80A. Unique TensorFlower  void RemoveDimRange(int begin, int end);
223f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
224f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Return whether the rank is unknown
225f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  bool unknown_rank() const {
226f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving    return kIsPartial && ndims_byte() == kUnknownRank;
227f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  }
228f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
229f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Return the number of dimensions in the tensor.
230f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Can be -1 meaning unknown rank for PartialTensorShape.
231f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  int dims() const {
232f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving    uint8 dims = ndims_byte();
233f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving    return kIsPartial && dims == kUnknownRank ? -1 : dims;
234f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  }
235f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
236f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// \brief Returns the number of elements in dimension `d`.
237f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// REQUIRES: `0 <= d < dims()`
238f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // TODO(touts): Rename to `dimension()` to match
239f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // `Eigen::Tensor::dimension()`?
240f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  int64 dim_size(int d) const;
241f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
242f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Returns sizes of all dimensions.
243f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // Returns an empty list for unknown rank PartialTensorShape.
244f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  gtl::InlinedVector<int64, 4> dim_sizes() const;
245f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
246f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Return true iff the rank and all of the dimensions are well defined
247f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // TODO(irving): Rename to is_fully_defined now that it's fast.
248f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  bool IsFullyDefined() const { return !kIsPartial || num_elements() != -1; }
249f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
250f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Fill `*proto` from `*this`.
251f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void AsProto(TensorShapeProto* proto) const;
252f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
253f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// For iterating through the dimensions.
254f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  TensorShapeIter<Shape> begin() const;
255f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  TensorShapeIter<Shape> end() const;
256f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
257f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving private:
258f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void RecomputeNumElements();
259f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
260f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // True for PartialTensorShape, false for TensorShape
261f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static constexpr bool kIsPartial =
262f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving      std::is_same<Shape, PartialTensorShape>::value;
263f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static_assert(kIsPartial || std::is_same<Shape, TensorShape>::value,
264f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving                "Shape is neither TensorShape nor PartialTensorShape");
265f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
266f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // Used by AddDim and MakeShapeHelper.  Does no error checking.
267f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void UnsafeAddDim(int64 size, int64 new_num_elements);
268f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
269f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // For use by TensorShapeUtils::MakeShape
270f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  template <class T, class S>
271f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  friend Status MakeShapeHelper(const T*, int64, S*);
272f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving};
273f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
274f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// Represents the shape of a Tensor.
275f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving///
276f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// A tensor's shape is denoted by its number of dimensions and a size for each
277f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// dimension.  For example, a Tensor represented by a 3 x 4 matrix would have
278f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// a shape of 2-D, [3,4].
279f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving///
280f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// If you know the exact shape of your Tensor when you create the TensorShape
281f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// object, you can specify it then, or you can create a TensorShape with
282f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// zero dimensions and one element, and call AddDim() to add dimensions later.
283f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingclass TensorShape : public TensorShapeBase<TensorShape> {
284f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving public:
285f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  using TensorShapeBase<TensorShape>::TensorShapeBase;
286f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
287f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Allow a TensorShape to be used as a PartialTensorShape without copying
288f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  operator const PartialTensorShape&() const;  // NOLINT(runtime/explicit)
289f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
290f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Returns true if `*this` and `b` have the same sizes. Ignores
291f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// dimension names.
292f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  bool IsSameSize(const TensorShape& b) const;
293f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  bool operator==(const TensorShape& b) const { return IsSameSize(b); }
294f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  bool operator!=(const TensorShape& b) const { return !IsSameSize(b); }
295f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
296f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Fill `*dsizes` from `*this`.
297f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  template <int NDIMS>
298f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  Eigen::DSizes<Eigen::DenseIndex, NDIMS> AsEigenDSizes() const;
299f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
300f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Same as `AsEigenDSizes()` but allows for `NDIMS > dims()` -- in
301f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// which case we pad the rest of the sizes with 1.
302f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  template <int NDIMS>
303f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  Eigen::DSizes<Eigen::DenseIndex, NDIMS> AsEigenDSizesWithPadding() const;
304f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
305f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving private:
306f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // These CHECK fail to ease debugging.
307f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // REQUIRES: dims() == NDIMS
308f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void CheckDimsEqual(int NDIMS) const;
309f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // REQUIRES: dims() >= NDIMS
310f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  void CheckDimsAtLeast(int NDIMS) const;
311f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving};
312f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
313120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower/// Represents the value of one dimension in a TensorShape.
314db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergstruct TensorShapeDim {
315db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  explicit TensorShapeDim(int64 s) : size(s) {}
316d33346a801181cb601a4cfc95f1087e165b19703Vijay Vasudevan  int64 size;
317db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg};
318db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
319120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower// START_SKIP_DOXYGEN
320f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingtemplate <class Shape>
321db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergclass TensorShapeIter {
322db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg public:
323f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  TensorShapeIter(const Shape* shape, int d) : shape_(shape), d_(d) {}
324db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  bool operator==(const TensorShapeIter& rhs) {
325db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    DCHECK(shape_ == rhs.shape_);
326db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    return d_ == rhs.d_;
327db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
328db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  bool operator!=(const TensorShapeIter& rhs) {
329db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    DCHECK(shape_ == rhs.shape_);
330db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    return d_ != rhs.d_;
331db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
332db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  void operator++() { ++d_; }
333db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  TensorShapeDim operator*() { return TensorShapeDim(shape_->dim_size(d_)); }
334db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
335db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg private:
336f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  const Shape* shape_;
337db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  int d_;
338db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg};
339120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower// END_SKIP_DOXYGEN
340db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
341db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg/// \brief Static helper routines for `TensorShape`. Includes a few common
342db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg/// predicates on a tensor shape.
343db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergclass TensorShapeUtils {
344db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg public:
345db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static bool IsScalar(const TensorShape& shape) { return shape.dims() == 0; }
346db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
347db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static bool IsVector(const TensorShape& shape) { return shape.dims() == 1; }
348db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
349db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static bool IsVectorOrHigher(const TensorShape& shape) {
350db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    return shape.dims() >= 1;
351db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
352db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
353db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static bool IsMatrix(const TensorShape& shape) { return shape.dims() == 2; }
354db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
355053fc50b2cbb1979cbed1662c3d964c36fdafecdA. Unique TensorFlower  static bool IsSquareMatrix(const TensorShape& shape) {
356053fc50b2cbb1979cbed1662c3d964c36fdafecdA. Unique TensorFlower    return shape.dims() == 2 && shape.dim_size(0) == shape.dim_size(1);
357053fc50b2cbb1979cbed1662c3d964c36fdafecdA. Unique TensorFlower  }
358053fc50b2cbb1979cbed1662c3d964c36fdafecdA. Unique TensorFlower
359db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static bool IsMatrixOrHigher(const TensorShape& shape) {
360db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    return shape.dims() >= 2;
361db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
362db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
363db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// \brief Returns a `TensorShape` whose dimensions are
364db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// `dims[0]`, `dims[1]`, ..., `dims[n-1]`.
36596a1afa21c59999c68887550b0c8c27cdf171339David G. Andersen  static Status MakeShape(const int32* dims, int64 n, TensorShape* out);
36696a1afa21c59999c68887550b0c8c27cdf171339David G. Andersen  static Status MakeShape(const int64* dims, int64 n, TensorShape* out);
3679d6b7680cfcc5b784401d17fef997f0c089038b1A. Unique TensorFlower  static Status MakeShape(gtl::ArraySlice<int32> shape, TensorShape* out);
3689d6b7680cfcc5b784401d17fef997f0c089038b1A. Unique TensorFlower  static Status MakeShape(gtl::ArraySlice<int64> shape, TensorShape* out);
369f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static Status MakeShape(const int32* dims, int64 n, PartialTensorShape* out);
370f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static Status MakeShape(const int64* dims, int64 n, PartialTensorShape* out);
371f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static Status MakeShape(gtl::ArraySlice<int32> shape,
372f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving                          PartialTensorShape* out);
373f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static Status MakeShape(gtl::ArraySlice<int64> shape,
374f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving                          PartialTensorShape* out);
375db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
376725e968a934419eec45b9acaf4bf8dc5f5f0574eGeoffrey Irving  static string ShapeListString(const gtl::ArraySlice<TensorShape>& shapes);
377db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
378b5388091998dbeb6641b5d29dbceb825ee359acdA. Unique TensorFlower  /// \brief Returns true iff `shape` starts with `prefix`.
379b5388091998dbeb6641b5d29dbceb825ee359acdA. Unique TensorFlower  static bool StartsWith(const TensorShape& shape, const TensorShape& prefix);
380b5388091998dbeb6641b5d29dbceb825ee359acdA. Unique TensorFlower
381b5388091998dbeb6641b5d29dbceb825ee359acdA. Unique TensorFlower  /// \brief Returns true iff `shape` ends with `suffix`.
382b5388091998dbeb6641b5d29dbceb825ee359acdA. Unique TensorFlower  static bool EndsWith(const TensorShape& shape, const TensorShape& suffix);
383cade141580c76b41ba71bdc4b019722e674ab954Eugene Brevdo
384cade141580c76b41ba71bdc4b019722e674ab954Eugene Brevdo  /// \brief Returns the product of values in an int64 array,
385cade141580c76b41ba71bdc4b019722e674ab954Eugene Brevdo  /// or a failing Status if the array represents a value larger than
386cade141580c76b41ba71bdc4b019722e674ab954Eugene Brevdo  /// a `TensorShape` can hold.
387cade141580c76b41ba71bdc4b019722e674ab954Eugene Brevdo  static Status NumElements(gtl::ArraySlice<int64> shape, int64* num_elements);
388db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg};
389db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
390f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// Manages the partially known dimensions of a Tensor and their sizes.
391f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingclass PartialTensorShape : public TensorShapeBase<PartialTensorShape> {
392f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving public:
393f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  PartialTensorShape() {}
394f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  using TensorShapeBase<PartialTensorShape>::TensorShapeBase;
395f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
396f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Add a dimension to the end ("inner-most"), returns a new
397f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// PartialTensorShape.
398f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// REQUIRES: `size >= -1`, where -1 means unknown
399f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  PartialTensorShape Concatenate(int64 size) const;
400f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
401f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Appends all the dimensions from `shape`.  Returns a new
402f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// PartialTensorShape.
403f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  PartialTensorShape Concatenate(const PartialTensorShape& shape) const;
404f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
405f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Merges all the dimensions from `shape`.  Returns
406f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// `InvalidArgument` error if either `shape` has a different rank
407f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// or if any of the dimensions are incompatible.
408f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  Status MergeWith(const PartialTensorShape& shape,
409f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving                   PartialTensorShape* result) const;
410f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
411f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Exact equality test. Returns true iff the ranks match (i.e., both are
412f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// unknown, or both are known and equal), and all dimensions are equal (i.e.,
413f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// both dimensions are known, or both are known and equal). This is a
414f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// stronger condition that IsCompatibleWith.
415f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  bool IsIdenticalTo(const PartialTensorShape& shape) const;
416f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
417f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// Return true iff the ranks match, and if the
418f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// dimensions all either match or one is unknown.
419f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  bool IsCompatibleWith(const PartialTensorShape& shape) const;
420f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
421f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // Fill `*shape` from `*this`.
422f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // If `*this` is not fully defined, returns false and
423f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // `*shape` is left in an intermediate state.  Otherwise
424f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // returns true.
425f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  bool AsTensorShape(TensorShape* shape) const;
426f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
427f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// \brief Returns a `PartialTensorShape` whose dimensions are
428f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// `dims[0]`, `dims[1]`, ..., `dims[n-1]`.  Values of -1 are
429f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  /// considered "unknown".
430f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  template <class T>
431f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static Status MakePartialShape(const T* dims, int n,
432f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving                                 PartialTensorShape* out) {
433f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving    return TensorShapeUtils::MakeShape(dims, n, out);
434f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  }
435f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving};
436f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
437f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// \brief Static helper routines for `PartialTensorShape`. Includes a few
438f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving/// common predicates on a partially known tensor shape.
439f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingclass PartialTensorShapeUtils {
440f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving public:
441f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static string PartialShapeListString(
442f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving      const gtl::ArraySlice<PartialTensorShape>& shapes);
443f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
444f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static bool AreIdentical(const gtl::ArraySlice<PartialTensorShape>& shapes0,
445f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving                           const gtl::ArraySlice<PartialTensorShape>& shapes1);
446f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
447f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  static bool AreCompatible(const gtl::ArraySlice<PartialTensorShape>& shapes0,
448f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving                            const gtl::ArraySlice<PartialTensorShape>& shapes1);
449f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving};
450f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
451db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg// ----------------------------------------------------------------------------
452db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg// Template method implementation details below
453db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg// ----------------------------------------------------------------------------
454db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
455db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergtemplate <int NDIMS>
456db7478e8998f7703c57a75a950c905ec0cb59d7bJosh LevenbergEigen::DSizes<Eigen::DenseIndex, NDIMS> TensorShape::AsEigenDSizes() const {
457821920c1f25968f5dfcd2f8999b293ebedf85957A. Unique TensorFlower  CheckDimsEqual(NDIMS);
458db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  return AsEigenDSizesWithPadding<NDIMS>();
459db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg}
460db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
461db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergtemplate <int NDIMS>
462db7478e8998f7703c57a75a950c905ec0cb59d7bJosh LevenbergEigen::DSizes<Eigen::DenseIndex, NDIMS> TensorShape::AsEigenDSizesWithPadding()
463db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    const {
464821920c1f25968f5dfcd2f8999b293ebedf85957A. Unique TensorFlower  CheckDimsAtLeast(NDIMS);
4654d9ec5ece5771a1982352574ce2cad587644fadaDavid G. Andersen  static_assert(NDIMS <= TensorShape::MaxDimensions(), "Too many dimensions");
466db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  Eigen::DSizes<Eigen::DenseIndex, NDIMS> dsizes;
467db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  for (int d = 0; d < dims(); d++) {
468db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    dsizes[d] = dim_size(d);
469db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
470db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  for (int d = dims(); d < NDIMS; d++) {
471db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    dsizes[d] = 1;
472db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
473db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  return dsizes;
474db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg}
475db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
476df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower// ----------------------------------------------------------------------------
477df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower// Inlining of some performance critical routines
478df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower// ----------------------------------------------------------------------------
479df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
480f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvinginline TensorShapeRep::TensorShapeRep(const TensorShapeRep& b) {
481df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  num_elements_ = b.num_elements_;
482df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  if (b.tag() != REP_OUT_OF_LINE) {
483df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    memcpy(buf(), b.buf(), sizeof(u_.buf));
484df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    // memcpy above Implicitly does:
485df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    //   set_ndims_byte(b.ndims_byte());
486df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    //   set_tag(b.tag());
487df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  } else {
488df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    set_tag(REP16);  // So that SlowCopyFrom does not try to deallocate
489df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    SlowCopyFrom(b);
490df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  }
491df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower}
492df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
493f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvinginline TensorShapeRep::TensorShapeRep(TensorShapeRep&& b) {
494f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  num_elements_ = b.num_elements_;
495f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  memcpy(buf(), b.buf(), sizeof(u_.buf));
496f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  // memcpy above Implicitly does:
497f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  //   set_ndims_byte(b.ndims_byte());
498f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  //   set_tag(b.tag());
499f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  b.set_tag(REP16);  // other shape no longer owns out-of-line data, if any.
500f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower}
501f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower
502f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvinginline TensorShapeRep::~TensorShapeRep() {
503df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  if (tag() == REP_OUT_OF_LINE) {
504b76812c8a84c0efd45342121bfc1cff2b6bb1051A. Unique TensorFlower    DestructorOutOfLine();
505df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  }
506df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower}
507df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
508f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvinginline void TensorShapeRep::operator=(const TensorShapeRep& b) {
509df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  num_elements_ = b.num_elements_;
510df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  if (tag() != REP_OUT_OF_LINE && b.tag() != REP_OUT_OF_LINE) {
511df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    memcpy(buf(), b.buf(), sizeof(u_.buf));
512df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    // memcpy above implicitly also does:
513df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    //   set_tag(b.tag());
514df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    //   set_ndims_byte(b.ndims_byte());
515df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  } else {
516df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    SlowCopyFrom(b);
517df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  }
518df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower}
519df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
520f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvinginline void TensorShapeRep::operator=(TensorShapeRep&& b) {
521f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  if (tag() == REP_OUT_OF_LINE) {
522f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower    DestructorOutOfLine();
523f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  }
524f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  num_elements_ = b.num_elements_;
525f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  memcpy(buf(), b.buf(), sizeof(u_.buf));
526f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  // memcpy above Implicitly does:
527f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  //   set_ndims_byte(b.ndims_byte());
528f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  //   set_tag(b.tag());
529f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  b.set_tag(REP16);  // other shape no longer owns out-of-line data, if any.
530f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower}
531f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower
532f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvinginline TensorShape::operator const PartialTensorShape&() const {
533f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  // Downcast to the shared representation and upcast to PartialTensorShape
534f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  const TensorShapeRep* rep = this;
535f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving  return *static_cast<const PartialTensorShape*>(rep);
536f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving}
537f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
538f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving// Declare explicit instantiations in .cc file
539f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingextern template class TensorShapeBase<TensorShape>;
540f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irvingextern template class TensorShapeBase<PartialTensorShape>;
541f5bbcdf2d05ddc3b24a17ac7fc2cfdf36ef2ee2bGeoffrey Irving
542db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg}  // namespace tensorflow
543db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
544db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#endif  // TENSORFLOW_CORE_FRAMEWORK_TENSOR_SHAPE_H_
545