int_tensor.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. #include <traph/tensor/int_tensor.h>
  2. namespace traph
  3. {
  4. // definition
  5. // private
  6. void Tensor<i32>::auto_strides()
  7. {
  8. idx_type dim_num = _dimensions.size();
  9. _strides.resize(dim_num);
  10. idx_type stride = 1;
  11. if(_order == layout_type::row_major)
  12. {
  13. for (idx_type i = dim_num - 1; i >= 0; --i)
  14. {
  15. _strides[i] = stride;
  16. stride *= _dimensions[i];
  17. }
  18. }
  19. else
  20. {
  21. for (idx_type i = 0; i < dim_num; ++i)
  22. {
  23. _strides[i] = stride;
  24. stride *= _dimensions[i];
  25. }
  26. }
  27. }
  28. void Tensor<i32>::reduce_impl(i32& result, idx_type dim, idx_type idx, std::function<i32(i32,i32)> f) const
  29. {
  30. idx_type dim_size = _dimensions.size();
  31. idx_type step_len = _strides[dim];
  32. idx_type step_num = _dimensions[dim];
  33. for(idx_type i = 0; i < step_num; ++i)
  34. {
  35. if(dim == dim_size - 1)
  36. result = f(result, _rep->data[idx]);
  37. else
  38. reduce_impl(result, dim + 1, idx, f);
  39. idx += step_len;
  40. }
  41. }
  42. i32 Tensor<i32>::reduce_dim_kernel(idx_type begin, idx_type step_len, idx_type step_num, std::function<i32(i32,i32)> f) const
  43. {
  44. i32 result{};
  45. for(idx_type i = 0; i < step_num; ++i)
  46. {
  47. result = f(result, _rep->data[begin]);
  48. begin += step_len;
  49. }
  50. return result;
  51. }
  52. void Tensor<i32>::reduce_dim_impl(Tensor<i32>& result, idx_type dim, idx_type reduce_dim,
  53. idx_type this_idx, idx_type result_idx,
  54. std::function<i32(i32,i32)> f) const
  55. {
  56. idx_type dim_size = _dimensions.size();
  57. if(dim == dim_size)
  58. {
  59. result._rep->data[result_idx] =
  60. reduce_dim_kernel(this_idx, _strides[reduce_dim], _dimensions[reduce_dim], f);
  61. return;
  62. }
  63. if(dim == reduce_dim)
  64. {
  65. reduce_dim_impl(result, dim + 1, reduce_dim, this_idx,result_idx, f);
  66. }
  67. else
  68. {
  69. for(idx_type i = 0; i < _dimensions[dim]; ++i)
  70. {
  71. reduce_dim_impl(result, dim + 1, reduce_dim, this_idx,result_idx, f);
  72. this_idx += _strides[dim];
  73. result_idx += result._strides[dim];
  74. }
  75. }
  76. }
  77. // public
  78. Tensor<i32>::Tensor()
  79. :_rep(new TensorStorage<i32>),
  80. _dimensions(), _offset(0), _strides(), _order(layout_type::row_major)
  81. {
  82. }
  83. Tensor<i32>::Tensor(const DimVector& dimensions)
  84. :_rep(new TensorStorage<i32>),
  85. _dimensions(dimensions), _offset(0), _strides(), _order(layout_type::row_major)
  86. {
  87. auto_strides();
  88. _rep->resize_(_dimensions.flat_size());
  89. }
  90. Tensor<i32>::Tensor(const DimVector& dimensions, layout_type order)
  91. :_rep(new TensorStorage<i32>),
  92. _dimensions(dimensions), _offset(0), _strides(), _order(order)
  93. {
  94. auto_strides();
  95. _rep->resize_(_dimensions.flat_size());
  96. }
  97. Tensor<i32>::Tensor(const DimVector& dimensions, const DimVector& strides)
  98. :_rep(new TensorStorage<i32>),
  99. _dimensions(dimensions), _offset(0), _strides(strides), _order(layout_type::row_major)
  100. {
  101. auto_strides();
  102. _rep->resize_(_dimensions.flat_size());
  103. }
  104. Tensor<i32>::Tensor(const DimVector& dimensions, const DimVector& strides, layout_type order)
  105. :_rep(new TensorStorage<i32>),
  106. _dimensions(dimensions), _offset(0), _strides(strides), _order(order)
  107. {
  108. auto_strides();
  109. _rep->resize_(_dimensions.flat_size());
  110. }
  111. Tensor<i32>::Tensor(const i32& t)
  112. :_rep(new TensorStorage<i32>),
  113. _dimensions(), _offset(0), _strides()
  114. {
  115. _dimensions.resize(1);
  116. auto_strides();
  117. }
  118. void Tensor<i32>::add_(TensorInterfacePtr other)
  119. {
  120. // check tensor other type
  121. if(other->dtype() != DataType::INT)
  122. throw std::runtime_error("expected type int tensor");
  123. // check broadcast.shape = this.shape
  124. auto shape = broadcast_shape(this->size(), other->size());
  125. if(shape != this->size())
  126. throw std::runtime_error("The size of tensor a must match the size of tensor b");
  127. // ok, get lhs, rhs
  128. Tensor<i32> * lhs = this;
  129. Tensor<i32> * rhs = dynamic_cast<Tensor<i32> *>(other.get());
  130. std::function<void(Tensor<i32> *, Tensor<i32> *, idx_type, idx_type,idx_type, idx_type)> add_impl =
  131. [&](Tensor<i32> * lhs, Tensor<i32> * rhs, idx_type lhs_dim, idx_type rhs_dim, idx_type lhs_idx, idx_type rhs_idx) {
  132. auto lhs_storage = std::dynamic_pointer_cast<TensorStorage<i32>>(lhs->storage())->data_ptr();
  133. auto rhs_storage = std::dynamic_pointer_cast<TensorStorage<i32>>(rhs->storage())->data_ptr();
  134. if (lhs_dim < -(lhs->size().size()) && rhs_dim < -(rhs->size().size()))
  135. {
  136. lhs_storage[lhs_idx] += rhs_storage[rhs_idx];
  137. return;
  138. }
  139. idx_type lsh_shape_size = lhs_dim >= -(lhs->size().size())? lhs->size(lhs_dim) : 1;
  140. idx_type rsh_shape_size = rhs_dim >= -(rhs->size().size()) ? rhs->size(rhs_dim) : 1;
  141. idx_type max_shape_size = std::max(lsh_shape_size, rsh_shape_size);
  142. for (idx_type i = 0; i < max_shape_size; ++i)
  143. {
  144. add_impl(lhs, rhs, lhs_dim - 1, rhs_dim - 1, lhs_idx, rhs_idx);
  145. if(lsh_shape_size > 1)
  146. lhs_idx += lhs->stride(lhs_dim);
  147. if (rsh_shape_size > 1)
  148. rhs_idx += rhs->stride(rhs_dim);
  149. }
  150. };
  151. add_impl(lhs, rhs, -1, -1, lhs->offset(), rhs->offset());
  152. }
  153. void Tensor<i32>::apply_(std::function<i32(i32)> f)
  154. {
  155. // sort stride for cache optimization
  156. DimVector cloned_stride(_strides);
  157. DimVector sorted_stride(_strides.size());
  158. for(int i = 0; i<_strides.size(); ++i)
  159. sorted_stride[i] = i;
  160. for (int i = 0; i < cloned_stride.size() - 1; i++)
  161. for (int j = 0; j < cloned_stride.size() - 1 - i; j++)
  162. if (cloned_stride[j] < cloned_stride[j + 1])
  163. {
  164. std::swap(cloned_stride[j], cloned_stride[j+1]);
  165. std::swap(sorted_stride[j], sorted_stride[j+1]);
  166. }
  167. std::function<void(idx_type, idx_type, std::function<i32(i32)>)> apply_impl =
  168. [&](idx_type dim_idx, idx_type idx, std::function<i32(i32)> f){
  169. idx_type dim = sorted_stride[dim_idx];
  170. idx_type dim_size = _dimensions.size();
  171. idx_type step_len = _strides[dim];
  172. idx_type step_num = _dimensions[dim];
  173. for(idx_type i = 0; i < step_num; ++i)
  174. {
  175. if(dim_idx == dim_size - 1)
  176. _rep->data[idx] = f(_rep->data[idx]);
  177. else
  178. apply_impl(dim_idx + 1, idx, f);
  179. idx += step_len;
  180. }
  181. };
  182. if(_dimensions.size() > 0)
  183. apply_impl(0, _offset, f);
  184. }
  185. TensorInterfacePtr Tensor<i32>::clone() const
  186. {
  187. std::shared_ptr<Tensor<i32>> cloned_tensor(new Tensor<i32>);
  188. cloned_tensor->_rep = std::dynamic_pointer_cast<TensorStorage<i32>>(_rep->clone());
  189. cloned_tensor->_dimensions = _dimensions;
  190. cloned_tensor->_offset = _offset;
  191. cloned_tensor->_strides = _strides;
  192. cloned_tensor->_order = _order;
  193. return cloned_tensor;
  194. }
  195. void Tensor<i32>::cos_()
  196. {
  197. throw std::runtime_error("No implement");
  198. }
  199. std::shared_ptr<TensorBase<f32>> Tensor<i32>::create_grad()
  200. {
  201. return std::shared_ptr<TensorBase<f32>>(new Tensor<f32>(_dimensions));
  202. }
  203. i32* Tensor<i32>::data_ptr()
  204. {
  205. return _rep->data_ptr();
  206. }
  207. const i32* Tensor<i32>::data_ptr() const
  208. {
  209. return _rep->data_ptr();
  210. }
  211. device_id Tensor<i32>::device() { return 0; }
  212. DataType Tensor<i32>::dtype() const
  213. {
  214. return DataType::INT;
  215. }
  216. bool Tensor<i32>::equal(std::shared_ptr<TensorInterface> other) const
  217. {
  218. if(other->platform() != this->platform())
  219. throw std::runtime_error("equal: Two tensors must be the same platform");
  220. if(other->dtype() != this->dtype())
  221. return false;
  222. if(other->size() != this->size())
  223. return false;
  224. std::shared_ptr<Tensor<i32>> other_ptr = std::dynamic_pointer_cast<Tensor<i32>>(other);
  225. std::function<bool(idx_type, i32*, i32*)> equal_impl =
  226. [&](idx_type dim, i32* lhs_idx, i32* rhs_idx){
  227. idx_type dim_size = _dimensions.size();
  228. for(idx_type i = 0; i < _dimensions[dim]; ++i)
  229. {
  230. if(dim == dim - 1)
  231. {
  232. if(*lhs_idx != *rhs_idx) return false;
  233. }
  234. else
  235. {
  236. if(!equal_impl(dim + 1, lhs_idx, rhs_idx)) return false;
  237. }
  238. lhs_idx += _strides[dim];
  239. rhs_idx += other_ptr->stride(dim);
  240. }
  241. return true;
  242. };
  243. return equal_impl(0, _rep->data_ptr() + _offset, other_ptr->data_ptr() + other_ptr->offset());
  244. }
  245. std::shared_ptr<TensorInterface> Tensor<i32>::inverse() const
  246. {
  247. throw std::runtime_error("No implement");
  248. }
  249. void Tensor<i32>::fill_(i32 value)
  250. {
  251. apply_([&value](i32 a)->i32 {return value; });
  252. }
  253. i32 Tensor<i32>::item() const
  254. {
  255. if(_dimensions.flat_size() == 1)
  256. {
  257. return _rep->data[_offset];
  258. }
  259. else
  260. {
  261. throw std::runtime_error("item: only one element tensors can be converted to scalars");
  262. }
  263. }
  264. std::shared_ptr<TensorInterface> Tensor<i32>::matmul(std::shared_ptr<TensorInterface> mat) const
  265. {
  266. auto right_matrix = std::dynamic_pointer_cast<Tensor<i32>>(mat);
  267. return matmul_impl(*this, *right_matrix);
  268. }
  269. TensorInterfacePtr Tensor<i32>::mean() const
  270. {
  271. DimVector d(1);
  272. d[0] = 1;
  273. TensorPtr<i32> result(new Tensor<i32>(d));
  274. auto flat_size = _dimensions.flat_size();
  275. result->_rep->data[0] = reduce([](i32 a, i32 b)->i32 {return a + b; });
  276. result->_rep->data[0] /= flat_size;
  277. return std::dynamic_pointer_cast<TensorInterface>(result);
  278. }
  279. void Tensor<i32>::mul_(i32 value)
  280. {
  281. apply_([value](i32 a)->i32 {return a*value; });
  282. }
  283. void Tensor<i32>::mul_(std::shared_ptr<TensorInterface> other)
  284. {
  285. // check tensor other type
  286. if(other->dtype() != DataType::INT)
  287. throw std::runtime_error("expected type int tensor");
  288. // check broadcast.shape = this.shape
  289. auto shape = broadcast_shape(this->size(), other->size());
  290. if(shape != this->size())
  291. throw std::runtime_error("The size of tensor a must match the size of tensor b");
  292. // ok, get lhs, rhs
  293. Tensor<i32> * lhs = this;
  294. Tensor<i32> * rhs = dynamic_cast<Tensor<i32> *>(other.get());
  295. std::function<void(idx_type, idx_type, idx_type, idx_type)> mul_impl =
  296. [&](idx_type lhs_dim, idx_type rhs_dim, idx_type lhs_idx, idx_type rhs_idx) {
  297. auto lhs_storage = std::dynamic_pointer_cast<TensorStorage<f32>>(lhs->storage())->data_ptr();
  298. auto rhs_storage = std::dynamic_pointer_cast<TensorStorage<f32>>(rhs->storage())->data_ptr();
  299. idx_type lsh_shape_size = lhs_dim >= -(lhs->size().size())? lhs->size(lhs_dim) : 1;
  300. idx_type rsh_shape_size = rhs_dim >= -(rhs->size().size()) ? rhs->size(rhs_dim) : 1;
  301. idx_type max_shape_size = std::max(lsh_shape_size, rsh_shape_size);
  302. for (idx_type i = 0; i < max_shape_size; ++i)
  303. {
  304. if (lhs_dim <= -(lhs->size().size()) && rhs_dim <= -(rhs->size().size()))
  305. {
  306. lhs_storage[lhs_idx] *= rhs_storage[rhs_idx];
  307. }
  308. else
  309. {
  310. mul_impl(lhs_dim - 1, rhs_dim - 1, lhs_idx, rhs_idx);
  311. }
  312. if(lsh_shape_size > 1)
  313. lhs_idx += lhs->stride(lhs_dim);
  314. if (rsh_shape_size > 1)
  315. rhs_idx += rhs->stride(rhs_dim);
  316. }
  317. };
  318. mul_impl(-1, -1, lhs->offset(), rhs->offset());
  319. }
  320. idx_type Tensor<i32>::ndimension() const
  321. {
  322. return _dimensions.size();
  323. }
  324. void Tensor<i32>::neg_()
  325. {
  326. apply_([](i32 a)->i32 {return -a; });
  327. }
  328. idx_type Tensor<i32>::offset() const { return _offset; }
  329. layout_type Tensor<i32>::order() const { return _order; }
  330. std::shared_ptr<TensorInterface> Tensor<i32>::permute(const DimVector& dims) const
  331. {
  332. // check dims
  333. if(dims.size() != _strides.size())
  334. throw std::runtime_error("permute dimension must have the same size");
  335. std::vector<int> check_vec(dims.size(), 0);
  336. for(int i = 0; i < dims.size();++i)
  337. if(dims[i] >= 0 && dims[i] < dims.size())
  338. check_vec[dims[i]] = 1;
  339. else
  340. throw std::runtime_error("permute dimension must in ndimension range");
  341. for(int i = 0; i < check_vec.size();++i)
  342. {
  343. if(check_vec[i] != 1)
  344. throw std::runtime_error("permute dimension error");
  345. }
  346. // permute
  347. std::shared_ptr<Tensor<i32>> result(new Tensor<i32>);
  348. result->_rep = _rep;
  349. result->_dimensions = _dimensions;
  350. result->_offset = _offset;
  351. result->_strides = _strides;
  352. result->_order = _order;
  353. for(int i=0; i<dims.size(); ++i)
  354. {
  355. result->_dimensions[i] = _dimensions[dims[i]];
  356. result->_strides[i] = _strides[dims[i]];
  357. }
  358. return result;
  359. }
  360. PlatformType Tensor<i32>::platform() const { return PlatformType::CPU; }
  361. void Tensor<i32>::pow_(f32 exp)
  362. {
  363. std::int32_t exp_int = static_cast<std::int32_t>(exp);
  364. apply_([&exp_int](i32 a)->i32 {return static_cast<i32>(std::pow(a, exp_int)); });
  365. }
  366. i32 Tensor<i32>::reduce(std::function<i32(i32, i32)> f) const
  367. {
  368. i32 result{};
  369. reduce_impl(result, 0, _offset, f);
  370. return result;
  371. }
  372. TensorInterfacePtr Tensor<i32>::reduce_dim(idx_type dim, std::function<i32(i32, i32)> f) const
  373. {
  374. DimVector reduced_dim = _dimensions;
  375. reduced_dim.erase(dim); // check dim?
  376. TensorBasePtr<i32> result(new Tensor<i32>(reduced_dim));
  377. TensorPtr<i32> raw_result = std::dynamic_pointer_cast<Tensor<i32>>(result);
  378. reduce_dim_impl(*(raw_result.get()), 0, dim, _offset, raw_result->_offset, f);
  379. return std::dynamic_pointer_cast<TensorInterface>(result);
  380. }
  381. void Tensor<i32>::reshape_(const DimVector& dims)
  382. {
  383. }
  384. void Tensor<i32>::resize_(const DimVector& dims)
  385. {
  386. _dimensions = dims;
  387. _rep->resize_(dims.flat_size());
  388. auto_strides();
  389. }
  390. std::shared_ptr<TensorInterface> Tensor<i32>::select(const SliceVector& slice) const
  391. {
  392. std::shared_ptr<Tensor<i32>> result(new Tensor<i32>);
  393. result->_rep = _rep;
  394. // dimension
  395. DimVector dim;
  396. std::fesetround(FE_TONEAREST);
  397. for (idx_type i = 0; i < slice.size(); ++i)
  398. {
  399. auto& each = slice[i];
  400. dim.push_back(
  401. std::lrint(std::ceil((each.end.value_or(_dimensions[i]) - each.start.value_or(0)) / (float)each.step.value_or(1)))
  402. );
  403. }
  404. result->_dimensions = dim;
  405. // offset
  406. idx_type new_offset = 1;
  407. for (idx_type i = 0; i < slice.size(); ++i)
  408. {
  409. new_offset *= _strides[i] * slice[i].start.value_or(0);
  410. }
  411. result->_offset = _offset + new_offset;
  412. // strides
  413. DimVector strides;
  414. for (idx_type i = 0; i < slice.size(); ++i)
  415. {
  416. strides.push_back(_strides[i] * slice[i].step.value_or(1));
  417. }
  418. result->_strides = strides;
  419. result->_order = _order;
  420. return std::dynamic_pointer_cast<TensorInterface>(result);
  421. }
  422. void Tensor<i32>::sin_()
  423. {
  424. throw std::runtime_error("No implement");
  425. }
  426. DimVector Tensor<i32>::size() const { return _dimensions;}
  427. idx_type Tensor<i32>::size(idx_type i) const
  428. {
  429. auto shape_size = _dimensions.size();
  430. if (i >= 0 && i < _dimensions.size())
  431. return _dimensions[i];
  432. else if (i <= -1 && i >= -_dimensions.size())
  433. return _dimensions[shape_size + i];
  434. else
  435. throw std::runtime_error("Dimension out of range");
  436. }
  437. std::shared_ptr<StorageBase<i32>> Tensor<i32>::storage() const { return _rep; }
  438. DimVector Tensor<i32>::stride() const { return _strides; }
  439. idx_type Tensor<i32>::stride(idx_type i) const
  440. {
  441. auto stride_size = _strides.size();
  442. if (i >= 0 && i < _strides.size())
  443. return _strides[i];
  444. else if (i <= -1 && i >= -_strides.size())
  445. return _strides[stride_size + i];
  446. else
  447. throw std::runtime_error("Stride out of range");
  448. }
  449. void Tensor<i32>::sub_(std::shared_ptr<TensorInterface> other)
  450. {
  451. Tensor<i32> * lhs = this;
  452. Tensor<i32> * rhs = dynamic_cast<Tensor<i32> *>(other.get());
  453. std::function<void(Tensor<i32> *, Tensor<i32> *, idx_type, idx_type,idx_type, idx_type)> sub_impl =
  454. [&](Tensor<i32> * lhs, Tensor<i32> * rhs, idx_type lhs_dim, idx_type rhs_dim, idx_type lhs_idx, idx_type rhs_idx) {
  455. auto lhs_storage = std::dynamic_pointer_cast<TensorStorage<i32>>(lhs->storage())->data_ptr();
  456. auto rhs_storage = std::dynamic_pointer_cast<TensorStorage<i32>>(rhs->storage())->data_ptr();
  457. if (lhs_dim < -(lhs->size().size()) && rhs_dim < -(rhs->size().size()))
  458. {
  459. lhs_storage[lhs_idx] -= rhs_storage[rhs_idx];
  460. return;
  461. }
  462. idx_type lhs_shape_size = lhs_dim >= -(lhs->size().size())? lhs->size(lhs_dim) : 1;
  463. idx_type rhs_shape_size = rhs_dim >= -(rhs->size().size()) ? rhs->size(rhs_dim) : 1;
  464. idx_type max_shape_size = std::max(lhs_shape_size, rhs_shape_size);
  465. for (idx_type i = 0; i < max_shape_size; ++i)
  466. {
  467. sub_impl(lhs, rhs, lhs_dim - 1, rhs_dim - 1, lhs_idx, rhs_idx);
  468. if(lhs_shape_size > 1)
  469. lhs_idx += lhs->stride(lhs_dim);
  470. if (rhs_shape_size > 1)
  471. rhs_idx += rhs->stride(rhs_dim);
  472. }
  473. };
  474. sub_impl(lhs, rhs, -1, -1, lhs->offset(), rhs->offset());
  475. }
  476. TensorInterfacePtr Tensor<i32>::sum() const
  477. {
  478. DimVector d(1);
  479. d[0] = 1;
  480. TensorPtr<i32> result(new Tensor<i32>(d));
  481. result->_rep->data[0] = reduce([](i32 a, i32 b)->i32 {return a + b; });
  482. return std::dynamic_pointer_cast<TensorInterface>(result);
  483. }
  484. std::string Tensor<i32>::to_string() const
  485. {
  486. std::function<std::string(const Tensor<i32>&, idx_type, idx_type)> to_string_impl =
  487. [&](const Tensor<i32>& t, idx_type dim, idx_type idx)->std::string {
  488. std::string result;
  489. if (dim == t.size().size())
  490. {
  491. result += std::to_string(t.data_ptr()[idx]);
  492. return result;
  493. }
  494. for (idx_type i = 0; i < t.size(dim); ++i)
  495. {
  496. if (dim != t.size().size() - 1 && i != 0) result += ",\n";
  497. if(dim != t.size().size() - 1) result += "[";
  498. result += to_string_impl(t, dim + 1, idx);
  499. if (i != t.size(dim) - 1 && dim == t.size().size() - 1)
  500. result += ",";
  501. if (dim != t.size().size() - 1) result += "]";
  502. idx += t.stride(dim);
  503. }
  504. return result;
  505. };
  506. std::string result;
  507. result += "[" + to_string_impl(*this, 0, offset()) + "]";
  508. return result;
  509. }
  510. void Tensor<i32>::transpose_(idx_type dim0, idx_type dim1)
  511. {
  512. if(dim0 != dim1 &&
  513. _dimensions.in_range(dim0) &&
  514. _dimensions.in_range(dim1))
  515. {
  516. std::swap(_dimensions[dim0], _dimensions[dim1]);
  517. std::swap(_strides[dim0], _strides[dim1]);
  518. }
  519. }
  520. std::shared_ptr<TensorInterface> Tensor<i32>::transpose(idx_type dim0, idx_type dim1)
  521. {
  522. std::shared_ptr<Tensor<i32>> result(new Tensor<i32>);
  523. result->_rep = _rep;
  524. result->_dimensions = _dimensions;
  525. result->_offset = _offset;
  526. result->_strides = _strides;
  527. result->_order = _order;
  528. result->transpose_(dim0, dim1);
  529. return result;
  530. }
  531. }