1/* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2
3Licensed under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License.
5You may obtain a copy of the License at
6
7    http://www.apache.org/licenses/LICENSE-2.0
8
9Unless required by applicable law or agreed to in writing, software
10distributed under the License is distributed on an "AS IS" BASIS,
11WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12See the License for the specific language governing permissions and
13limitations under the License.
14==============================================================================*/
15
16#include "tensorflow/core/framework/tensor_util.h"
17
18#include <vector>
19#include "tensorflow/core/framework/tensor.h"
20#include "tensorflow/core/framework/types.h"
21#include "tensorflow/core/lib/core/status_test_util.h"
22#include "tensorflow/core/platform/test.h"
23
24namespace tensorflow {
25namespace {
26
27TEST(TensorUtil, DeepCopy0d) {
28  Tensor x(DT_FLOAT, TensorShape({}));
29  x.scalar<float>()() = 10.0;
30
31  // Make y a deep copy of x and then change it.
32  Tensor y = tensor::DeepCopy(x);
33  y.scalar<float>()() = 20.0;
34
35  // x doesn't change
36  EXPECT_EQ(10.0, x.scalar<float>()());
37
38  // Change x.
39  x.scalar<float>()() = 30.0;
40
41  // Y doesn't change.
42  EXPECT_EQ(20.0, y.scalar<float>()());
43
44  Tensor z = tensor::DeepCopy(y);
45
46  // Change y.
47  y.scalar<float>()() = 40.0;
48
49  // The final states should all be different.
50  EXPECT_EQ(20.0, z.scalar<float>()());
51  EXPECT_EQ(30.0, x.scalar<float>()());
52  EXPECT_EQ(40.0, y.scalar<float>()());
53
54  // Should have the same shape and type.
55  EXPECT_EQ(TensorShape({}), x.shape());
56  EXPECT_EQ(TensorShape({}), y.shape());
57  EXPECT_EQ(TensorShape({}), z.shape());
58
59  EXPECT_EQ(DT_FLOAT, x.dtype());
60  EXPECT_EQ(DT_FLOAT, y.dtype());
61  EXPECT_EQ(DT_FLOAT, z.dtype());
62}
63
64TEST(TensorUtil, DeepCopyZeroElements) {
65  Tensor x;
66  Tensor y = tensor::DeepCopy(x);
67  EXPECT_EQ(TensorShape({0}), y.shape());
68  EXPECT_EQ(DT_FLOAT, y.dtype());
69  EXPECT_EQ(0, y.NumElements());
70}
71
72TEST(TensorUtil, DeepCopy) {
73  Tensor x(DT_FLOAT, TensorShape({1}));
74  x.flat<float>()(0) = 10.0;
75
76  // Make y a deep copy of x and then change it.
77  Tensor y = tensor::DeepCopy(x);
78  y.flat<float>()(0) = 20.0;
79
80  // x doesn't change
81  EXPECT_EQ(10.0, x.flat<float>()(0));
82
83  // Change x.
84  x.flat<float>()(0) = 30.0;
85
86  // Y doesn't change.
87  EXPECT_EQ(20.0, y.flat<float>()(0));
88
89  Tensor z = tensor::DeepCopy(y);
90
91  // Change y.
92  y.flat<float>()(0) = 40.0;
93
94  // The final states should all be different.
95  EXPECT_EQ(20.0, z.flat<float>()(0));
96  EXPECT_EQ(30.0, x.flat<float>()(0));
97  EXPECT_EQ(40.0, y.flat<float>()(0));
98
99  // Should have the same shape and type.
100  EXPECT_EQ(TensorShape({1}), x.shape());
101  EXPECT_EQ(TensorShape({1}), y.shape());
102  EXPECT_EQ(TensorShape({1}), z.shape());
103
104  EXPECT_EQ(DT_FLOAT, x.dtype());
105  EXPECT_EQ(DT_FLOAT, y.dtype());
106  EXPECT_EQ(DT_FLOAT, z.dtype());
107
108  // Test string deep copy
109  Tensor str1(DT_STRING, TensorShape({2}));
110  str1.flat<string>()(0) = "foo1";
111  str1.flat<string>()(1) = "foo2";
112  Tensor str2 = tensor::DeepCopy(str1);
113  str2.flat<string>()(0) = "bar1";
114  str2.flat<string>()(1) = "bar2";
115  EXPECT_NE(str2.flat<string>()(0), str1.flat<string>()(0));
116}
117
118TEST(TensorUtil, DeepCopySlice) {
119  Tensor x(DT_INT32, TensorShape({10}));
120  x.flat<int32>().setConstant(1);
121
122  // Slice 'x' -- y still refers to the same buffer.
123  Tensor y = x.Slice(2, 6);
124
125  // Do a deep copy of y, which is a slice.
126  Tensor z = tensor::DeepCopy(y);
127
128  // Set x to be different.
129  x.flat<int32>().setConstant(2);
130
131  EXPECT_EQ(TensorShape({10}), x.shape());
132  EXPECT_EQ(TensorShape({4}), y.shape());
133  EXPECT_EQ(TensorShape({4}), z.shape());
134  EXPECT_EQ(DT_INT32, x.dtype());
135  EXPECT_EQ(DT_INT32, y.dtype());
136  EXPECT_EQ(DT_INT32, z.dtype());
137
138  // x and y should now all be '2', but z should be '1'.
139  for (int i = 0; i < 10; ++i) {
140    EXPECT_EQ(2, x.flat<int32>()(i));
141  }
142  for (int i = 0; i < 4; ++i) {
143    EXPECT_EQ(2, y.unaligned_flat<int32>()(i));
144    EXPECT_EQ(1, z.flat<int32>()(i));
145  }
146}
147
148TEST(TensorUtil, Concat) {
149  std::vector<int64> sizes = {1, 4, 5};
150  std::vector<Tensor> to_concat;
151  int64 total_size = 0;
152  int offset = 0;
153  for (size_t entry = 0; entry < sizes.size(); ++entry) {
154    const int64 size = sizes[entry];
155    Tensor tensor(DT_INT32, TensorShape({size, 2}));
156    for (int i = offset; i < offset + size; ++i) {
157      for (int j = 0; j < 2; ++j) {
158        tensor.matrix<int32>()(i - offset, j) = 2 * i + j;
159      }
160    }
161    to_concat.push_back(tensor);
162    total_size += size;
163    offset += size;
164  }
165
166  Tensor concated;
167  TF_ASSERT_OK(tensor::Concat(to_concat, &concated));
168  ASSERT_EQ(TensorShape({total_size, 2}), concated.shape());
169  for (int i = 0; i < total_size; ++i) {
170    for (int j = 0; j < 2; ++j) {
171      EXPECT_EQ(2 * i + j, concated.matrix<int32>()(i, j));
172    }
173  }
174}
175
176TEST(TensorUtil, Split) {
177  Tensor to_split(DT_INT64, TensorShape({10, 2}));
178  for (int i = 0; i < 10; ++i) {
179    for (int j = 0; j < 2; ++j) {
180      to_split.matrix<int64>()(i, j) = 2 * i + j;
181    }
182  }
183
184  std::vector<int64> sizes = {1, 4, 5};
185  std::vector<Tensor> splits;
186  TF_ASSERT_OK(tensor::Split(to_split, sizes, &splits));
187  ASSERT_EQ(sizes.size(), splits.size());
188
189  int offset = 0;
190  for (size_t entry = 0; entry < splits.size(); ++entry) {
191    const int64 size = sizes[entry];
192    const Tensor& split = splits[entry];
193
194    ASSERT_EQ(TensorShape({size, 2}), split.shape());
195    for (int i = offset; i < offset + size; ++i) {
196      for (int j = 0; j < 2; ++j) {
197        EXPECT_EQ(2 * i + j, split.matrix<int64>()(i - offset, j));
198      }
199    }
200
201    offset += size;
202  }
203}
204
205TEST(TensorUtil, ConcatSplitStrings) {
206  Tensor x(DT_STRING, TensorShape({4, 3}));
207  for (int i = 0; i < 4 * 3; ++i) {
208    x.flat<string>()(i) = strings::StrCat("foo_", i);
209  }
210
211  std::vector<Tensor> split;
212  TF_ASSERT_OK(tensor::Split(x, {2, 1, 1}, &split));
213  Tensor x_round_tripped;
214  TF_ASSERT_OK(tensor::Concat(split, &x_round_tripped));
215  ASSERT_EQ(x.shape(), x_round_tripped.shape());
216  for (int i = 0; i < 4 * 3; ++i) {
217    EXPECT_EQ(x.flat<string>()(i), x_round_tripped.flat<string>()(i));
218  }
219
220  // Ensure that no memory is being shared between 'x' and 'x_round_tripped'.
221  for (int i = 0; i < 4 * 3; ++i) {
222    x_round_tripped.flat<string>()(i) = strings::StrCat("bar_", i);
223  }
224  for (int i = 0; i < 4 * 3; ++i) {
225    EXPECT_NE(x.flat<string>()(i), x_round_tripped.flat<string>()(i));
226  }
227}
228
229}  // namespace
230}  // namespace tensorflow
231