tensor_shape.h revision e8ee5286a686c6fc3057ba7cf9ba9ef7003789a6
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"
22db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/framework/tensor_shape.pb.h"
239934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower#include "tensorflow/core/framework/types.pb.h"
24db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/core/errors.h"
25db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/core/status.h"
26db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/core/stringpiece.h"
27db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/gtl/array_slice.h"
28db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/gtl/inlined_vector.h"
29db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/lib/strings/strcat.h"
30db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#include "tensorflow/core/platform/logging.h"
31db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
32db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergnamespace tensorflow {
33db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
34120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower// START_SKIP_DOXYGEN
35db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergclass TensorShapeIter;  // Declared below
36120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower// END_SKIP_DOXYGEN
37120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower
38120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower/// Represents the shape of a Tensor.
39120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower///
40120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower/// A tensor's shape is denoted by its number of dimensions and a size for each
41120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower/// dimension.  For example, a Tensor represented by a 3 x 4 matrix would have
42120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower/// a shape of 2-D, [3,4].
43120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower///
44120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower/// If you know the exact shape of your Tensor when you create the TensorShape
45120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower/// object, you can specify it then, or you can create a TensorShape with
46120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower/// zero dimensions and one element, and call AddDim() to add dimensions later.
47db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergclass TensorShape {
48db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg public:
49db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// \brief Construct a `TensorShape` from the provided sizes.
50db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// REQUIRES: `dim_sizes[i] >= 0`
51db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  explicit TensorShape(gtl::ArraySlice<int64> dim_sizes);
52db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  TensorShape(std::initializer_list<int64> dim_sizes)
53db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg      : TensorShape(gtl::ArraySlice<int64>(dim_sizes)) {}
54db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
55db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// REQUIRES: `IsValid(proto)`
56db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  explicit TensorShape(const TensorShapeProto& proto);
57db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
58db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// Create a tensor shape with no dimensions and one element, which you can
59db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// then call `AddDim()` on.
60db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  TensorShape();
61db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
62df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  ~TensorShape();
63df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
64df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  /// Copy the specified shape
65df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  TensorShape(const TensorShape& b);
66df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  void operator=(const TensorShape& b);
67df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
68f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  /// Move the specified shape.  After moving, <b> is safe for destruction and
69f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  // can be reassigned into, but its dimensions and number of elements can be
70f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  // nonsensical (e.g., negative dimension sizes, or number of elements not
71f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  // properly recomputed).
72f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  TensorShape(TensorShape&& b);
73f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  void operator=(TensorShape&& b);
74f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower
75db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// Returns `true` iff `proto` is a valid tensor shape.
76db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static bool IsValid(const TensorShapeProto& proto);
77db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
78db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// Returns `OK` iff `proto` is a valid tensor shape, and a descriptive error
79db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// status otherwise.
80db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static Status IsValidShape(const TensorShapeProto& proto);
81db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
82db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// Clear a tensor shape
83db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  void Clear();
84db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
85db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// \brief Add a dimension to the end ("inner-most").
86db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// REQUIRES: `size >= 0`
87db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  void AddDim(int64 size);
88db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
89db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// Appends all the dimensions from `shape`.
90db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  void AppendShape(const TensorShape& shape);
91db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
92ffd88925f4a29e68779f5b95eb99d60b40daf184David G. Andersen  // Maximum number of dimensions in a tensor.
93ffd88925f4a29e68779f5b95eb99d60b40daf184David G. Andersen  static constexpr int MaxDimensions() { return 255; }
94ffd88925f4a29e68779f5b95eb99d60b40daf184David G. Andersen
95db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// \brief Insert a dimension somewhere in the `TensorShape`.
96db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// REQUIRES: `0 <= d <= dims()`
97db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// REQUIRES: `size >= 0`
98db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  void InsertDim(int d, int64 size);
99db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
100db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// \brief Modifies the size of the dimension `d` to be `size`
101db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// REQUIRES: `0 <= d < dims()`
102db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// REQUIRES: `size >= 0`
103db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  void set_dim(int d, int64 size);
104db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
105db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// \brief Removes dimension `d` from the `TensorShape`.
106db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// REQUIRES: `0 <= d < dims()`
107db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  void RemoveDim(int d);
108db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
109db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// Return the number of dimensions in the tensor.
110df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  int dims() const {
1119ccc4b6afe4defa748de89eac90ba1062232bb5aA. Unique TensorFlower    DCHECK(tag() != REP_OUT_OF_LINE || (*as64()->dims_).size() == ndims_byte());
1129ccc4b6afe4defa748de89eac90ba1062232bb5aA. Unique TensorFlower    return ndims_byte();
113df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  }
114db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
115db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// \brief Returns the number of elements in dimension `d`.
116db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// REQUIRES: `0 <= d < dims()`
117db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  // TODO(touts): Rename to `dimension()` to match
118db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  // `Eigen::Tensor::dimension()`?
1199ccc4b6afe4defa748de89eac90ba1062232bb5aA. Unique TensorFlower  int64 dim_size(int d) const;
120db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
121db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// Returns sizes of all dimensions.
122df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  gtl::InlinedVector<int64, 4> dim_sizes() const;
123db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
124db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// \brief Returns the number of elements in the tensor.
125db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  ///
126db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// We use `int64` and not `size_t` to be compatible with `Eigen::Tensor`
127db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// which uses `ptrdiff_t`.
128db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  int64 num_elements() const { return num_elements_; }
129db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
130db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// Returns true if `*this` and `b` have the same sizes. Ignores
131db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// dimension names.
132db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  bool IsSameSize(const TensorShape& b) const;
133db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  bool operator==(const TensorShape& b) const { return IsSameSize(b); }
13412b36c655359319c1ad31907d407bba3c594fee7A. Unique TensorFlower  bool operator!=(const TensorShape& b) const { return !IsSameSize(b); }
135db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
136db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// Fill `*proto` from `*this`.
137db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  void AsProto(TensorShapeProto* proto) const;
138db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
139db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// Fill `*dsizes` from `*this`.
140db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  template <int NDIMS>
141db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  Eigen::DSizes<Eigen::DenseIndex, NDIMS> AsEigenDSizes() const;
142db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
143db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// Same as `AsEigenDSizes()` but allows for `NDIMS > dims()` -- in
144db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// which case we pad the rest of the sizes with 1.
145db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  template <int NDIMS>
146db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  Eigen::DSizes<Eigen::DenseIndex, NDIMS> AsEigenDSizesWithPadding() const;
147db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
148db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// For iterating through the dimensions.
149db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  TensorShapeIter begin() const;
150db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  TensorShapeIter end() const;
151db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
152db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// For error messages.
153db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  string DebugString() const;
154db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
155d552be23658b3bdd1b7dedd34f25631773e81dffGeoffrey Irving  /// Same as `TensorShape(proto).DebugString()` but doesn't crash for
156db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// invalid protos.
157d552be23658b3bdd1b7dedd34f25631773e81dffGeoffrey Irving  static string DebugString(const TensorShapeProto& proto);
158d552be23658b3bdd1b7dedd34f25631773e81dffGeoffrey Irving
159df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  void DumpRep() const;  // XXX
160e8ee5286a686c6fc3057ba7cf9ba9ef7003789a6Geoffrey Irving
161db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg private:
162b76812c8a84c0efd45342121bfc1cff2b6bb1051A. Unique TensorFlower  void DestructorOutOfLine();
1639934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  void ClearAllButDataType();
164df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  void SlowCopyFrom(const TensorShape& b);
165df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
166df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  void RecomputeNumElements();
167df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
168821920c1f25968f5dfcd2f8999b293ebedf85957A. Unique TensorFlower  void CheckDimsEqual(int NDIMS) const;
169821920c1f25968f5dfcd2f8999b293ebedf85957A. Unique TensorFlower  void CheckDimsAtLeast(int NDIMS) const;
170821920c1f25968f5dfcd2f8999b293ebedf85957A. Unique TensorFlower
171e8ee5286a686c6fc3057ba7cf9ba9ef7003789a6Geoffrey Irving  // Used by AddDim and MakeShapeHelper.  Does no error checking.
172e8ee5286a686c6fc3057ba7cf9ba9ef7003789a6Geoffrey Irving  void UnsafeAddDim(int64 size, int64 new_num_elements);
173e8ee5286a686c6fc3057ba7cf9ba9ef7003789a6Geoffrey Irving
174e8ee5286a686c6fc3057ba7cf9ba9ef7003789a6Geoffrey Irving  // For use by TensorShapeUtils::MakeShape
175e8ee5286a686c6fc3057ba7cf9ba9ef7003789a6Geoffrey Irving  template <class T>
176e8ee5286a686c6fc3057ba7cf9ba9ef7003789a6Geoffrey Irving  friend Status MakeShapeHelper(const T*, int64, TensorShape*);
177e8ee5286a686c6fc3057ba7cf9ba9ef7003789a6Geoffrey Irving
178df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // We use 16 bytes to represent a TensorShape.  Because we need to
179df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // be able to support full 64-bit dimension sizes and an arbitrary
180df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // number of dimensions for a Tensor, but most tensor dimensions are
181df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // significantly smaller than 64 bits and most tensors are 1, 2, or 3
182df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // dimensions, we have several representations.
1839934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  // Rep16: Supports up to 6 dimensions where each dimension is < 2^16
184df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // Rep32: Supports up to 3 dimensions where each dimension is < 2^32
1851bcebcc665e7e9c280be65899002fd3d5a7456a5Geoffrey Irving  // Rep64: Supports arbitrary dimensionality, 64-bit dimensions using
186df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  //        an out of line vector.
187df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  struct Rep16 {
1889934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower    int16 dims_[6];
189df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  };
190df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  struct Rep32 {
191df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    int32 dims_[3];
192df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  };
193df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  struct Rep64 {
194df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    gtl::InlinedVector<int64, 4>* dims_;
195df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  };
196df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
197df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  static const int64 kMaxRep16 = 32768;
198df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  static const int64 kMaxRep32 = (1ull << 31) - 1;
199df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
200df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  uint8* buf() { return &u_.buf[0]; }
201df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  const uint8* buf() const { return &u_.buf[0]; }
202df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
203df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  Rep16* as16() { return reinterpret_cast<Rep16*>(buf()); }
204df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  Rep32* as32() { return reinterpret_cast<Rep32*>(buf()); }
205df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  Rep64* as64() { return reinterpret_cast<Rep64*>(buf()); }
206df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
207df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  const Rep16* as16() const { return reinterpret_cast<const Rep16*>(buf()); }
208df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  const Rep32* as32() const { return reinterpret_cast<const Rep32*>(buf()); }
209df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  const Rep64* as64() const { return reinterpret_cast<const Rep64*>(buf()); }
210df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
211df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  enum RepTag { REP16 = 0, REP32 = 1, REP_OUT_OF_LINE = 2 };
212df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
2139934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  // Since we have a convenient extra byte available, we allow the
2149934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  // Tensor class to store an 8-bit value in this extra storage.  This
2159934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  // allows it to store the Tensor's datatype enum value here and avoid
2169934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  // an extra word of storage.
2179934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  friend class Tensor;
2189934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  friend class TensorShapeTestHelper;
2199934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  DataType data_type() const { return static_cast<DataType>(buf()[13]); }
2209934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  void set_data_type(DataType dt) {
2219934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower    // We only have 8 bits available to store DataType, so make sure it fits
222f4002dd3cb62d64053bc6097a70f83c718c24af2A. Unique TensorFlower    DCHECK_LT(static_cast<uint32>(dt), 256u);
2239934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower    buf()[13] = static_cast<uint8>(dt);
2249934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower  }
2259934b9c6841ee56368c7cb1d10053f68a02680baA. Unique TensorFlower
226df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // We store the number of dimensions in byte 14, and the RepTag in byte 15.
227df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  // Bytes [0..13] vary depending on the representation
228df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  uint8 ndims_byte() const { return buf()[14]; }
229df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  void set_ndims_byte(uint8 nd) { buf()[14] = nd; }
230df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
231df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  RepTag tag() const { return static_cast<RepTag>(buf()[15]); }
232df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  void set_tag(RepTag tag) { buf()[15] = static_cast<uint8>(tag); }
233df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
234df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  union {
235df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    uint8 buf[16];
236df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    // Force data to be aligned enough for a pointer.
237df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    Rep64* unused_aligner;
238df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  } u_;
239db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  int64 num_elements_;
240db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg};
241db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
242120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower/// Represents the value of one dimension in a TensorShape.
243db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergstruct TensorShapeDim {
244db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  explicit TensorShapeDim(int64 s) : size(s) {}
245d33346a801181cb601a4cfc95f1087e165b19703Vijay Vasudevan  int64 size;
246db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg};
247db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
248120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower// START_SKIP_DOXYGEN
249db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergclass TensorShapeIter {
250db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg public:
251db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  TensorShapeIter(const TensorShape* shape, int d) : shape_(shape), d_(d) {}
252db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  bool operator==(const TensorShapeIter& rhs) {
253db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    DCHECK(shape_ == rhs.shape_);
254db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    return d_ == rhs.d_;
255db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
256db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  bool operator!=(const TensorShapeIter& rhs) {
257db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    DCHECK(shape_ == rhs.shape_);
258db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    return d_ != rhs.d_;
259db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
260db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  void operator++() { ++d_; }
261db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  TensorShapeDim operator*() { return TensorShapeDim(shape_->dim_size(d_)); }
262db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
263db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg private:
264db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  const TensorShape* shape_;
265db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  int d_;
266db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg};
267120c3f11f857ce6da7ae90b3eab943896499dca2A. Unique TensorFlower// END_SKIP_DOXYGEN
268db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
269db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg/// \brief Static helper routines for `TensorShape`. Includes a few common
270db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg/// predicates on a tensor shape.
271db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergclass TensorShapeUtils {
272db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg public:
273db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static bool IsScalar(const TensorShape& shape) { return shape.dims() == 0; }
274db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
275db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static bool IsVector(const TensorShape& shape) { return shape.dims() == 1; }
276db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
277db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static bool IsVectorOrHigher(const TensorShape& shape) {
278db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    return shape.dims() >= 1;
279db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
280db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
281db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static bool IsMatrix(const TensorShape& shape) { return shape.dims() == 2; }
282db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
283053fc50b2cbb1979cbed1662c3d964c36fdafecdA. Unique TensorFlower  static bool IsSquareMatrix(const TensorShape& shape) {
284053fc50b2cbb1979cbed1662c3d964c36fdafecdA. Unique TensorFlower    return shape.dims() == 2 && shape.dim_size(0) == shape.dim_size(1);
285053fc50b2cbb1979cbed1662c3d964c36fdafecdA. Unique TensorFlower  }
286053fc50b2cbb1979cbed1662c3d964c36fdafecdA. Unique TensorFlower
287db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  static bool IsMatrixOrHigher(const TensorShape& shape) {
288db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    return shape.dims() >= 2;
289db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
290db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
291db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// \brief Returns a `TensorShape` whose dimensions are
292db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  /// `dims[0]`, `dims[1]`, ..., `dims[n-1]`.
29396a1afa21c59999c68887550b0c8c27cdf171339David G. Andersen  static Status MakeShape(const int32* dims, int64 n, TensorShape* out);
29496a1afa21c59999c68887550b0c8c27cdf171339David G. Andersen  static Status MakeShape(const int64* dims, int64 n, TensorShape* out);
2959d6b7680cfcc5b784401d17fef997f0c089038b1A. Unique TensorFlower  static Status MakeShape(gtl::ArraySlice<int32> shape, TensorShape* out);
2969d6b7680cfcc5b784401d17fef997f0c089038b1A. Unique TensorFlower  static Status MakeShape(gtl::ArraySlice<int64> shape, TensorShape* out);
297db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
298725e968a934419eec45b9acaf4bf8dc5f5f0574eGeoffrey Irving  static string ShapeListString(const gtl::ArraySlice<TensorShape>& shapes);
299db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
300b5388091998dbeb6641b5d29dbceb825ee359acdA. Unique TensorFlower  /// \brief Returns true iff `shape` starts with `prefix`.
301b5388091998dbeb6641b5d29dbceb825ee359acdA. Unique TensorFlower  static bool StartsWith(const TensorShape& shape, const TensorShape& prefix);
302b5388091998dbeb6641b5d29dbceb825ee359acdA. Unique TensorFlower
303b5388091998dbeb6641b5d29dbceb825ee359acdA. Unique TensorFlower  /// \brief Returns true iff `shape` ends with `suffix`.
304b5388091998dbeb6641b5d29dbceb825ee359acdA. Unique TensorFlower  static bool EndsWith(const TensorShape& shape, const TensorShape& suffix);
305db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg};
306db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
307db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg// ----------------------------------------------------------------------------
308db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg// Template method implementation details below
309db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg// ----------------------------------------------------------------------------
310db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
311db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergtemplate <int NDIMS>
312db7478e8998f7703c57a75a950c905ec0cb59d7bJosh LevenbergEigen::DSizes<Eigen::DenseIndex, NDIMS> TensorShape::AsEigenDSizes() const {
313821920c1f25968f5dfcd2f8999b293ebedf85957A. Unique TensorFlower  CheckDimsEqual(NDIMS);
314db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  return AsEigenDSizesWithPadding<NDIMS>();
315db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg}
316db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
317db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenbergtemplate <int NDIMS>
318db7478e8998f7703c57a75a950c905ec0cb59d7bJosh LevenbergEigen::DSizes<Eigen::DenseIndex, NDIMS> TensorShape::AsEigenDSizesWithPadding()
319db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    const {
320821920c1f25968f5dfcd2f8999b293ebedf85957A. Unique TensorFlower  CheckDimsAtLeast(NDIMS);
3214d9ec5ece5771a1982352574ce2cad587644fadaDavid G. Andersen  static_assert(NDIMS <= TensorShape::MaxDimensions(), "Too many dimensions");
322db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  Eigen::DSizes<Eigen::DenseIndex, NDIMS> dsizes;
323db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  for (int d = 0; d < dims(); d++) {
324db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    dsizes[d] = dim_size(d);
325db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
326db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  for (int d = dims(); d < NDIMS; d++) {
327db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg    dsizes[d] = 1;
328db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  }
329db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg  return dsizes;
330db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg}
331db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
332df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower// ----------------------------------------------------------------------------
333df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower// Inlining of some performance critical routines
334df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower// ----------------------------------------------------------------------------
335df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
336df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlowerinline TensorShape::TensorShape(const TensorShape& b) {
337df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  num_elements_ = b.num_elements_;
338df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  if (b.tag() != REP_OUT_OF_LINE) {
339df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    memcpy(buf(), b.buf(), sizeof(u_.buf));
340df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    // memcpy above Implicitly does:
341df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    //   set_ndims_byte(b.ndims_byte());
342df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    //   set_tag(b.tag());
343df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  } else {
344df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    set_tag(REP16);  // So that SlowCopyFrom does not try to deallocate
345df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    SlowCopyFrom(b);
346df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  }
347df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower}
348df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
349f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlowerinline TensorShape::TensorShape(TensorShape&& b) {
350f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  num_elements_ = b.num_elements_;
351f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  memcpy(buf(), b.buf(), sizeof(u_.buf));
352f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  // memcpy above Implicitly does:
353f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  //   set_ndims_byte(b.ndims_byte());
354f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  //   set_tag(b.tag());
355f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  b.set_tag(REP16);  // other shape no longer owns out-of-line data, if any.
356f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower}
357f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower
358df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlowerinline TensorShape::~TensorShape() {
359df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  if (tag() == REP_OUT_OF_LINE) {
360b76812c8a84c0efd45342121bfc1cff2b6bb1051A. Unique TensorFlower    DestructorOutOfLine();
361df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  }
362df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower}
363df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
364df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlowerinline void TensorShape::operator=(const TensorShape& b) {
365df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  num_elements_ = b.num_elements_;
366df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  if (tag() != REP_OUT_OF_LINE && b.tag() != REP_OUT_OF_LINE) {
367df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    memcpy(buf(), b.buf(), sizeof(u_.buf));
368df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    // memcpy above implicitly also does:
369df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    //   set_tag(b.tag());
370df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    //   set_ndims_byte(b.ndims_byte());
371df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  } else {
372df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower    SlowCopyFrom(b);
373df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower  }
374df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower}
375df66b9fe049cb17e58454f309b662bdaf0d14fdbA. Unique TensorFlower
376f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlowerinline void TensorShape::operator=(TensorShape&& b) {
377f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  if (tag() == REP_OUT_OF_LINE) {
378f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower    DestructorOutOfLine();
379f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  }
380f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  num_elements_ = b.num_elements_;
381f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  memcpy(buf(), b.buf(), sizeof(u_.buf));
382f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  // memcpy above Implicitly does:
383f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  //   set_ndims_byte(b.ndims_byte());
384f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  //   set_tag(b.tag());
385f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower  b.set_tag(REP16);  // other shape no longer owns out-of-line data, if any.
386f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower}
387f7a662e595f1631c12d15173344ee0f50d2cd9f8A. Unique TensorFlower
388db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg}  // namespace tensorflow
389db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg
390db7478e8998f7703c57a75a950c905ec0cb59d7bJosh Levenberg#endif  // TENSORFLOW_CORE_FRAMEWORK_TENSOR_SHAPE_H_
391