Cytnx v1.0.0
Loading...
Searching...
No Matches
UniTensor.hpp
Go to the documentation of this file.
1#ifndef CYTNX_UNITENSOR_H_
2#define CYTNX_UNITENSOR_H_
3
4#include "Type.hpp"
5#include "cytnx_error.hpp"
6#include "Device.hpp"
7#include "Tensor.hpp"
8#include "utils/utils.hpp"
10#include <iostream>
11#include <vector>
12#include <map>
13#include <utility>
14#include <initializer_list>
15#include <fstream>
16#include <algorithm>
17#include "Symmetry.hpp"
18#include "Bond.hpp"
19#include "Generator.hpp"
20#include <random>
21
22#include "backend/Scalar.hpp"
23
24// namespace cytnx{
25namespace cytnx {
26 namespace random {
27 extern std::random_device __static_random_device;
28 }
29
31 class UniTensorType_class {
32 public:
33 enum : int { Void = -99, Dense = 0, Sparse = 1, Block = 2, BlockFermionic = 3 };
34 std::string getname(const int &ut_type) const;
35 };
37
54 extern UniTensorType_class UTenType;
55
57 // class DenseUniTensor;
58 class UniTensor_base : public intrusive_ptr_base<UniTensor_base> {
59 public:
60 int uten_type_id; // the unitensor type id.
61 bool _is_braket_form;
62 bool _is_tag;
63 bool _is_diag;
64 cytnx_int64 _rowrank;
65 std::string _name;
66 std::vector<std::string> _labels;
67 std::vector<Bond> _bonds;
68 std::vector<Symmetry> syms_cache;
69
70 bool _update_braket() {
71 if (_bonds.size() == 0) return false;
72
73 if (this->_bonds[0].type() != bondType::BD_REG) {
74 // check:
75 for (unsigned int i = 0; i < this->_bonds.size(); i++) {
76 if (i < this->_rowrank) {
77 if (this->_bonds[i].type() != bondType::BD_KET) return false;
78 } else {
79 if (this->_bonds[i].type() != bondType::BD_BRA) return false;
80 }
81 }
82 return true;
83 } else {
84 return false;
85 }
86 }
87
88 friend class UniTensor; // allow wrapper to access the private elems
89 friend class DenseUniTensor;
90 friend class BlockUniTensor;
91 friend class BlockFermionicUniTensor;
92
93 UniTensor_base()
94 : _is_tag(false),
95 _name(std::string("")),
96 _is_braket_form(false),
97 _rowrank(0),
98 _is_diag(false),
99 uten_type_id(UTenType.Void){};
100
101 // copy&assignment constr., use intrusive_ptr's !!
102 UniTensor_base(const UniTensor_base &rhs);
103 UniTensor_base &operator=(UniTensor_base &rhs);
104
105 cytnx_uint64 rowrank() const { return this->_rowrank; }
106 bool is_diag() const { return this->_is_diag; }
107 const bool &is_braket_form() const { return this->_is_braket_form; }
108 const bool &is_tag() const { return this->_is_tag; }
109 const std::vector<std::string> &labels() const { return this->_labels; }
116 cytnx_int64 get_index(std::string label) const {
117 std::vector<std::string> labels = this->_labels;
118 for (cytnx_uint64 i = 0; i < labels.size(); i++) {
119 if (labels[i] == label) return i;
120 }
121 return -1;
122 }
123 const std::vector<Bond> &bonds() const { return this->_bonds; }
124
125 Bond &bond_(const cytnx_uint64 &idx) {
126 cytnx_error_msg(idx >= this->rank(), "[ERROR][bond] index %d out of bound, total %d\n", idx,
127 this->rank());
128 return this->_bonds[idx];
129 }
130
131 Bond &bond_(const std::string &label) {
132 auto res = std::find(this->_labels.begin(), this->_labels.end(), label);
133 cytnx_error_msg(res == this->_labels.end(), "[ERROR] label %s not exists.\n", label.c_str());
134 cytnx_uint64 idx = std::distance(this->_labels.begin(), res);
135
136 return this->bond_(idx);
137 }
138
139 const std::string &name() const { return this->_name; }
140 cytnx_uint64 rank() const {
141 cytnx_error_msg(this->_labels.size() != this->_bonds.size(),
142 "[ERROR][UniTensor_base][rank] inconsistent metadata: labels.size()=%zu, "
143 "bonds.size()=%zu.%s",
144 this->_labels.size(), this->_bonds.size(), "\n");
145 return this->_labels.size();
146 }
147 void set_name_(const std::string &in) { this->_name = in; }
148 [[deprecated("Please use set_name_(const std::string &in) instead.")]] void set_name(
149 const std::string &in) {
150 this->set_name_(in);
151 }
152
164 void set_label_(const std::string &oldlabel, const std::string &new_label) {
165 cytnx_int64 idx;
166 auto res = std::find(this->_labels.begin(), this->_labels.end(), oldlabel);
167 cytnx_error_msg(res == this->_labels.end(), "[ERROR] label %s not exists.\n",
168 oldlabel.c_str());
169 idx = std::distance(this->_labels.begin(), res);
170
171 cytnx_error_msg(idx >= this->_labels.size(), "[ERROR] index exceed the rank of UniTensor%s",
172 "\n");
173 // check in:
174 bool is_dup = false;
175 for (cytnx_uint64 i = 0; i < this->_labels.size(); i++) {
176 if (i == idx) continue;
177 if (new_label == this->_labels[i]) {
178 is_dup = true;
179 break;
180 }
181 }
182 cytnx_error_msg(is_dup, "[ERROR] alreay has a label that is the same as the input label%s",
183 "\n");
184 this->_labels[idx] = new_label;
185 }
186 void set_label_(const cytnx_int64 &inx, const std::string &new_label) {
187 cytnx_error_msg(inx < 0, "[ERROR] index is negative%s", "\n");
188 cytnx_error_msg(inx >= this->_labels.size(), "[ERROR] index exceed the rank of UniTensor%s",
189 "\n");
190 // check in:
191 bool is_dup = false;
192 for (cytnx_uint64 i = 0; i < this->_labels.size(); i++) {
193 if (i == inx) continue;
194 if (new_label == this->_labels[i]) {
195 is_dup = true;
196 break;
197 }
198 }
199 cytnx_error_msg(is_dup, "[ERROR] alreay has a label that is the same as the input label%s",
200 "\n");
201 this->_labels[inx] = new_label;
202 }
203 [[deprecated(
204 "Please use set_label_(const std::string &oldlabel, const std::string "
205 "&new_label) instead.")]] void
206 set_label(const std::string &oldlabel, const std::string &new_label) {
207 this->set_label_(oldlabel, new_label);
208 }
209 [[deprecated(
210 "Please use set_label_(const cytnx_int64 &inx, const std::string &new_label) "
211 "instead.")]] void
212 set_label(const cytnx_int64 &inx, const std::string &new_label) {
213 this->set_label_(inx, new_label);
214 }
215
216 [[deprecated("Please use relabel_(const std::vector<std::string> &new_labels) instead.")]] void
217 set_labels(const std::vector<std::string> &new_labels);
218 void relabel_(const std::vector<std::string> &new_labels); // implemented
219 [[deprecated("Please use relabel_(const std::vector<std::string> &new_labels) instead.")]] void
220 relabels_(const std::vector<std::string> &new_labels); // implemented
221 void relabel_(const std::vector<std::string> &old_labels,
222 const std::vector<std::string> &new_labels); // implemented
223 [[deprecated(
224 "Please use relabel_(const std::vector<std::string> &old_labels, const "
225 "std::vector<std::string> &new_labels) instead.")]] void
226 relabels_(const std::vector<std::string> &old_labels,
227 const std::vector<std::string> &new_labels); // implemented
228 void relabel_(const std::string &old_label, const std::string &new_label) {
229 this->set_label_(old_label, new_label);
230 }
231 void relabel_(const cytnx_int64 &inx, const std::string &new_label) {
232 this->set_label_(inx, new_label);
233 }
234
235 int uten_type() { return this->uten_type_id; }
236 std::string uten_type_str() const { return UTenType.getname(this->uten_type_id); }
237
239
240 // string labels!
241 virtual void Init(const std::vector<Bond> &bonds,
242 const std::vector<std::string> &in_labels = {},
243 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
244 const int &device = Device.cpu, const bool &is_diag = false,
245 const bool &no_alloc = false, const std::string &name = "");
246
247 virtual void Init_by_Tensor(const Tensor &in, const bool &is_diag = false,
248 const cytnx_int64 &rowrank = -1, const std::string &name = "");
249 virtual std::vector<cytnx_uint64> shape() const;
250 virtual std::vector<bool> signflip() const;
251 virtual bool is_blockform() const;
252 virtual bool is_contiguous() const;
253 virtual void to_(const int &device);
254 virtual boost::intrusive_ptr<UniTensor_base> to(const int &device);
255 virtual boost::intrusive_ptr<UniTensor_base> clone() const;
256 virtual unsigned int dtype() const;
257 virtual int device() const;
258 virtual std::string dtype_str() const;
259 virtual std::string device_str() const;
260 virtual void set_rowrank_(const cytnx_uint64 &new_rowrank);
261 virtual boost::intrusive_ptr<UniTensor_base> set_rowrank(const cytnx_uint64 &new_rowrank) const;
262
263 virtual boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,
264 const cytnx_int64 &rowrank = -1);
265 virtual boost::intrusive_ptr<UniTensor_base> permute(const std::vector<std::string> &mapper,
266 const cytnx_int64 &rowrank = -1);
267 // virtual boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,
268 // const cytnx_int64 &rowrank = -1);
269
270 virtual void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1);
271 virtual void permute_(const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1);
272
273 virtual boost::intrusive_ptr<UniTensor_base> permute_nosignflip(
274 const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1);
275 virtual boost::intrusive_ptr<UniTensor_base> permute_nosignflip(
276 const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1);
277 virtual void permute_nosignflip_(const std::vector<cytnx_int64> &mapper,
278 const cytnx_int64 &rowrank = -1);
279 virtual void permute_nosignflip_(const std::vector<std::string> &mapper,
280 const cytnx_int64 &rowrank = -1);
281 // virtual void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank =
282 // -1);
283
284 virtual void twist_(const cytnx_int64 &idx);
285 virtual void twist_(const std::string &label);
286 virtual void fermion_twists_();
287
288 virtual boost::intrusive_ptr<UniTensor_base> contiguous_();
289 virtual boost::intrusive_ptr<UniTensor_base> contiguous();
290 virtual boost::intrusive_ptr<UniTensor_base> apply_();
291 virtual boost::intrusive_ptr<UniTensor_base> apply();
292 virtual void print_diagram(const bool &bond_info = false) const;
293 virtual void print_blocks(const bool &full_info = true) const;
294 virtual void print_block(const cytnx_int64 &idx, const bool &full_info = true) const;
295
296 virtual boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const;
297
298 virtual cytnx_uint64 Nblocks() const { return 0; };
299 virtual Tensor get_block(const cytnx_uint64 &idx = 0) const; // return a copy of block
300 // qidx holds one sector index per bond (a position in the bond's qnum list, not a
301 // quantum-number charge); the block whose sectors match qidx is selected.
302 virtual Tensor get_block(const std::vector<cytnx_int64> &qidx,
303 const bool &force) const; // return a copy of block
304
305 virtual const Tensor &get_block_(const cytnx_uint64 &idx = 0)
306 const; // return a share view of block, this only work for non-symm tensor.
307 virtual const Tensor &get_block_(const std::vector<cytnx_int64> &qidx,
308 const bool &force) const; // return a copy of block
309 virtual Tensor &get_block_(const cytnx_uint64 &idx = 0); // return a share view of block, this
310 // only work for non-symm tensor.
311 virtual Tensor &get_block_(const std::vector<cytnx_int64> &qidx,
312 const bool &force); // return a copy of block
313 virtual bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const;
314
315 virtual std::vector<Tensor> get_blocks() const;
316 virtual const std::vector<Tensor> &get_blocks_(const bool &) const;
317 virtual std::vector<Tensor> &get_blocks_(const bool &);
318
319 virtual void put_block(const Tensor &in, const cytnx_uint64 &idx = 0);
320 virtual void put_block_(Tensor &in, const cytnx_uint64 &idx = 0);
321 virtual void put_block(const Tensor &in, const std::vector<cytnx_int64> &qidx);
322 virtual void put_block_(Tensor &in, const std::vector<cytnx_int64> &qidx);
323
324 // this will only work on non-symm tensor (DenseUniTensor)
325 virtual boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors);
326
327 // this will only work on non-symm tensor (DenseUniTensor)
328 virtual void set(const std::vector<Accessor> &accessors, const Tensor &rhs);
329
330 virtual void reshape_(const std::vector<cytnx_int64> &new_shape,
331 const cytnx_uint64 &rowrank = 0);
332 virtual boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape,
333 const cytnx_uint64 &rowrank = 0);
334 virtual boost::intrusive_ptr<UniTensor_base> to_dense();
335 virtual void to_dense_();
336 virtual void combineBond(const std::vector<std::string> &indicators, const bool &force = false);
337 virtual void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force,
338 const bool &by_label);
339 virtual void combineBonds(const std::vector<std::string> &indicators,
340 const bool &force = false);
341 virtual void combineBonds(const std::vector<cytnx_int64> &indicators,
342 const bool &force = false);
343 virtual boost::intrusive_ptr<UniTensor_base> contract(
344 const boost::intrusive_ptr<UniTensor_base> &rhs, const bool &mv_elem_self = false,
345 const bool &mv_elem_rhs = false);
346 virtual std::vector<Bond> getTotalQnums(const bool &physical = false);
347 virtual std::vector<std::vector<cytnx_int64>> get_blocks_qnums() const;
348 virtual void Trace_(const std::string &a, const std::string &b);
349 virtual void Trace_(const cytnx_int64 &a, const cytnx_int64 &b);
350
351 virtual boost::intrusive_ptr<UniTensor_base> Trace(const std::string &a, const std::string &b);
352 virtual boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b);
353
354 virtual boost::intrusive_ptr<UniTensor_base> relabel(
355 const std::vector<std::string> &new_labels);
356 virtual boost::intrusive_ptr<UniTensor_base> relabels(
357 const std::vector<std::string> &new_labels);
358
359 virtual boost::intrusive_ptr<UniTensor_base> relabel(
360 const std::vector<std::string> &old_labels, const std::vector<std::string> &new_labels);
361 virtual boost::intrusive_ptr<UniTensor_base> relabels(
362 const std::vector<std::string> &old_labels, const std::vector<std::string> &new_labels);
363
364 virtual boost::intrusive_ptr<UniTensor_base> relabel(const std::string &old_label,
365 const std::string &new_label);
366
367 virtual boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx,
368 const std::string &new_label);
369
370 virtual std::vector<Symmetry> syms() const;
371
372 // arithmetic
373 // internal/advanced: the UniTensor-vs-UniTensor overloads below (Add_/Mul_/Sub_/Div_
374 // taking a boost::intrusive_ptr<UniTensor_base>) are not TN operations; python surface
375 // removed per #934. See operator+(const UniTensor&, const UniTensor&) in
376 // include/linalg.hpp for the full rationale. The Scalar overloads (scalar scaling)
377 // remain fully public, including from python.
378 virtual void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
379 virtual void Add_(const Scalar &rhs);
380
381 virtual void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
382 virtual void Mul_(const Scalar &rhs);
383
384 virtual void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
385 virtual void Sub_(const Scalar &rhs);
386 virtual void lSub_(const Scalar &lhs);
387
388 virtual void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
389 virtual void Div_(const Scalar &rhs);
390 virtual void lDiv_(const Scalar &lhs);
391
392 virtual Tensor Norm() const;
393 virtual boost::intrusive_ptr<UniTensor_base> normalize();
394 virtual void normalize_();
395
396 virtual boost::intrusive_ptr<UniTensor_base> Conj();
397 virtual void Conj_();
398
399 virtual boost::intrusive_ptr<UniTensor_base> Transpose();
400 virtual void Transpose_();
401
402 virtual boost::intrusive_ptr<UniTensor_base> Dagger();
403 virtual void Dagger_();
404
405 virtual void tag_();
406
407 virtual void truncate_(const std::string &label, const cytnx_uint64 &dim);
408 virtual void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim);
409
410 virtual bool elem_exists(const std::vector<cytnx_uint64> &locator) const;
411
412 // this a workaround, as virtual function cannot template.
413 virtual Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator);
414 virtual const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const;
415
416 virtual cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
417 const cytnx_complex128 &aux);
418 virtual cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
419 const cytnx_complex64 &aux);
420 virtual cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator,
421 const cytnx_double &aux);
422 virtual cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator,
423 const cytnx_float &aux);
424 virtual cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
425 const cytnx_uint64 &aux);
426 virtual cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
427 const cytnx_int64 &aux);
428 virtual cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
429 const cytnx_uint32 &aux);
430 virtual cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
431 const cytnx_int32 &aux);
432 virtual cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
433 const cytnx_uint16 &aux);
434 virtual cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
435 const cytnx_int16 &aux);
436
437 virtual const cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
438 const cytnx_complex128 &aux) const;
439 virtual const cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
440 const cytnx_complex64 &aux) const;
441 virtual const cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator,
442 const cytnx_double &aux) const;
443 virtual const cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator,
444 const cytnx_float &aux) const;
445 virtual const cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
446 const cytnx_uint64 &aux) const;
447 virtual const cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
448 const cytnx_int64 &aux) const;
449 virtual const cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
450 const cytnx_uint32 &aux) const;
451 virtual const cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
452 const cytnx_int32 &aux) const;
453 virtual const cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
454 const cytnx_uint16 &aux) const;
455 virtual const cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
456 const cytnx_int16 &aux) const;
457
458 virtual void from_(const boost::intrusive_ptr<UniTensor_base> &rhs, bool force,
459 cytnx_double tol = 0.);
460
461 virtual void group_basis_();
462 virtual const std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) const;
463 virtual std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx);
464 virtual const vec2d<cytnx_uint64> &get_itoi() const;
465 virtual vec2d<cytnx_uint64> &get_itoi();
466
467 virtual void _save_dispatch(std::fstream &f) const;
468 virtual void _load_dispatch(std::fstream &f, unsigned int version);
469
470 virtual ~UniTensor_base(){};
471 };
473
474 //======================================================================
476 class DenseUniTensor : public UniTensor_base {
477 protected:
478 public:
479 Tensor _block;
480 std::vector<Tensor> _interface_block; // this is serves as interface for get_blocks_();
481 boost::intrusive_ptr<DenseUniTensor> clone_meta() const {
482 boost::intrusive_ptr<DenseUniTensor> tmp(new DenseUniTensor());
483 tmp->_bonds = vec_clone(this->_bonds);
484 tmp->_labels = this->_labels;
485 tmp->syms_cache = vec_clone(this->syms_cache);
486 tmp->_is_braket_form = this->_is_braket_form;
487 tmp->_rowrank = this->_rowrank;
488 tmp->_is_diag = this->_is_diag;
489 tmp->_name = this->_name;
490 tmp->_is_tag = this->_is_tag;
491 return tmp;
492 }
493 //------------------------------------------
494
495 DenseUniTensor() { this->uten_type_id = UTenType.Dense; };
496 friend class UniTensor; // allow wrapper to access the private elems
497 // virtual functions
498
499 // void Init(const std::vector<Bond> &bonds, const std::vector<cytnx_int64> &in_labels = {},
500 // const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
501 // const int &device = Device.cpu, const bool &is_diag = false,
502 // const bool &no_alloc = false);
503
504 void Init(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
505 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
506 const int &device = Device.cpu, const bool &is_diag = false,
507 const bool &no_alloc = false, const std::string &name = "");
508 // this only work for non-symm tensor
509 void Init_by_Tensor(const Tensor &in_tensor, const bool &is_diag = false,
510 const cytnx_int64 &rowrank = -1, const std::string &name = "");
511 std::vector<cytnx_uint64> shape() const {
512 if (this->_is_diag) {
513 std::vector<cytnx_uint64> shape = this->_block.shape();
514 shape.push_back(shape[0]);
515 return shape;
516 } else {
517 return this->_block.shape();
518 }
519 }
520 bool is_blockform() const { return false; }
521 void to_(const int &device) { this->_block.to_(device); }
522 boost::intrusive_ptr<UniTensor_base> to(const int &device) {
523 if (this->device() == device) {
524 std::vector<Tensor> _interface_block; // this is serves as interface for get_blocks_();
525 return this;
526 } else {
527 boost::intrusive_ptr<UniTensor_base> out = this->clone();
528 out->to_(device);
529 return out;
530 }
531 }
532 void set_rowrank_(const cytnx_uint64 &new_rowrank) {
533 cytnx_error_msg(new_rowrank > this->_labels.size(),
534 "[ERROR] rowrank cannot exceed the rank of UniTensor.%s", "\n");
535 if (this->is_diag()) {
536 cytnx_error_msg(new_rowrank != 1, "[ERROR] rowrank should be [==1] when is_diag =true!.%s",
537 "\n");
538 }
539
540 this->_rowrank = new_rowrank;
541 }
542
543 boost::intrusive_ptr<UniTensor_base> set_rowrank(const cytnx_uint64 &new_rowrank) const {
544 boost::intrusive_ptr<DenseUniTensor> out_raw = this->clone_meta();
545 out_raw->_block = this->_block;
546 out_raw->set_rowrank_(new_rowrank);
547 return out_raw;
548 }
549
550 boost::intrusive_ptr<UniTensor_base> clone() const {
551 boost::intrusive_ptr<DenseUniTensor> tmp = this->clone_meta();
552 tmp->_block = this->_block.clone();
553 return tmp;
554 };
555 bool is_contiguous() const { return this->_block.is_contiguous(); }
556 unsigned int dtype() const { return this->_block.dtype(); }
557 int device() const { return this->_block.device(); }
558 std::string dtype_str() const { return Type.getname(this->_block.dtype()); }
559 std::string device_str() const { return Device.getname(this->_block.device()); }
569 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,
570 const cytnx_int64 &rowrank = -1);
571 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<std::string> &mapper,
572 const cytnx_int64 &rowrank = -1);
573
582 void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1);
583 void permute_(const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1);
584
585 void twist_(const cytnx_int64 &idx) override {
586 // do nothing for bosonic UniTensor
587 return;
588 }
589 void twist_(const std::string &label) override {
590 // do nothing for bosonic UniTensor
591 return;
592 }
593
594 void fermion_twists_() override {
595 // do nothing for bosonic UniTensor
596 return;
597 }
598
599 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &new_labels);
600 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &new_labels);
601
602 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &old_labels,
603 const std::vector<std::string> &new_labels);
604 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &old_labels,
605 const std::vector<std::string> &new_labels);
606
617 boost::intrusive_ptr<UniTensor_base> relabel(const std::string &old_label,
618 const std::string &new_label);
619 boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx,
620 const std::string &new_label);
621
622 boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const {
623 boost::intrusive_ptr<DenseUniTensor> tmp = this->clone_meta();
624 tmp->_block = this->_block.astype(dtype);
625 return tmp;
626 }
627
628 std::vector<Symmetry> syms() const {
629 cytnx_error_msg(true, "[ERROR][DenseUniTensor] dense unitensor does not have symmetry.%s",
630 "\n");
631 return std::vector<Symmetry>();
632 }
633
634 boost::intrusive_ptr<UniTensor_base> contiguous_() {
635 // Rebind _block to the non-mutating Tensor::contiguous() result instead of calling
636 // contiguous_() in place, so a block Tensor shared with another UniTensor (e.g. via
637 // relabel()) is not corrupted (#724). Tensor::contiguous() is cheap when the block is
638 // already contiguous (no data copy; same impl returned).
639 this->_block = this->_block.contiguous();
640 return boost::intrusive_ptr<UniTensor_base>(this);
641 }
642 boost::intrusive_ptr<UniTensor_base> contiguous() {
643 // if contiguous then return self!
644 if (this->is_contiguous()) {
645 boost::intrusive_ptr<UniTensor_base> out(this);
646 return out;
647 } else {
648 boost::intrusive_ptr<DenseUniTensor> tmp = this->clone_meta();
649 tmp->_block = this->_block.contiguous();
650 return tmp;
651 }
652 }
653
654 boost::intrusive_ptr<UniTensor_base> apply_() {
655 return boost::intrusive_ptr<UniTensor_base>(this);
656 }
657 boost::intrusive_ptr<UniTensor_base> apply() {
658 // just return self
659 boost::intrusive_ptr<UniTensor_base> out(this);
660 return out;
661 }
662
663 void print_diagram(const bool &bond_info = false) const;
664 void print_blocks(const bool &full_info = true) const;
665 void print_block(const cytnx_int64 &idx, const bool &full_info = true) const;
666 Tensor get_block() const { return this->_block.clone(); }
667 Tensor get_block(const cytnx_uint64 &idx) const {
668 cytnx_error_msg(idx != 0,
669 "[ERROR][DenseUniTensor] Dense tensor has only one block, block number %llu "
670 "invalid. Use get_block(0).\n",
671 (unsigned long long)idx);
672 return this->_block.clone();
673 }
674
675 Tensor get_block(const std::vector<cytnx_int64> &qidx, const bool &force) const {
677 true, "[ERROR][DenseUniTensor] try to get_block() using qidx on a non-symmetry UniTensor%s",
678 "\n");
679 return Tensor();
680 }
681 // return a share view of block, this only work for non-symm tensor.
682 const Tensor &get_block_(const std::vector<cytnx_int64> &qidx, const bool &force) const {
684 true,
685 "[ERROR][DenseUniTensor] try to get_block_() using qidx on a non-symmetry UniTensor%s",
686 "\n");
687 return this->_block;
688 }
689 Tensor &get_block_(const std::vector<cytnx_int64> &qidx, const bool &force) {
691 true,
692 "[ERROR][DenseUniTensor] try to get_block_() using qidx on a non-symmetry UniTensor%s",
693 "\n");
694 return this->_block;
695 }
696
697 // return a share view of block, this only work for non-symm tensor.
698 Tensor &get_block_() { return this->_block; }
699 Tensor &get_block_(const cytnx_uint64 &idx) {
700 cytnx_error_msg(idx != 0,
701 "[ERROR][DenseUniTensor] Dense tensor has only one block, block number %llu "
702 "invalid. Use get_block_(0).\n",
703 (unsigned long long)idx);
704 return this->_block;
705 }
706 // return a share view of block, this only work for non-symm tensor.
707 const Tensor &get_block_() const { return this->_block; }
708 const Tensor &get_block_(const cytnx_uint64 &idx) const {
709 cytnx_error_msg(idx != 0,
710 "[ERROR][DenseUniTensor] Dense tensor has only one block, block number %llu "
711 "invalid. Use get_block_(0).\n",
712 (unsigned long long)idx);
713 return this->_block;
714 }
715
716 cytnx_uint64 Nblocks() const { return 1; };
717 std::vector<Tensor> get_blocks() const {
718 std::vector<Tensor> out;
720 true, "[ERROR][DenseUniTensor] Cannot use get_blocks(), use get_block() instead!%s", "\n");
721 return out; // this will not share memory!!
722 }
723 const std::vector<Tensor> &get_blocks_(const bool &silent = false) const {
725 true, "[ERROR][DenseUniTensor] Cannot use get_blocks_(), use get_block_() instead!%s",
726 "\n");
727 return this->_interface_block; // this will not share memory!!
728 }
729 std::vector<Tensor> &get_blocks_(const bool &silent = false) {
731 true, "[ERROR][DenseUniTensor] Cannot use get_blocks_(), use get_block_() instead!%s",
732 "\n");
733 return this->_interface_block; // this will not share memory!!
734 }
735
736 void put_block(const Tensor &in) {
737 // We don't check the dtype for DenseUniTensor, since it'll be more convenient to change
738 // DenseUniTensor's dtype
739
740 // cytnx_error_msg(in.dtype() != this->dtype(),
741 // "[ERROR][DenseUniTensor][put_block] The input tensor dtype does not
742 // match.%s",
743 // "\n");
744 cytnx_error_msg(in.device() != this->device(),
745 "[ERROR][DenseUniTensor][put_block] The input tensor device does not "
746 "match.%s",
747 "\n");
748 // We shouldn't check the contiguous
749 // cytnx_error_msg(!in.contiguous());
750 if (this->is_diag()) {
752 in.shape() != this->_block.shape(),
753 "[ERROR][DenseUniTensor][put_block] the input tensor shape does not match.%s", "\n");
754 this->_block = in.clone();
755 } else {
757 in.shape() != this->shape(),
758 "[ERROR][DenseUniTensor][put_block] the input tensor shape does not match.%s", "\n");
759 this->_block = in.clone();
760 }
761 }
762 void put_block(const Tensor &in, const cytnx_uint64 &idx) {
763 cytnx_error_msg(idx != 0,
764 "[ERROR][DenseUniTensor] Dense tensor has only one block, block number %llu "
765 "invalid. Use put_block(0).\n",
766 (unsigned long long)idx);
767 put_block(in);
768 }
769 // share view of the block
770 void put_block_(Tensor &in) {
771 // We don't check the dtype for DenseUniTensor, since it'll be more convenient to change
772 // DenseUniTensor's dtype
773
774 // cytnx_error_msg(in.dtype() != this->dtype(),
775 // "[ERROR][DenseUniTensor][put_block] The input tensor dtype does not
776 // match.%s",
777 // "\n");
778 cytnx_error_msg(in.device() != this->device(),
779 "[ERROR][DenseUniTensor][put_block] The input tensor device does not "
780 "match.%s",
781 "\n");
782 // We shouldn't check the contiguous
783 // cytnx_error_msg(!in.contiguous());
784 if (this->is_diag()) {
786 in.shape() != this->_block.shape(),
787 "[ERROR][DenseUniTensor][put_block] the input tensor shape does not match.%s", "\n");
788 this->_block = in;
789 } else {
791 in.shape() != this->shape(),
792 "[ERROR][DenseUniTensor][put_block] the input tensor shape does not match.%s", "\n");
793 this->_block = in;
794 }
795 }
796 void put_block_(Tensor &in, const cytnx_uint64 &idx) {
797 cytnx_error_msg(idx != 0,
798 "[ERROR][DenseUniTensor] Dense tensor has only one block, block number %llu "
799 "invalid. Use put_block_(0).\n",
800 (unsigned long long)idx);
801 put_block_(in);
802 }
803
804 void put_block(const Tensor &in, const std::vector<cytnx_int64> &qidx) {
806 true, "[ERROR][DenseUniTensor] try to put_block using qidx on a non-symmetry UniTensor%s",
807 "\n");
808 }
809 void put_block_(Tensor &in, const std::vector<cytnx_int64> &qidx) {
811 true, "[ERROR][DenseUniTensor] try to put_block using qidx on a non-symmetry UniTensor%s",
812 "\n");
813 }
814 // these two methods only work on non-symm tensor (DenseUniTensor)
815 boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors);
816 void set(const std::vector<Accessor> &accessors, const Tensor &rhs);
817
818 void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank = 0);
819 boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape,
820 const cytnx_uint64 &rowrank = 0);
821 boost::intrusive_ptr<UniTensor_base> to_dense();
822 void to_dense_();
823 void combineBond(const std::vector<std::string> &indicators, const bool &force = true);
824 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force,
825 const bool &by_label);
826 void combineBonds(const std::vector<std::string> &indicators, const bool &force = true);
827 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force = true);
828 boost::intrusive_ptr<UniTensor_base> contract(const boost::intrusive_ptr<UniTensor_base> &rhs,
829 const bool &mv_elem_self = false,
830 const bool &mv_elem_rhs = false);
831 std::vector<Bond> getTotalQnums(const bool &physical = false) {
832 cytnx_error_msg(true, "[ERROR][DenseUniTensor] %s",
833 "getTotalQnums can only operate on UniTensor with symmetry.\n");
834 return std::vector<Bond>();
835 }
836
837 std::vector<std::vector<cytnx_int64>> get_blocks_qnums() const {
838 cytnx_error_msg(true, "[ERROR][DenseUniTensor] %s",
839 "get_blocks_qnums can only operate on UniTensor with symmetry.\n");
840 return std::vector<std::vector<cytnx_int64>>();
841 }
842
843 bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const {
844 if (rhs->uten_type() != UTenType.Dense) return false;
845
846 return this->get_block_().same_data(rhs->get_block_());
847 }
848
849 ~DenseUniTensor(){};
850
851 // arithmetic
852 void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
853 void Add_(const Scalar &rhs);
854
855 void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
856 void Mul_(const Scalar &rhs);
857
858 void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
859 void Sub_(const Scalar &rhs);
860 void lSub_(const Scalar &lhs);
861
862 void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
863 void Div_(const Scalar &rhs);
864 void lDiv_(const Scalar &lhs);
865
866 void Conj_() { this->_block.Conj_(); };
867
868 boost::intrusive_ptr<UniTensor_base> Conj() {
869 boost::intrusive_ptr<UniTensor_base> out = this->clone();
870 out->Conj_();
871 return out;
872 }
873
874 boost::intrusive_ptr<UniTensor_base> Transpose() {
875 boost::intrusive_ptr<UniTensor_base> out = this->clone();
876 out->Transpose_();
877 return out;
878 }
879 void Transpose_();
880
881 boost::intrusive_ptr<UniTensor_base> normalize() {
882 boost::intrusive_ptr<UniTensor_base> out = this->clone();
883 out->normalize_();
884 return out;
885 }
886 void normalize_();
887
888 boost::intrusive_ptr<UniTensor_base> Dagger() {
889 boost::intrusive_ptr<UniTensor_base> out = this->Conj();
890 out->Transpose_();
891 return out;
892 }
893 void Dagger_() {
894 this->Conj_();
895 this->Transpose_();
896 }
906 void Trace_(const cytnx_int64 &a, const cytnx_int64 &b);
907 void Trace_(const std::string &a, const std::string &b);
908 boost::intrusive_ptr<UniTensor_base> Trace(const std::string &a, const std::string &b) {
909 boost::intrusive_ptr<UniTensor_base> out = this->clone();
910 out->Trace_(a, b);
911 return out;
912 }
913 boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b) {
914 boost::intrusive_ptr<UniTensor_base> out = this->clone();
915 out->Trace_(a, b);
916 return out;
917 }
918
919 Tensor Norm() const;
920
921 const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const {
923 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
924 "\n");
925 return Scalar::Sproxy();
926 }
927 const cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
928 const cytnx_complex128 &aux) const {
930 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
931 "\n");
932 return cytnx_complex128(0, 0);
933 }
934 const cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
935 const cytnx_complex64 &aux) const {
937 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
938 "\n");
939 return cytnx_complex64(0, 0);
940 }
941 const cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator,
942 const cytnx_double &aux) const {
944 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
945 "\n");
946 return 0;
947 }
948 const cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator,
949 const cytnx_float &aux) const {
951 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
952 "\n");
953 return 0;
954 }
955 const cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
956 const cytnx_uint64 &aux) const {
958 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
959 "\n");
960 return 0;
961 }
962 const cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
963 const cytnx_int64 &aux) const {
965 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
966 "\n");
967 return 0;
968 }
969 const cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
970 const cytnx_uint32 &aux) const {
972 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
973 "\n");
974 return 0;
975 }
976 const cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
977 const cytnx_int32 &aux) const {
979 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
980 "\n");
981 return 0;
982 }
983 const cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
984 const cytnx_uint16 &aux) const {
986 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
987 "\n");
988 return 0;
989 }
990 const cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
991 const cytnx_int16 &aux) const {
993 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
994 "\n");
995 return 0;
996 }
997
998 Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) {
1000 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1001 "\n");
1002 return Scalar::Sproxy();
1003 }
1004 cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1005 const cytnx_complex128 &aux) {
1007 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1008 "\n");
1009 return *(cytnx_complex128 *)nullptr;
1010 }
1011 cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1012 const cytnx_complex64 &aux) {
1014 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1015 "\n");
1016 return *(cytnx_complex64 *)nullptr;
1017 }
1018 cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux) {
1020 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1021 "\n");
1022 return *(cytnx_double *)nullptr;
1023 }
1024 cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux) {
1026 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1027 "\n");
1028 return *(cytnx_float *)nullptr;
1029 }
1030 cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux) {
1032 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1033 "\n");
1034 return *(cytnx_uint64 *)nullptr;
1035 }
1036 cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux) {
1038 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1039 "\n");
1040 return *(cytnx_int64 *)nullptr;
1041 }
1042 cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux) {
1044 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1045 "\n");
1046 return *(cytnx_uint32 *)nullptr;
1047 }
1048 cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux) {
1050 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1051 "\n");
1052 return *(cytnx_int32 *)nullptr;
1053 }
1054 cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux) {
1056 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1057 "\n");
1058 return *(cytnx_uint16 *)nullptr;
1059 }
1060 cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux) {
1062 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1063 "\n");
1064 return *(cytnx_int16 *)nullptr;
1065 }
1066
1067 bool elem_exists(const std::vector<cytnx_uint64> &locator) const {
1069 true, "[ERROR][DenseUniTensor] elem_exists can only be used on UniTensor with Symmetry.%s",
1070 "\n");
1071 }
1072 void tag_() {
1073 if (!this->is_tag()) {
1074 for (int i = 0; i < this->_rowrank; i++) {
1075 this->_bonds[i] = this->_bonds[i].retype(BD_KET);
1076 }
1077 for (int i = this->_rowrank; i < this->_bonds.size(); i++) {
1078 this->_bonds[i] = this->_bonds[i].retype(BD_BRA);
1079 }
1080 this->_is_tag = true;
1081 this->_is_braket_form = this->_update_braket();
1082 }
1083 }
1093 void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim);
1094 void truncate_(const std::string &label, const cytnx_uint64 &dim);
1095
1096 void from_(const boost::intrusive_ptr<UniTensor_base> &rhs, bool force, cytnx_double tol = 0.);
1097
1098 void group_basis_() {
1099 cytnx_warning_msg(true, "[WARNING] group basis will not have any effect on DensUniTensor.%s",
1100 "\n");
1101 }
1102
1103 void _save_dispatch(std::fstream &f) const;
1104 void _load_dispatch(std::fstream &f, unsigned int version);
1105
1106 const std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) const {
1107 cytnx_error_msg(true, "[ERROR] get_qindices can only be unsed on UniTensor with Symmetry.%s",
1108 "\n");
1109 }
1110 std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) {
1111 cytnx_error_msg(true, "[ERROR] get_qindices can only be unsed on UniTensor with Symmetry.%s",
1112 "\n");
1113 }
1114
1115 const vec2d<cytnx_uint64> &get_itoi() const {
1116 cytnx_error_msg(true, "[ERROR] get_itoi can only be unsed on UniTensor with Symmetry.%s",
1117 "\n");
1118 }
1119 vec2d<cytnx_uint64> &get_itoi() {
1120 cytnx_error_msg(true, "[ERROR] get_itoi can only be unsed on UniTensor with Symmetry.%s",
1121 "\n");
1122 }
1123
1124 // end virtual function
1125 };
1127
1128 //======================================================================
1130 class BlockUniTensor : public UniTensor_base {
1131 protected:
1132 public:
1133 std::vector<std::vector<cytnx_uint64>>
1134 _inner_to_outer_idx; // stores the qindices for each block
1135 std::vector<Tensor> _blocks;
1136 Tensor NullRefTensor; // this returns when access block does not exists!
1137
1138 // given an index list [loc], get qnums from this->_bonds[loc] and return the combined qnums
1139 // calculated from Symm object! this assume 1. symmetry are the same for each bond!
1140 // 2. total_qns are feeded with size len(symmetry)
1141 void _fx_get_total_fluxs(std::vector<cytnx_uint64> &loc, const std::vector<Symmetry> &syms,
1142 std::vector<cytnx_int64> &total_qns) {
1144 loc.size() != this->_bonds.size(),
1145 "[ERROR][BlockUniTensor] qnum location rank does not match the number of bonds.%s", "\n");
1146 cytnx_error_msg(total_qns.size() != syms.size(),
1147 "[ERROR][BlockUniTensor] total_qns size does not match symmetry count.%s",
1148 "\n");
1149 std::fill(total_qns.begin(), total_qns.end(), 0);
1150 if (this->_bonds.empty()) return;
1151
1152 for (cytnx_int32 i = 0; i < syms.size(); i++) {
1153 if (this->_bonds[0].type() == BD_BRA)
1154 total_qns[i] = syms[i].reverse_rule(this->_bonds[0]._impl->_qnums[loc[0]][i]);
1155 else
1156 total_qns[i] = this->_bonds[0]._impl->_qnums[loc[0]][i];
1157
1158 for (auto j = 1; j < loc.size(); j++) {
1159 if (this->_bonds[j].type() == BD_BRA)
1160 total_qns[i] = syms[i].combine_rule(
1161 total_qns[i], syms[i].reverse_rule(this->_bonds[j]._impl->_qnums[loc[j]][i]));
1162 else {
1163 total_qns[i] =
1164 syms[i].combine_rule(total_qns[i], this->_bonds[j]._impl->_qnums[loc[j]][i]);
1165 }
1166 }
1167 }
1168 }
1169
1170 void _fx_locate_elem(cytnx_int64 &bidx, std::vector<cytnx_uint64> &loc_in_T,
1171 const std::vector<cytnx_uint64> &locator) const;
1172
1173 // internal function, grouping all duplicate qnums in all bonds
1174 void _fx_group_duplicates(const std::vector<cytnx_uint64> &dup_bond_idxs,
1175 const std::vector<std::vector<cytnx_uint64>> &idx_mappers);
1176
1177 void set_meta(BlockUniTensor *tmp, const bool &inner, const bool &outer) const {
1178 // outer meta
1179 if (outer) {
1180 tmp->_bonds = vec_clone(this->_bonds);
1181 tmp->_labels = this->_labels;
1182 tmp->syms_cache = vec_clone(this->syms_cache);
1183 tmp->_is_braket_form = this->_is_braket_form;
1184 tmp->_rowrank = this->_rowrank;
1185 tmp->_name = this->_name;
1186 }
1187
1188 tmp->_is_diag = this->_is_diag;
1189
1190 // inner meta
1191 if (inner) {
1192 tmp->_inner_to_outer_idx = this->_inner_to_outer_idx;
1193 }
1194 }
1195
1196 boost::intrusive_ptr<BlockUniTensor> clone_meta(const bool &inner, const bool &outer) const {
1197 boost::intrusive_ptr<BlockUniTensor> tmp(new BlockUniTensor());
1198 this->set_meta(tmp.get(), inner, outer);
1199 return tmp;
1200 };
1201
1202 friend class UniTensor;
1203 BlockUniTensor() {
1204 this->uten_type_id = UTenType.Block;
1205 this->_is_tag = true;
1206 }
1207
1208 // virtual functions:
1209 // void Init(const std::vector<Bond> &bonds, const std::vector<cytnx_int64> &in_labels = {},
1210 // const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
1211 // const int &device = Device.cpu, const bool &is_diag = false,
1212 // const bool &no_alloc = false);
1213
1214 void Init(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
1215 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
1216 const int &device = Device.cpu, const bool &is_diag = false,
1217 const bool &no_alloc = false, const std::string &name = "");
1218
1219 void Init_by_Tensor(const Tensor &in_tensor, const bool &is_diag = false,
1220 const cytnx_int64 &rowrank = -1, const std::string &name = "") {
1222 true, "[ERROR][BlockUniTensor] Cannot use Init_by_tensor() on a BlockUniTensor.%s", "\n");
1223 }
1224
1225 std::vector<cytnx_uint64> shape() const {
1226 if (this->rank() == 0) return {};
1227 std::vector<cytnx_uint64> out(this->_bonds.size());
1228 for (cytnx_uint64 i = 0; i < out.size(); i++) {
1229 out[i] = this->_bonds[i].dim();
1230 }
1231 return out;
1232 }
1233
1234 bool is_blockform() const { return true; }
1235 bool is_contiguous() const {
1236 bool out = true;
1237 for (int i = 0; i < this->_blocks.size(); i++) {
1238 out &= this->_blocks[i].is_contiguous();
1239 }
1240 return out;
1241 };
1242
1243 cytnx_uint64 Nblocks() const { return this->_blocks.size(); };
1244
1245 void to_(const int &device) {
1246 for (cytnx_uint64 i = 0; i < this->_blocks.size(); i++) {
1247 this->_blocks[i].to_(device);
1248 }
1249 };
1250
1251 boost::intrusive_ptr<UniTensor_base> to(const int &device) {
1252 if (this->device() == device) {
1253 return this;
1254 } else {
1255 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1256 out->to_(device);
1257 return out;
1258 }
1259 };
1260
1261 boost::intrusive_ptr<UniTensor_base> clone() const {
1262 boost::intrusive_ptr<BlockUniTensor> tmp = this->clone_meta(true, true);
1263 tmp->_blocks = vec_clone(this->_blocks);
1264 return tmp;
1265 };
1266
1267 unsigned int dtype() const {
1268 //[21 Aug 2024] This is a copy from BlockUniTensor;
1269#ifdef UNI_DEBUG
1270 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
1271 "\n");
1272#endif
1273 return this->_blocks.size() < 1 ? Type.Void : this->_blocks[0].dtype();
1274 };
1275 int device() const {
1276 //[21 Aug 2024] This is a copy from BlockUniTensor;
1277#ifdef UNI_DEBUG
1278 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
1279 "\n");
1280#endif
1281 return this->_blocks.size() < 1 ? -404 : this->_blocks[0].device();
1282 };
1283 std::string dtype_str() const {
1284 //[21 Aug 2024] This is a copy from BlockUniTensor;
1285#ifdef UNI_DEBUG
1286 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
1287 "\n");
1288#endif
1289 return this->_blocks.size() < 1 ? "Void, no valid blocks" : this->_blocks[0].dtype_str();
1290 };
1291 std::string device_str() const {
1292 //[21 Aug 2024] This is a copy from BlockUniTensor;
1293#ifdef UNI_DEBUG
1294 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
1295 "\n");
1296#endif
1297 return this->_blocks.size() < 1 ? "None, no valid blocks" : this->_blocks[0].device_str();
1298 };
1299
1300 Tensor get_block(const cytnx_uint64 &idx = 0) const {
1301 cytnx_error_msg(idx >= this->_blocks.size(), "[ERROR][BlockUniTensor] index out of range%s",
1302 "\n");
1303 return this->_blocks[idx].clone();
1304 };
1305
1306 // this one for Block will return the indicies!!
1307 Tensor get_block(const std::vector<cytnx_int64> &qidx, const bool &force_return) const {
1308 if (this->rank() == 0) {
1309 cytnx_error_msg(!qidx.empty(),
1310 "[ERROR][get_block][BlockUniTensor] rank-0 scalar block expects no "
1311 "qidx entries.%s",
1312 "\n");
1313 cytnx_error_msg(this->_blocks.empty(), "[ERROR][BlockUniTensor] index out of range%s",
1314 "\n");
1315 return this->_blocks[0].clone();
1316 }
1317 cytnx_error_msg(qidx.size() != this->rank(),
1318 "[ERROR][get_block][BlockUniTensor] len(qidx) must be the same as the "
1319 "Tensor rank (number of legs).%s",
1320 "\n");
1321
1322 std::vector<cytnx_uint64> inds(qidx.begin(), qidx.end());
1323
1324 // find the block whose qidx matches
1325 cytnx_int64 b = -1;
1326 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
1327 if (inds == this->_inner_to_outer_idx[i]) {
1328 b = i;
1329 break;
1330 }
1331 }
1332
1333 if (b < 0) {
1334 if (force_return) {
1335 return NullRefTensor;
1336 } else {
1337 cytnx_error_msg(true,
1338 "[ERROR][get_block][BlockUniTensor] no avaliable block exists, "
1339 "force_return=false, so "
1340 "error throws. \n If you want to return an empty block without "
1341 "error when block is "
1342 "not avaliable, set force_return=True.%s",
1343 "\n");
1344 }
1345 } else {
1346 return this->_blocks[b].clone();
1347 }
1348 }
1349
1350 const Tensor &get_block_(const cytnx_uint64 &idx = 0) const {
1351 cytnx_error_msg(idx >= this->_blocks.size(), "[ERROR][BlockUniTensor] index out of range%s",
1352 "\n");
1353 return this->_blocks[idx];
1354 };
1355
1356 Tensor &get_block_(const cytnx_uint64 &idx = 0) {
1357 cytnx_error_msg(idx >= this->_blocks.size(), "[ERROR][BlockUniTensor] index out of range%s",
1358 "\n");
1359 return this->_blocks[idx];
1360 };
1361
1362 const Tensor &get_block_(const std::vector<cytnx_int64> &qidx, const bool &force_return) const {
1363 if (this->rank() == 0) {
1364 cytnx_error_msg(!qidx.empty(),
1365 "[ERROR][get_block][BlockUniTensor] rank-0 scalar block expects no "
1366 "qidx entries.%s",
1367 "\n");
1368 cytnx_error_msg(this->_blocks.empty(), "[ERROR][BlockUniTensor] index out of range%s",
1369 "\n");
1370 return this->_blocks[0];
1371 }
1372 cytnx_error_msg(qidx.size() != this->rank(),
1373 "[ERROR][get_block][BlockUniTensor] len(qidx) must be the same as the "
1374 "Tensor rank (number of legs).%s",
1375 "\n");
1376
1377 std::vector<cytnx_uint64> inds(qidx.begin(), qidx.end());
1378
1379 // find the block whose qidx matches
1380 cytnx_int64 b = -1;
1381 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
1382 if (inds == this->_inner_to_outer_idx[i]) {
1383 b = i;
1384 break;
1385 }
1386 }
1387
1388 if (b < 0) {
1389 if (force_return) {
1390 return this->NullRefTensor;
1391 } else {
1392 cytnx_error_msg(true,
1393 "[ERROR][get_block][BlockUniTensor] no avaliable block exists, "
1394 "force_return=false, so "
1395 "error throws. \n If you want to return an empty block without "
1396 "error when block is "
1397 "not avaliable, set force_return=True.%s",
1398 "\n");
1399 }
1400 } else {
1401 return this->_blocks[b];
1402 }
1403 }
1404
1405 Tensor &get_block_(const std::vector<cytnx_int64> &qidx, const bool &force_return) {
1406 if (this->rank() == 0) {
1407 cytnx_error_msg(!qidx.empty(),
1408 "[ERROR][get_block][BlockUniTensor] rank-0 scalar block expects no "
1409 "qidx entries.%s",
1410 "\n");
1411 cytnx_error_msg(this->_blocks.empty(), "[ERROR][BlockUniTensor] index out of range%s",
1412 "\n");
1413 return this->_blocks[0];
1414 }
1415 cytnx_error_msg(qidx.size() != this->rank(),
1416 "[ERROR][get_block][BlockUniTensor] len(qidx) must be the same as the "
1417 "Tensor rank (number of legs).%s",
1418 "\n");
1419
1420 std::vector<cytnx_uint64> inds(qidx.begin(), qidx.end());
1421
1422 // find the block whose qidx matches
1423 cytnx_int64 b = -1;
1424 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
1425 if (inds == this->_inner_to_outer_idx[i]) {
1426 b = i;
1427 break;
1428 }
1429 }
1430
1431 if (b < 0) {
1432 if (force_return) {
1433 return this->NullRefTensor;
1434 } else {
1435 cytnx_error_msg(true,
1436 "[ERROR][get_block][BlockUniTensor] no avaliable block exists, "
1437 "force_return=false, so "
1438 "error throws. \n If you want to return an empty block without "
1439 "error when block is "
1440 "not avaliable, set force_return=True.%s",
1441 "\n");
1442 }
1443 } else {
1444 return this->_blocks[b];
1445 }
1446 }
1447
1448 std::vector<Tensor> get_blocks() const { return vec_clone(this->_blocks); }
1449 const std::vector<Tensor> &get_blocks_(const bool &) const { return this->_blocks; }
1450 std::vector<Tensor> &get_blocks_(const bool &) { return this->_blocks; }
1451
1452 bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const {
1453 if (rhs->uten_type() != UTenType.Block) return false;
1454 if (rhs->get_blocks_(1).size() != this->get_blocks_(1).size()) return false;
1455
1456 for (int i = 0; i < rhs->get_blocks_(1).size(); i++)
1457 if (this->get_blocks_(1)[i].same_data(rhs->get_blocks_(1)[i]) == false) return false;
1458
1459 return true;
1460 }
1461
1462 void set_rowrank_(const cytnx_uint64 &new_rowrank) {
1463 cytnx_error_msg(new_rowrank > this->rank(),
1464 "[ERROR][BlockUniTensor] rowrank should be [>=0] and [<=UniTensor.rank].%s",
1465 "\n");
1466 if (this->is_diag()) {
1467 cytnx_error_msg(new_rowrank != 1,
1468 "[ERROR][BlockUniTensor] rowrank should be [==1] when is_diag =true!.%s",
1469 "\n");
1470 }
1471 this->_rowrank = new_rowrank;
1472 this->_is_braket_form = this->_update_braket();
1473 }
1474
1475 boost::intrusive_ptr<UniTensor_base> set_rowrank(const cytnx_uint64 &new_rowrank) const {
1476 boost::intrusive_ptr<BlockUniTensor> tmp = this->clone_meta(true, true);
1477 tmp->_blocks = this->_blocks;
1478 tmp->set_rowrank_(new_rowrank);
1479 return tmp;
1480 }
1481
1482 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,
1483 const cytnx_int64 &rowrank = -1);
1484 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<std::string> &mapper,
1485 const cytnx_int64 &rowrank = -1);
1486
1487 void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1);
1488 void permute_(const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1);
1489
1490 void twist_(const cytnx_int64 &idx) override {
1491 // do nothing for bosonic UniTensor
1492 return;
1493 }
1494 void fermion_twists_() override {
1495 // do nothing for bosonic UniTensor
1496 return;
1497 }
1498 void twist_(const std::string &label) override {
1499 // do nothing for bosonic UniTensor
1500 return;
1501 }
1502
1503 boost::intrusive_ptr<UniTensor_base> contiguous_() {
1504 // Rebind each block to the non-mutating Tensor::contiguous() result instead of calling
1505 // contiguous_() in place, so a block Tensor shared with another UniTensor (e.g. via
1506 // relabel()) is not corrupted (#724). Tensor::contiguous() is cheap when the block is
1507 // already contiguous (no data copy; same impl returned).
1508 for (unsigned int b = 0; b < this->_blocks.size(); b++)
1509 this->_blocks[b] = this->_blocks[b].contiguous();
1510 return boost::intrusive_ptr<UniTensor_base>(this);
1511 }
1512 boost::intrusive_ptr<UniTensor_base> contiguous();
1513
1514 boost::intrusive_ptr<UniTensor_base> apply_() {
1515 return boost::intrusive_ptr<UniTensor_base>(this);
1516 }
1517 boost::intrusive_ptr<UniTensor_base> apply() {
1518 // just return self
1519 boost::intrusive_ptr<UniTensor_base> out(this);
1520 return out;
1521 }
1522
1523 void print_diagram(const bool &bond_info = false) const;
1524 void print_blocks(const bool &full_info = true) const;
1525 void print_block(const cytnx_int64 &idx, const bool &full_info = true) const;
1526
1527 boost::intrusive_ptr<UniTensor_base> contract(const boost::intrusive_ptr<UniTensor_base> &rhs,
1528 const bool &mv_elem_self = false,
1529 const bool &mv_elem_rhs = false);
1530
1531 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &new_labels);
1532 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &new_labels);
1533
1534 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &old_labels,
1535 const std::vector<std::string> &new_labels);
1536 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &old_labels,
1537 const std::vector<std::string> &new_labels);
1538
1539 boost::intrusive_ptr<UniTensor_base> relabel(const std::string &old_label,
1540 const std::string &new_label);
1541 boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx,
1542 const std::string &new_label);
1543
1544 std::vector<Symmetry> syms() const;
1545
1546 void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank = 0) {
1547 cytnx_error_msg(true, "[ERROR] Cannot reshape a UniTensor with symmetry.%s", "\n");
1548 }
1549 boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape,
1550 const cytnx_uint64 &rowrank = 0) {
1551 cytnx_error_msg(true, "[ERROR] Cannot reshape a UniTensor with symmetry.%s", "\n");
1552 return nullptr;
1553 }
1554
1555 boost::intrusive_ptr<UniTensor_base> to_dense();
1556 void to_dense_();
1557
1558 boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const {
1559 boost::intrusive_ptr<BlockUniTensor> tmp = this->clone_meta(true, true);
1560 tmp->_blocks.resize(this->_blocks.size());
1561 for (cytnx_int64 blk = 0; blk < this->_blocks.size(); blk++) {
1562 tmp->_blocks[blk] = this->_blocks[blk].astype(dtype);
1563 }
1564 return tmp;
1565 };
1566
1567 // this will only work on non-symm tensor (DenseUniTensor)
1568 boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors) {
1570 true,
1571 "[ERROR][BlockUniTensor][get] Cannot use get on a UniTensor with "
1572 "Symmetry.\n suggestion: try get_block/get_block_/get_blocks/get_blocks_ first.%s",
1573 "\n");
1574 return nullptr;
1575 }
1576
1577 // this will only work on non-symm tensor (DenseUniTensor)
1578 void set(const std::vector<Accessor> &accessors, const Tensor &rhs) {
1580 true,
1581 "[ERROR][BlockUniTensor][get] Cannot use get on a UniTensor with "
1582 "Symmetry.\n suggestion: try get_block/get_block_/get_blocks/get_blocks_ first.%s",
1583 "\n");
1584 }
1585
1586 void put_block(const Tensor &in, const cytnx_uint64 &idx = 0) {
1587 cytnx_error_msg(in.dtype() != this->dtype(),
1588 "[ERROR][BlockUniTensor][put_block] The input tensor dtype does not match.%s",
1589 "\n");
1590 cytnx_error_msg(in.device() != this->device(),
1591 "[ERROR][BlockUniTensor][put_block] The input tensor device does not "
1592 "match.%s",
1593 "\n");
1594 // We shouldn't check the contiguous
1595 // cytnx_error_msg(!in.contiguous());
1596 cytnx_error_msg(idx >= this->_blocks.size(), "[ERROR][BlockUniTensor] index out of range%s",
1597 "\n");
1598 cytnx_error_msg(in.shape() != this->_blocks[idx].shape(),
1599 "[ERROR][BlockUniTensor] the shape of input tensor does not match the shape "
1600 "of block @ idx=%d\n",
1601 idx);
1602
1603 this->_blocks[idx] = in.clone();
1604 }
1605 void put_block_(Tensor &in, const cytnx_uint64 &idx = 0) {
1606 cytnx_error_msg(in.dtype() != this->dtype(),
1607 "[ERROR][BlockUniTensor][put_block] The input tensor dtype does not match.%s",
1608 "\n");
1609 cytnx_error_msg(in.device() != this->device(),
1610 "[ERROR][BlockUniTensor][put_block] The input tensor device does not "
1611 "match.%s",
1612 "\n");
1613 // We shouldn't check the contiguous
1614 // cytnx_error_msg(!in.contiguous());
1615 cytnx_error_msg(idx >= this->_blocks.size(), "[ERROR][BlockUniTensor] index out of range%s",
1616 "\n");
1617 cytnx_error_msg(in.shape() != this->_blocks[idx].shape(),
1618 "[ERROR][BlockUniTensor] the shape of input tensor does not match the shape "
1619 "of block @ idx=%d\n",
1620 idx);
1621
1622 this->_blocks[idx] = in;
1623 }
1624 void put_block(const Tensor &in, const std::vector<cytnx_int64> &qidx) {
1625 cytnx_error_msg(in.dtype() != this->dtype(),
1626 "[ERROR][BlockUniTensor][put_block] The input tensor dtype does not match.%s",
1627 "\n");
1628 cytnx_error_msg(in.device() != this->device(),
1629 "[ERROR][BlockUniTensor][put_block] The input tensor device does not "
1630 "match.%s",
1631 "\n");
1632 // We shouldn't check the contiguous
1633 // cytnx_error_msg(!in.contiguous());
1634 cytnx_error_msg(qidx.size() != this->rank(),
1635 "[ERROR][put_block][BlockUniTensor] len(qidx) must be the same as the "
1636 "Tensor rank (number of legs).%s",
1637 "\n");
1638
1639 std::vector<cytnx_uint64> inds(qidx.begin(), qidx.end());
1640
1641 // find the block whose qidx matches
1642 cytnx_int64 b = -1;
1643 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
1644 if (inds == this->_inner_to_outer_idx[i]) {
1645 b = i;
1646 break;
1647 }
1648 }
1649
1650 if (b < 0) {
1651 cytnx_error_msg(true, "[ERROR][put_block][BlockUniTensor] no avaliable block exists.%s",
1652 "\n");
1653 } else {
1655 in.shape() != this->_blocks[b].shape(),
1656 "[ERROR][BlockUniTensor] the shape of input tensor does not match the shape "
1657 "of block @ idx=%d\n",
1658 b);
1659
1660 this->_blocks[b] = in.clone();
1661 }
1662 }
1663 void put_block_(Tensor &in, const std::vector<cytnx_int64> &qidx) {
1664 cytnx_error_msg(in.dtype() != this->dtype(),
1665 "[ERROR][BlockUniTensor][put_block] The input tensor dtype does not match.%s",
1666 "\n");
1667 cytnx_error_msg(in.device() != this->device(),
1668 "[ERROR][BlockUniTensor][put_block] The input tensor device does not "
1669 "match.%s",
1670 "\n");
1671 // We shouldn't check the contiguous
1672 // cytnx_error_msg(!in.contiguous());
1673 cytnx_error_msg(qidx.size() != this->rank(),
1674 "[ERROR][put_block][BlockUniTensor] len(qidx) must be the same as the "
1675 "Tensor rank (number of legs).%s",
1676 "\n");
1677
1678 std::vector<cytnx_uint64> inds(qidx.begin(), qidx.end());
1679
1680 // find the block whose qidx matches
1681 cytnx_int64 b = -1;
1682 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
1683 if (inds == this->_inner_to_outer_idx[i]) {
1684 b = i;
1685 break;
1686 }
1687 }
1688
1689 if (b < 0) {
1690 cytnx_error_msg(true, "[ERROR][put_block][BlockUniTensor] no avaliable block exists.%s",
1691 "\n");
1692 } else {
1694 in.shape() != this->_blocks[b].shape(),
1695 "[ERROR][BlockUniTensor] the shape of input tensor does not match the shape "
1696 "of block @ idx=%d\n",
1697 b);
1698 this->_blocks[b] = in;
1699 }
1700 }
1701
1702 void tag_() {
1703 // no-use!
1704 }
1705
1706 boost::intrusive_ptr<UniTensor_base> Conj() {
1707 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1708 out->Conj_();
1709 return out;
1710 }
1711
1712 void Conj_() {
1713 for (int i = 0; i < this->_blocks.size(); i++) {
1714 this->_blocks[i].Conj_();
1715 }
1716 };
1717
1718 void Transpose_();
1719 boost::intrusive_ptr<UniTensor_base> Transpose() {
1720 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1721 out->Transpose_();
1722 return out;
1723 }
1724
1725 void normalize_();
1726 boost::intrusive_ptr<UniTensor_base> normalize() {
1727 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1728 out->normalize_();
1729 return out;
1730 }
1731
1732 boost::intrusive_ptr<UniTensor_base> Dagger() {
1733 boost::intrusive_ptr<UniTensor_base> out = this->Conj();
1734 out->Transpose_();
1735 return out;
1736 }
1737 void Dagger_() {
1738 this->Conj_();
1739 this->Transpose_();
1740 }
1741
1742 void Trace_(const std::string &a, const std::string &b);
1743 void Trace_(const cytnx_int64 &a, const cytnx_int64 &b);
1744
1745 boost::intrusive_ptr<UniTensor_base> Trace(const std::string &a, const std::string &b) {
1746 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1747 out->Trace_(a, b);
1748 return out;
1749 }
1750 boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b) {
1751 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1752 out->Trace_(a, b);
1753 return out;
1754 }
1755
1756 Tensor Norm() const;
1757
1758 bool elem_exists(const std::vector<cytnx_uint64> &locator) const;
1759
1760 const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const;
1761 const cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1762 const cytnx_complex128 &aux) const;
1763 const cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1764 const cytnx_complex64 &aux) const;
1765 const cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1766 const cytnx_double &aux) const;
1767 const cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1768 const cytnx_float &aux) const;
1769 const cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1770 const cytnx_uint64 &aux) const;
1771 const cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1772 const cytnx_int64 &aux) const;
1773 const cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1774 const cytnx_uint32 &aux) const;
1775 const cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1776 const cytnx_int32 &aux) const;
1777 const cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1778 const cytnx_uint16 &aux) const;
1779 const cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1780 const cytnx_int16 &aux) const;
1781
1782 Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator);
1783 cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1784 const cytnx_complex128 &aux);
1785 cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1786 const cytnx_complex64 &aux);
1787 cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux);
1788 cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux);
1789 cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux);
1790 cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux);
1791 cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux);
1792 cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux);
1793 cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux);
1794 cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux);
1795
1796 void _save_dispatch(std::fstream &f) const;
1797 void _load_dispatch(std::fstream &f, unsigned int version);
1798
1799 // this will remove the [q_index]-th qnum at [bond_idx]-th Bond!
1800 void truncate_(const std::string &label, const cytnx_uint64 &q_index);
1801 void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &q_index);
1802
1803 void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1804 void Add_(const Scalar &rhs) {
1806 true,
1807 "[ERROR] Cannot perform elementwise arithmetic '+' between Scalar and BlockUniTensor.\n %s "
1808 "\n",
1809 "This operation would destroy the block structure. [Suggest] Avoid or use get/put_block(s) "
1810 "to do operation on blocks.");
1811 }
1812
1813 void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1814 void Mul_(const Scalar &rhs);
1815
1816 void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1817 void Sub_(const Scalar &rhs) {
1819 true,
1820 "[ERROR] Cannot perform elementwise arithmetic '-' between Scalar and BlockUniTensor.\n %s "
1821 "\n",
1822 "This operation would destroy the block structure. [Suggest] Avoid or use get/put_block(s) "
1823 "to do operation on blocks.");
1824 }
1825 void lSub_(const Scalar &lhs) {
1827 true,
1828 "[ERROR] Cannot perform elementwise arithmetic '-' between Scalar and BlockUniTensor.\n %s "
1829 "\n",
1830 "This operation would destroy the block structure. [Suggest] Avoid or use get/put_block(s) "
1831 "to do operation on blocks.");
1832 }
1833
1834 void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1835 void Div_(const Scalar &rhs);
1836 void lDiv_(const Scalar &lhs) {
1838 true,
1839 "[ERROR] Cannot perform elementwise arithmetic '/' between Scalar and BlockUniTensor.\n %s "
1840 "\n",
1841 "This operation would cause division by zero on non-block elements. [Suggest] Avoid or use "
1842 "get/put_block(s) to do operation on blocks.");
1843 }
1844 void from_(const boost::intrusive_ptr<UniTensor_base> &rhs, bool force, cytnx_double tol = 0.);
1845
1846 void group_basis_();
1847
1848 void combineBond(const std::vector<std::string> &indicators, const bool &force = false);
1849 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force = false);
1850 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force,
1851 const bool &by_label);
1852 void combineBonds(const std::vector<std::string> &indicators, const bool &force = false);
1853
1854 const std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) const {
1856 bidx >= this->Nblocks(),
1857 "[ERROR][BlockUniTensor] bidx out of bound! only %d blocks in current UTen.\n",
1858 this->Nblocks());
1859 return this->_inner_to_outer_idx[bidx];
1860 }
1861 std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) {
1863 bidx >= this->Nblocks(),
1864 "[ERROR][BlockUniTensor] bidx out of bound! only %d blocks in current UTen.\n",
1865 this->Nblocks());
1866 return this->_inner_to_outer_idx[bidx];
1867 }
1868
1869 const vec2d<cytnx_uint64> &get_itoi() const { return this->_inner_to_outer_idx; }
1870 vec2d<cytnx_uint64> &get_itoi() { return this->_inner_to_outer_idx; }
1871 };
1873
1874 //======================================================================
1876 class BlockFermionicUniTensor : public UniTensor_base {
1877 //[21 Aug 2024] This is a copy from BlockUniTensor; additionally sign flips are stored as
1878 //_signflip and taken care of in all the methods
1879 public:
1880 std::vector<std::vector<cytnx_uint64>>
1881 _inner_to_outer_idx; // stores the qindices for each block
1882 std::vector<Tensor> _blocks;
1883 Tensor NullRefTensor; // this returns when accessed block does not exists!
1884
1885 // given an index list [loc], get qnums from this->_bonds[loc] and return the combined qnums
1886 // calculated from Symm object! this assume 1. symmetry are the same for each bond!
1887 // 2. total_qns are feeded with size len(symmetry)
1888 void _fx_get_total_fluxs(std::vector<cytnx_uint64> &loc, const std::vector<Symmetry> &syms,
1889 std::vector<cytnx_int64> &total_qns) {
1890 //[21 Aug 2024] This is a copy from BlockUniTensor;
1892 loc.size() != this->_bonds.size(),
1893 "[ERROR][BlockFermionicUniTensor] qnum location rank does not match the number of bonds.%s",
1894 "\n");
1896 total_qns.size() != syms.size(),
1897 "[ERROR][BlockFermionicUniTensor] total_qns size does not match symmetry count.%s", "\n");
1898 std::fill(total_qns.begin(), total_qns.end(), 0);
1899 if (this->_bonds.empty()) return;
1900
1901 for (cytnx_int32 i = 0; i < syms.size(); i++) {
1902 if (this->_bonds[0].type() == BD_BRA)
1903 total_qns[i] = syms[i].reverse_rule(this->_bonds[0]._impl->_qnums[loc[0]][i]);
1904 else
1905 total_qns[i] = this->_bonds[0]._impl->_qnums[loc[0]][i];
1906
1907 for (auto j = 1; j < loc.size(); j++) {
1908 if (this->_bonds[j].type() == BD_BRA)
1909 total_qns[i] = syms[i].combine_rule(
1910 total_qns[i], syms[i].reverse_rule(this->_bonds[j]._impl->_qnums[loc[j]][i]));
1911 else {
1912 total_qns[i] =
1913 syms[i].combine_rule(total_qns[i], this->_bonds[j]._impl->_qnums[loc[j]][i]);
1914 }
1915 }
1916 }
1917 }
1918
1919 void _fx_locate_elem(cytnx_int64 &bidx, std::vector<cytnx_uint64> &loc_in_T,
1920 const std::vector<cytnx_uint64> &locator) const;
1921
1922 // internal function, grouping all duplicate qnums in all bonds
1923 void _fx_group_duplicates(const std::vector<cytnx_uint64> &dup_bond_idxs,
1924 const std::vector<std::vector<cytnx_uint64>> &idx_mappers);
1925
1926 void set_meta(BlockFermionicUniTensor *tmp, const bool &inner, const bool &outer) const {
1927 //[21 Aug 2024] This is a copy from BlockUniTensor; additionally, _signflip is set
1928 // outer meta
1929 if (outer) {
1930 tmp->_bonds = vec_clone(this->_bonds);
1931 tmp->_labels = this->_labels;
1932 tmp->syms_cache = vec_clone(this->syms_cache);
1933 tmp->_is_braket_form = this->_is_braket_form;
1934 tmp->_rowrank = this->_rowrank;
1935 tmp->_name = this->_name;
1936 // tmp->_signflip = vec_clone(this->_signflip);
1937 tmp->_signflip = this->_signflip;
1938 }
1939
1940 tmp->_is_diag = this->_is_diag;
1941
1942 // inner meta
1943 if (inner) {
1944 tmp->_inner_to_outer_idx = this->_inner_to_outer_idx;
1945 }
1946 }
1947
1948 boost::intrusive_ptr<BlockFermionicUniTensor> clone_meta(const bool &inner,
1949 const bool &outer) const {
1950 //[21 Aug 2024] This is a copy from BlockUniTensor;
1951 boost::intrusive_ptr<BlockFermionicUniTensor> tmp(new BlockFermionicUniTensor());
1952 this->set_meta(tmp.get(), inner, outer);
1953 return tmp;
1954 };
1955
1956 friend class UniTensor;
1957 BlockFermionicUniTensor() {
1958 //[21 Aug 2024] This is a copy from BlockUniTensor;
1959 this->uten_type_id = UTenType.BlockFermionic;
1960 this->_is_tag = true;
1961 }
1962
1963 void Init(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
1964 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
1965 const int &device = Device.cpu, const bool &is_diag = false,
1966 const bool &no_alloc = false, const std::string &name = "");
1967
1968 void Init_by_Tensor(const Tensor &in_tensor, const bool &is_diag = false,
1969 const cytnx_int64 &rowrank = -1, const std::string &name = "") {
1970 cytnx_error_msg(true,
1971 "[ERROR][BlockFermionicUniTensor] Cannot use Init_by_tensor() on a "
1972 "BlockFermionicUniTensor.%s",
1973 "\n");
1974 }
1975
1976 std::vector<cytnx_uint64> shape() const {
1977 //[21 Aug 2024] This is a copy from BlockUniTensor;
1978 if (this->rank() == 0) return {};
1979 std::vector<cytnx_uint64> out(this->_bonds.size());
1980 for (cytnx_uint64 i = 0; i < out.size(); i++) {
1981 out[i] = this->_bonds[i].dim();
1982 }
1983 return out;
1984 }
1985
1986 bool is_blockform() const {
1987 //[21 Aug 2024] This is a copy from BlockUniTensor;
1988 return true;
1989 }
1990
1991 bool is_contiguous() const {
1992 //[21 Aug 2024] This is a copy from BlockUniTensor;
1993 bool out = true;
1994 for (int i = 0; i < this->_blocks.size(); i++) {
1995 out &= this->_blocks[i].is_contiguous();
1996 }
1997 return out;
1998 };
1999
2000 cytnx_uint64 Nblocks() const {
2001 //[21 Aug 2024] This is a copy from BlockUniTensor;
2002 return this->_blocks.size();
2003 };
2004
2005 std::vector<bool> signflip() const override { return this->_signflip; };
2006
2010 void reset_signflip_() { this->_signflip.assign(this->_blocks.size(), false); }
2011
2016 void erase_signflip_(const std::vector<cytnx_uint64> &positions);
2017
2018 void to_(const int &device) {
2019 //[21 Aug 2024] This is a copy from BlockUniTensor;
2020 for (cytnx_uint64 i = 0; i < this->_blocks.size(); i++) {
2021 this->_blocks[i].to_(device);
2022 }
2023 };
2024
2025 boost::intrusive_ptr<UniTensor_base> to(const int &device) {
2026 //[21 Aug 2024] This is a copy from BlockUniTensor;
2027 if (this->device() == device) {
2028 return this;
2029 } else {
2030 boost::intrusive_ptr<UniTensor_base> out = this->clone();
2031 out->to_(device);
2032 return out;
2033 }
2034 };
2035
2036 boost::intrusive_ptr<UniTensor_base> clone() const {
2037 //[21 Aug 2024] This is a copy from BlockUniTensor; changed to BlockFermionicUniTensor as
2038 // output
2039 boost::intrusive_ptr<BlockFermionicUniTensor> tmp = this->clone_meta(true, true);
2040 tmp->_blocks = vec_clone(this->_blocks);
2041 return tmp;
2042 };
2043
2044 unsigned int dtype() const {
2045 //[21 Aug 2024] This is a copy from BlockUniTensor;
2046#ifdef UNI_DEBUG
2047 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
2048 "\n");
2049#endif
2050 return this->_blocks.size() < 1 ? Type.Void : this->_blocks[0].dtype();
2051 };
2052 int device() const {
2053 //[21 Aug 2024] This is a copy from BlockUniTensor;
2054#ifdef UNI_DEBUG
2055 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
2056 "\n");
2057#endif
2058 return this->_blocks.size() < 1 ? -404 : this->_blocks[0].device();
2059 };
2060 std::string dtype_str() const {
2061 //[21 Aug 2024] This is a copy from BlockUniTensor;
2062#ifdef UNI_DEBUG
2063 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
2064 "\n");
2065#endif
2066 return this->_blocks.size() < 1 ? "Void, no valid blocks" : this->_blocks[0].dtype_str();
2067 };
2068 std::string device_str() const {
2069 //[21 Aug 2024] This is a copy from BlockUniTensor;
2070#ifdef UNI_DEBUG
2071 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
2072 "\n");
2073#endif
2074 return this->_blocks.size() < 1 ? "None, no valid blocks" : this->_blocks[0].device_str();
2075 };
2076
2077 Tensor get_block(const cytnx_uint64 &idx = 0) const {
2078 //[21 Aug 2024] This is a copy from BlockUniTensor;
2079 cytnx_error_msg(idx >= this->_blocks.size(),
2080 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2081 return this->_blocks[idx].clone();
2082 };
2083
2084 // this one for Block will return the indicies!!
2085 Tensor get_block(const std::vector<cytnx_int64> &qidx, const bool &force_return) const {
2086 //[21 Aug 2024] This is a copy from BlockUniTensor;
2087 if (this->rank() == 0) {
2088 cytnx_error_msg(!qidx.empty(),
2089 "[ERROR][get_block][BlockFermionicUniTensor] rank-0 scalar block expects "
2090 "no qidx entries.%s",
2091 "\n");
2092 cytnx_error_msg(this->_blocks.empty(),
2093 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2094 return this->_blocks[0].clone();
2095 }
2097 qidx.size() != this->rank(),
2098 "[ERROR][get_block][BlockFermionicUniTensor] len(qidx) must be the same as the "
2099 "Tensor rank (number of legs).%s",
2100 "\n");
2101
2102 std::vector<cytnx_uint64> inds(qidx.begin(), qidx.end());
2103
2104 // find the block whose qidx matches
2105 cytnx_int64 b = -1;
2106 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
2107 if (inds == this->_inner_to_outer_idx[i]) {
2108 b = i;
2109 break;
2110 }
2111 }
2112
2113 if (b < 0) {
2114 if (force_return) {
2115 return NullRefTensor;
2116 } else {
2117 cytnx_error_msg(true,
2118 "[ERROR][get_block][BlockFermionicUniTensor] no avaliable block exists, "
2119 "force_return=false, so "
2120 "error throws. \n If you want to return an empty block without "
2121 "error when block is "
2122 "not avaliable, set force_return=True.%s",
2123 "\n");
2124 }
2125 } else {
2126 return this->_blocks[b].clone();
2127 }
2128 }
2129
2130 const Tensor &get_block_(const cytnx_uint64 &idx = 0) const {
2131 //[21 Aug 2024] This is a copy from BlockUniTensor;
2132 cytnx_error_msg(idx >= this->_blocks.size(),
2133 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2134 return this->_blocks[idx];
2135 };
2136
2137 Tensor &get_block_(const cytnx_uint64 &idx = 0) {
2138 //[21 Aug 2024] This is a copy from BlockUniTensor;
2139 cytnx_error_msg(idx >= this->_blocks.size(),
2140 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2141 return this->_blocks[idx];
2142 };
2143
2144 const Tensor &get_block_(const std::vector<cytnx_int64> &qidx, const bool &force_return) const {
2145 //[21 Aug 2024] This is a copy from BlockUniTensor;
2146 if (this->rank() == 0) {
2147 cytnx_error_msg(!qidx.empty(),
2148 "[ERROR][get_block][BlockFermionicUniTensor] rank-0 scalar block expects "
2149 "no qidx entries.%s",
2150 "\n");
2151 cytnx_error_msg(this->_blocks.empty(),
2152 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2153 return this->_blocks[0];
2154 }
2156 qidx.size() != this->rank(),
2157 "[ERROR][get_block][BlockFermionicUniTensor] len(qidx) must be the same as the "
2158 "Tensor rank (number of legs).%s",
2159 "\n");
2160
2161 std::vector<cytnx_uint64> inds(qidx.begin(), qidx.end());
2162
2163 // find the block whose qidx matches
2164 cytnx_int64 b = -1;
2165 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
2166 if (inds == this->_inner_to_outer_idx[i]) {
2167 b = i;
2168 break;
2169 }
2170 }
2171
2172 if (b < 0) {
2173 if (force_return) {
2174 return this->NullRefTensor;
2175 } else {
2176 cytnx_error_msg(true,
2177 "[ERROR][get_block][BlockFermionicUniTensor] no avaliable block exists, "
2178 "force_return=false, so "
2179 "error throws. \n If you want to return an empty block without "
2180 "error when block is "
2181 "not avaliable, set force_return=True.%s",
2182 "\n");
2183 }
2184 } else {
2185 return this->_blocks[b];
2186 }
2187 }
2188
2189 Tensor &get_block_(const std::vector<cytnx_int64> &qidx, const bool &force_return) {
2190 //[21 Aug 2024] This is a copy from BlockUniTensor;
2191 if (this->rank() == 0) {
2192 cytnx_error_msg(!qidx.empty(),
2193 "[ERROR][get_block][BlockFermionicUniTensor] rank-0 scalar block expects "
2194 "no qidx entries.%s",
2195 "\n");
2196 cytnx_error_msg(this->_blocks.empty(),
2197 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2198 return this->_blocks[0];
2199 }
2201 qidx.size() != this->rank(),
2202 "[ERROR][get_block][BlockFermionicUniTensor] len(qidx) must be the same as the "
2203 "Tensor rank (number of legs).%s",
2204 "\n");
2205
2206 std::vector<cytnx_uint64> inds(qidx.begin(), qidx.end());
2207
2208 // find the block whose qidx matches
2209 cytnx_int64 b = -1;
2210 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
2211 if (inds == this->_inner_to_outer_idx[i]) {
2212 b = i;
2213 break;
2214 }
2215 }
2216
2217 if (b < 0) {
2218 if (force_return) {
2219 return this->NullRefTensor;
2220 } else {
2221 cytnx_error_msg(true,
2222 "[ERROR][get_block][BlockFermionicUniTensor] no avaliable block exists, "
2223 "force_return=false, so "
2224 "error throws. \n If you want to return an empty block without "
2225 "error when block is "
2226 "not avaliable, set force_return=True.%s",
2227 "\n");
2228 }
2229 } else {
2230 return this->_blocks[b];
2231 }
2232 }
2233
2234 std::vector<Tensor> get_blocks() const {
2235 //[21 Aug 2024] This is a copy from BlockUniTensor;
2236 return vec_clone(this->_blocks);
2237 }
2238 const std::vector<Tensor> &get_blocks_(const bool &) const {
2239 //[21 Aug 2024] This is a copy from BlockUniTensor;
2240 return this->_blocks;
2241 }
2242 std::vector<Tensor> &get_blocks_(const bool &) {
2243 //[21 Aug 2024] This is a copy from BlockUniTensor;
2244 return this->_blocks;
2245 }
2246
2247 bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const {
2248 //[21 Aug 2024] This is a copy from BlockUniTensor; changed to BlockFermionic UTenType
2249 if (rhs->uten_type() != UTenType.BlockFermionic) return false;
2250 if (rhs->get_blocks_(1).size() != this->get_blocks_(1).size()) return false;
2251
2252 for (int i = 0; i < rhs->get_blocks_(1).size(); i++)
2253 if (this->get_blocks_(1)[i].same_data(rhs->get_blocks_(1)[i]) == false) return false;
2254
2255 return true;
2256 }
2257
2258 void set_rowrank_(const cytnx_uint64 &new_rowrank) {
2259 //[21 Aug 2024] This is a copy from BlockUniTensor;
2261 new_rowrank > this->rank(),
2262 "[ERROR][BlockFermionicUniTensor] rowrank should be [>=0] and [<=UniTensor.rank].%s", "\n");
2263 if (this->is_diag()) {
2265 new_rowrank != 1,
2266 "[ERROR][BlockFermionicUniTensor] rowrank should be [==1] when is_diag =true!.%s", "\n");
2267 }
2268 this->_rowrank = new_rowrank;
2269 this->_is_braket_form = this->_update_braket();
2270 }
2271
2272 boost::intrusive_ptr<UniTensor_base> set_rowrank(const cytnx_uint64 &new_rowrank) const {
2273 //[21 Aug 2024] This is a copy from BlockUniTensor; output type changed to
2274 // BlockFermionicUniTensor
2275 boost::intrusive_ptr<BlockFermionicUniTensor> tmp = this->clone_meta(true, true);
2276 tmp->_blocks = this->_blocks;
2277 tmp->set_rowrank_(new_rowrank);
2278 return tmp;
2279 }
2280
2281 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,
2282 const cytnx_int64 &rowrank = -1);
2283 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<std::string> &mapper,
2284 const cytnx_int64 &rowrank = -1);
2285
2286 void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1) override;
2287 void permute_(const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1) override;
2288
2289 boost::intrusive_ptr<UniTensor_base> permute_nosignflip(
2290 const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1) override;
2291 boost::intrusive_ptr<UniTensor_base> permute_nosignflip(
2292 const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1) override;
2293 void permute_nosignflip_(const std::vector<cytnx_int64> &mapper,
2294 const cytnx_int64 &rowrank = -1) override;
2295 void permute_nosignflip_(const std::vector<std::string> &mapper,
2296 const cytnx_int64 &rowrank = -1) override;
2297
2298 void twist_(const cytnx_int64 &idx) override;
2299 void twist_(const std::string &label) override;
2300 void fermion_twists_() override;
2301
2302 // Helper function; implements the sign flips when permuting indices
2303 std::vector<bool> _swapsigns_(const std::vector<cytnx_int64> &mapper) const;
2304 std::vector<bool> _lhssigns_(const std::vector<cytnx_int64> &mapper,
2305 const cytnx_int64 contrno) const;
2306 std::vector<bool> _swapsigns_(const std::vector<cytnx_uint64> &mapper) const;
2307 std::vector<bool> _lhssigns_(const std::vector<cytnx_uint64> &mapper,
2308 const cytnx_uint64 contrno) const;
2309
2310 boost::intrusive_ptr<UniTensor_base> contiguous_() {
2311 //[21 Aug 2024] This is a copy from BlockUniTensor;
2312 // Rebind each block to the non-mutating Tensor::contiguous() result instead of calling
2313 // contiguous_() in place, so a block Tensor shared with another UniTensor (e.g. via
2314 // relabel()) is not corrupted (#724).
2315 for (unsigned int b = 0; b < this->_blocks.size(); b++)
2316 this->_blocks[b] = this->_blocks[b].contiguous();
2317 return boost::intrusive_ptr<UniTensor_base>(this);
2318 }
2319 boost::intrusive_ptr<UniTensor_base> contiguous();
2320
2321 boost::intrusive_ptr<UniTensor_base> apply_();
2322 boost::intrusive_ptr<UniTensor_base> apply();
2323
2324 void print_diagram(const bool &bond_info = false) const;
2325 void print_blocks(const bool &full_info = true) const;
2326 void print_block(const cytnx_int64 &idx, const bool &full_info = true) const;
2327
2328 boost::intrusive_ptr<UniTensor_base> contract(const boost::intrusive_ptr<UniTensor_base> &rhs,
2329 const bool &mv_elem_self = false,
2330 const bool &mv_elem_rhs = false);
2331
2332 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &new_labels);
2333 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &new_labels);
2334
2335 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &old_labels,
2336 const std::vector<std::string> &new_labels);
2337 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &old_labels,
2338 const std::vector<std::string> &new_labels);
2339
2340 boost::intrusive_ptr<UniTensor_base> relabel(const std::string &old_label,
2341 const std::string &new_label);
2342 boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx,
2343 const std::string &new_label);
2344 std::vector<Symmetry> syms() const;
2345
2346 void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank = 0) {
2347 cytnx_error_msg(true, "[ERROR] Cannot reshape a UniTensor with symmetry.%s", "\n");
2348 }
2349 boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape,
2350 const cytnx_uint64 &rowrank = 0) {
2351 cytnx_error_msg(true, "[ERROR] Cannot reshape a UniTensor with symmetry.%s", "\n");
2352 return nullptr;
2353 }
2354
2355 boost::intrusive_ptr<UniTensor_base> to_dense();
2356 void to_dense_();
2357
2358 boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const {
2359 //[21 Aug 2024] This is a copy from BlockUniTensor; the tensor type was adapted
2360 boost::intrusive_ptr<BlockFermionicUniTensor> tmp = this->clone_meta(true, true);
2361 tmp->_blocks.resize(this->_blocks.size());
2362 for (cytnx_int64 blk = 0; blk < this->_blocks.size(); blk++) {
2363 tmp->_blocks[blk] = this->_blocks[blk].astype(dtype);
2364 }
2365 return tmp;
2366 };
2367
2368 // this will only work on non-symm tensor (DenseUniTensor)
2369 boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors) {
2371 true,
2372 "[ERROR][BlockFermionicUniTensor][get] Cannot use get on a UniTensor with "
2373 "Symmetry.\n suggestion: try get_block/get_block_/get_blocks/get_blocks_ first.%s",
2374 "\n");
2375 return nullptr;
2376 }
2377
2378 // this will only work on non-symm tensor (DenseUniTensor)
2379 void set(const std::vector<Accessor> &accessors, const Tensor &rhs) {
2380 //[21 Aug 2024] This is a copy from BlockUniTensor;
2382 true,
2383 "[ERROR][BlockFermionicUniTensor][get] Cannot use get on a UniTensor with "
2384 "Symmetry.\n suggestion: try get_block/get_block_/get_blocks/get_blocks_ first.%s",
2385 "\n");
2386 }
2387
2388 void put_block(const Tensor &in, const cytnx_uint64 &idx = 0) {
2389 //[21 Aug 2024] This is a copy from BlockUniTensor;
2391 in.dtype() != this->dtype(),
2392 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor dtype does not match.%s",
2393 "\n");
2395 in.device() != this->device(),
2396 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor device does not "
2397 "match.%s",
2398 "\n");
2399 // We shouldn't check the contiguous
2400 // cytnx_error_msg(!in.contiguous());
2401 cytnx_error_msg(idx >= this->_blocks.size(),
2402 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2404 in.shape() != this->_blocks[idx].shape(),
2405 "[ERROR][BlockFermionicUniTensor] the shape of input tensor does not match the shape "
2406 "of block @ idx=%d\n",
2407 idx);
2408
2409 this->_blocks[idx] = in.clone();
2410 }
2411 void put_block_(Tensor &in, const cytnx_uint64 &idx = 0) {
2412 //[21 Aug 2024] This is a copy from BlockUniTensor;
2414 in.dtype() != this->dtype(),
2415 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor dtype does not match.%s",
2416 "\n");
2418 in.device() != this->device(),
2419 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor device does not "
2420 "match.%s",
2421 "\n");
2422 // We shouldn't check the contiguous
2423 // cytnx_error_msg(!in.contiguous());
2424 cytnx_error_msg(idx >= this->_blocks.size(),
2425 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2427 in.shape() != this->_blocks[idx].shape(),
2428 "[ERROR][BlockFermionicUniTensor] the shape of input tensor does not match the shape "
2429 "of block @ idx=%d\n",
2430 idx);
2431
2432 this->_blocks[idx] = in;
2433 }
2434 void put_block(const Tensor &in, const std::vector<cytnx_int64> &qidx) {
2435 //[21 Aug 2024] This is a copy from BlockUniTensor;
2437 in.dtype() != this->dtype(),
2438 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor dtype does not match.%s",
2439 "\n");
2441 in.device() != this->device(),
2442 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor device does not "
2443 "match.%s",
2444 "\n");
2445 // We shouldn't check the contiguous
2446 // cytnx_error_msg(!in.contiguous());
2448 qidx.size() != this->rank(),
2449 "[ERROR][put_block][BlockFermionicUniTensor] len(qidx) must be the same as the "
2450 "Tensor rank (number of legs).%s",
2451 "\n");
2452
2453 std::vector<cytnx_uint64> inds(qidx.begin(), qidx.end());
2454
2455 // find the block whose qidx matches
2456 cytnx_int64 b = -1;
2457 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
2458 if (inds == this->_inner_to_outer_idx[i]) {
2459 b = i;
2460 break;
2461 }
2462 }
2463
2464 if (b < 0) {
2466 true, "[ERROR][put_block][BlockFermionicUniTensor] no avaliable block exists.%s", "\n");
2467 } else {
2469 in.shape() != this->_blocks[b].shape(),
2470 "[ERROR][BlockFermionicUniTensor] the shape of input tensor does not match the shape "
2471 "of block @ idx=%d\n",
2472 b);
2473
2474 this->_blocks[b] = in.clone();
2475 }
2476 }
2477 void put_block_(Tensor &in, const std::vector<cytnx_int64> &qidx) {
2478 //[21 Aug 2024] This is a copy from BlockUniTensor;
2480 in.dtype() != this->dtype(),
2481 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor dtype does not match.%s",
2482 "\n");
2484 in.device() != this->device(),
2485 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor device does not "
2486 "match.%s",
2487 "\n");
2488 // We shouldn't check the contiguous
2489 // cytnx_error_msg(!in.contiguous());
2491 qidx.size() != this->rank(),
2492 "[ERROR][put_block][BlockFermionicUniTensor] len(qidx) must be the same as the "
2493 "Tensor rank (number of legs).%s",
2494 "\n");
2495
2496 std::vector<cytnx_uint64> inds(qidx.begin(), qidx.end());
2497
2498 // find the block whose qidx matches
2499 cytnx_int64 b = -1;
2500 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
2501 if (inds == this->_inner_to_outer_idx[i]) {
2502 b = i;
2503 break;
2504 }
2505 }
2506
2507 if (b < 0) {
2509 true, "[ERROR][put_block][BlockFermionicUniTensor] no avaliable block exists.%s", "\n");
2510 } else {
2512 in.shape() != this->_blocks[b].shape(),
2513 "[ERROR][BlockFermionicUniTensor] the shape of input tensor does not match the shape "
2514 "of block @ idx=%d\n",
2515 b);
2516 this->_blocks[b] = in;
2517 }
2518 }
2519
2520 void tag_() {
2521 // no-use!
2522 }
2523
2524 boost::intrusive_ptr<UniTensor_base> Conj() {
2525 //[21 Aug 2024] This is a copy from BlockUniTensor;
2526 boost::intrusive_ptr<UniTensor_base> out = this->clone();
2527 out->Conj_();
2528 return out;
2529 }
2530
2531 void Conj_() {
2532 //[21 Aug 2024] This is a copy from BlockUniTensor;
2533 for (int i = 0; i < this->_blocks.size(); i++) {
2534 this->_blocks[i].Conj_();
2535 }
2536 };
2537
2538 // Transpose(_) changes the index order without sign flips and reverses the bond directions for
2539 // fermionic tensors
2540 void Transpose_();
2541 boost::intrusive_ptr<UniTensor_base> Transpose() {
2542 //[21 Aug 2024] This is a copy from BlockUniTensor;
2543 boost::intrusive_ptr<UniTensor_base> out = this->clone();
2544 out->Transpose_();
2545 return out;
2546 }
2547
2548 void normalize_();
2549 boost::intrusive_ptr<UniTensor_base> normalize() {
2550 //[21 Aug 2024] This is a copy from BlockUniTensor;
2551 boost::intrusive_ptr<UniTensor_base> out = this->clone();
2552 out->normalize_();
2553 return out;
2554 }
2555
2556 boost::intrusive_ptr<UniTensor_base> Dagger() {
2557 //[21 Aug 2024] This is a copy from BlockUniTensor;
2558 boost::intrusive_ptr<UniTensor_base> out = this->Conj();
2559 out->Transpose_();
2560 return out;
2561 }
2562 void Dagger_() {
2563 //[21 Aug 2024] This is a copy from BlockUniTensor;
2564 this->Conj_();
2565 this->Transpose_();
2566 }
2567
2568 void Trace_(const std::string &a, const std::string &b);
2569 void Trace_(const cytnx_int64 &a, const cytnx_int64 &b);
2570
2571 boost::intrusive_ptr<UniTensor_base> Trace(const std::string &a, const std::string &b) {
2572 //[21 Aug 2024] This is a copy from BlockUniTensor; the tensor type was adapted
2573 boost::intrusive_ptr<UniTensor_base> out = this->clone();
2574 out->Trace_(a, b);
2575 return out;
2576 }
2577 boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b) {
2578 //[21 Aug 2024] This is a copy from BlockUniTensor; the tensor type was adapted
2579 boost::intrusive_ptr<UniTensor_base> out = this->clone();
2580 out->Trace_(a, b);
2581 return out;
2582 }
2583
2584 Tensor Norm() const;
2585
2586 bool elem_exists(const std::vector<cytnx_uint64> &locator) const;
2587
2588 const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const;
2589 const cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2590 const cytnx_complex128 &aux) const;
2591 const cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2592 const cytnx_complex64 &aux) const;
2593 const cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2594 const cytnx_double &aux) const;
2595 const cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2596 const cytnx_float &aux) const;
2597 const cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2598 const cytnx_uint64 &aux) const;
2599 const cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2600 const cytnx_int64 &aux) const;
2601 const cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2602 const cytnx_uint32 &aux) const;
2603 const cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2604 const cytnx_int32 &aux) const;
2605 const cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2606 const cytnx_uint16 &aux) const;
2607 const cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2608 const cytnx_int16 &aux) const;
2609
2610 Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator);
2611 cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2612 const cytnx_complex128 &aux);
2613 cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2614 const cytnx_complex64 &aux);
2615 cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux);
2616 cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux);
2617 cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux);
2618 cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux);
2619 cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux);
2620 cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux);
2621 cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux);
2622 cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux);
2623
2624 void _save_dispatch(std::fstream &f) const;
2625 void _load_dispatch(std::fstream &f, unsigned int version);
2626
2627 // this will remove the [q_index]-th qnum at [bond_idx]-th Bond!
2628 void truncate_(const std::string &label, const cytnx_uint64 &q_index);
2629 void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &q_index);
2630
2631 void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
2632 void Add_(const Scalar &rhs) {
2633 cytnx_error_msg(true,
2634 "[ERROR] Cannot perform elementwise arithmetic '+' between Scalar and "
2635 "BlockFermionicUniTensor.\n %s "
2636 "\n",
2637 "This operation would destroy the block structure. [Suggest] Avoid or use "
2638 "get/put_block(s) to do operation on blocks.");
2639 }
2640
2641 void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
2642 void Mul_(const Scalar &rhs);
2643
2644 void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
2645 void Sub_(const Scalar &rhs) {
2646 cytnx_error_msg(true,
2647 "[ERROR] Cannot perform elementwise arithmetic '-' between Scalar and "
2648 "BlockFermionicUniTensor.\n %s "
2649 "\n",
2650 "This operation would destroy the block structure. [Suggest] Avoid or use "
2651 "get/put_block(s) to do operation on blocks.");
2652 }
2653 void lSub_(const Scalar &lhs) {
2654 cytnx_error_msg(true,
2655 "[ERROR] Cannot perform elementwise arithmetic '-' between Scalar and "
2656 "BlockFermionicUniTensor.\n %s "
2657 "\n",
2658 "This operation would destroy the block structure. [Suggest] Avoid or use "
2659 "get/put_block(s) to do operation on blocks.");
2660 }
2661
2662 void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
2663 void Div_(const Scalar &rhs);
2664 void lDiv_(const Scalar &lhs) {
2665 cytnx_error_msg(true,
2666 "[ERROR] Cannot perform elementwise arithmetic '/' between Scalar and "
2667 "BlockFermionicUniTensor.\n %s "
2668 "\n",
2669 "This operation would cause division by zero on non-block elements. "
2670 "[Suggest] Avoid or use get/put_block(s) to do operation on blocks.");
2671 }
2672 void from_(const boost::intrusive_ptr<UniTensor_base> &rhs, bool force, cytnx_double tol = 0.);
2673
2674 void group_basis_();
2675
2676 void combineBond(const std::vector<std::string> &indicators, const bool &force = false);
2677 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force = false);
2678 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force,
2679 const bool &by_label);
2680 void combineBonds(const std::vector<std::string> &indicators, const bool &force = false);
2681
2682 const std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) const {
2683 //[21 Aug 2024] This is a copy from BlockUniTensor;
2685 bidx >= this->Nblocks(),
2686 "[ERROR][BlockFermionicUniTensor] bidx out of bound! only %d blocks in current UTen.\n",
2687 this->Nblocks());
2688 return this->_inner_to_outer_idx[bidx];
2689 }
2690 std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) {
2691 //[21 Aug 2024] This is a copy from BlockUniTensor;
2693 bidx >= this->Nblocks(),
2694 "[ERROR][BlockFermionicUniTensor] bidx out of bound! only %d blocks in current UTen.\n",
2695 this->Nblocks());
2696 return this->_inner_to_outer_idx[bidx];
2697 }
2698
2699 const vec2d<cytnx_uint64> &get_itoi() const {
2700 //[21 Aug 2024] This is a copy from BlockUniTensor;
2701 return this->_inner_to_outer_idx;
2702 }
2703 vec2d<cytnx_uint64> &get_itoi() {
2704 //[21 Aug 2024] This is a copy from BlockUniTensor;
2705 return this->_inner_to_outer_idx;
2706 }
2707
2708 void beauty_print_block(std::ostream &os, const cytnx_uint64 &Nin, const cytnx_uint64 &Nout,
2709 const std::vector<cytnx_uint64> &qn_indices,
2710 const std::vector<Bond> &bonds, const Tensor &block) const;
2711
2712 private:
2713 // additional information for fermions (#841): if true, the sign of the corresponding
2714 // block needs to be flipped. Must stay in lockstep with _blocks (one entry per block);
2715 // outside the class it can only be modified through reset_signflip_()/erase_signflip_()
2716 // above, each of which preserves that invariant.
2717 std::vector<cytnx_bool> _signflip;
2718 };
2720
2721 //======================================================================
2722
2724 class UniTensor_options {
2725 public:
2726 bool _is_diag;
2727 int _dtype;
2728 int _device;
2729 int _rowrank;
2730
2731 UniTensor_options() {
2732 this->_is_diag = false;
2733 this->_dtype = Type.Double;
2734 this->_device = Device.cpu;
2735 this->_rowrank = -1;
2736 }
2737
2738 UniTensor_options(const UniTensor_options &rhs) {
2739 this->_is_diag = rhs._is_diag;
2740 this->_dtype = rhs._dtype;
2741 this->_device = rhs._device;
2742 this->_rowrank = rhs._rowrank;
2743 }
2744
2745 UniTensor_options &operator=(const UniTensor_options &rhs) {
2746 this->_is_diag = rhs._is_diag;
2747 this->_dtype = rhs._dtype;
2748 this->_device = rhs._device;
2749 this->_rowrank = rhs._rowrank;
2750 return *this;
2751 }
2752
2753 UniTensor_options &is_diag(const bool &in) {
2754 this->_is_diag = in;
2755 return *this;
2756 }
2757 UniTensor_options &dtype(const int &in) {
2758 this->_dtype = in;
2759 return *this;
2760 }
2761 UniTensor_options &device(const int &in) {
2762 this->_device = in;
2763 return *this;
2764 }
2765 UniTensor_options &rowrank(const int &in) {
2766 this->_rowrank = in;
2767 return *this;
2768 }
2769 };
2771
2774 public:
2776 boost::intrusive_ptr<UniTensor_base> _impl;
2777 UniTensor() : _impl(new UniTensor_base()){};
2778 UniTensor(const UniTensor &rhs) { this->_impl = rhs._impl; }
2779 UniTensor &operator=(const UniTensor &rhs) {
2780 this->_impl = rhs._impl;
2781 return *this;
2782 }
2784
2786
2812 explicit UniTensor(const Tensor &in_tensor, const bool &is_diag = false,
2813 const cytnx_int64 &rowrank = -1,
2814 const std::vector<std::string> &in_labels = {}, const std::string &name = "")
2815 : _impl(new UniTensor_base()) {
2816 this->Init(in_tensor, is_diag, rowrank, in_labels, name);
2817 }
2835 void Init(const Tensor &in_tensor, const bool &is_diag = false, const cytnx_int64 &rowrank = -1,
2836 const std::vector<std::string> &in_labels = {}, const std::string &name = "") {
2837 boost::intrusive_ptr<UniTensor_base> out(new DenseUniTensor());
2838 out->Init_by_Tensor(in_tensor, is_diag, rowrank, name);
2839 this->_impl = out;
2840 if (in_labels.size() != 0) this->set_labels(in_labels);
2841 }
2843
2845
2862 UniTensor(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
2863 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
2864 const int &device = Device.cpu, const bool &is_diag = false,
2865 const std::string &name = "")
2866 : _impl(new UniTensor_base()) {
2867#ifdef UNI_DEBUG
2869 true,
2870 "[DEBUG] message: entry for UniTensor(const std::vector<Bond> &bonds, const "
2871 "std::vector<std::string> &in_labels={}, const cytnx_int64 &rowrank=-1, const unsigned "
2872 "int "
2873 "&dtype=Type.Double, const int &device = Device.cpu, const bool &is_diag=false)%s",
2874 "\n");
2875#endif
2876 this->Init(bonds, in_labels, rowrank, dtype, device, is_diag, name);
2877 }
2878
2880 /* [developing]
2881 void Init(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
2882 const UniTensor_options &UToptions = UniTensor_options(), const std::string &name =
2883 ""){ this->Init(bonds,in_labels, UToptions._rowrank, UToptions._dtype , UToptions._device ,
2884 UToptions._is_diag,
2885 name);
2886 }
2887 */
2889
2909 UniTensor &Init(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
2910 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
2911 const int &device = Device.cpu, const bool &is_diag = false,
2912 const std::string &name = "") {
2913 // checking type:
2914 bool is_sym = false;
2915 int sym_fver = -1;
2916 bool fermionic = false;
2917
2918 for (cytnx_uint64 i = 0; i < bonds.size(); i++) {
2919 // check
2920 if (bonds[i].syms().size() != 0) {
2921 is_sym = true;
2922 if (sym_fver == -1)
2923 sym_fver = bonds[i]._impl->_degs.size();
2924 else {
2925 cytnx_error_msg((bool(sym_fver) ^ bool(bonds[i]._impl->_degs.size())),
2926 "[ERROR] When initializing a UniTensor with symmetries, all Bonds must "
2927 "be in the same format!%s",
2928 "\n");
2929 }
2930 if (!fermionic) {
2931 std::vector<Symmetry> symms = bonds[i].syms();
2932 for (cytnx_uint64 i = 0; i < symms.size(); i++) {
2933 if (symms[i].is_fermionic()) fermionic = true;
2934 }
2935 }
2936 } else
2938 is_sym, "[ERROR] Cannot have bonds with mixing of symmetry and non-symmetry.%s", "\n");
2939 }
2940
2941 // dynamical dispatch:
2942 if (is_sym) {
2943#ifdef UNI_DEBUG
2944 cytnx_warning_msg(true, "[DEBUG] message: entry dispatch: UniTensor: symmetric%s", "\n");
2945#endif
2947 sym_fver < 1,
2948 "[ERROR] Symmetric tensor, but no degeneracies given. The UniTensor seems broken.%s",
2949 "\n");
2950 if (fermionic) {
2951 boost::intrusive_ptr<UniTensor_base> out(new BlockFermionicUniTensor());
2952 this->_impl = out;
2953 } else {
2954 boost::intrusive_ptr<UniTensor_base> out(new BlockUniTensor());
2955 this->_impl = out;
2956 }
2957 } else {
2958 boost::intrusive_ptr<UniTensor_base> out(new DenseUniTensor());
2959 this->_impl = out;
2960 }
2961 this->_impl->Init(bonds, in_labels, rowrank, dtype, device, is_diag, false, name);
2962 return *this;
2963 }
2964
2971 UniTensor &set_name_(const std::string &in) {
2972 this->_impl->set_name_(in);
2973 return *this;
2974 }
2975
2979 [[deprecated("Please use set_name_(const std::string &in) instead.")]] UniTensor &set_name(
2980 const std::string &in) {
2981 return this->set_name_(in);
2982 }
2983
2994 UniTensor &set_label_(const cytnx_int64 &idx, const std::string &new_label) {
2995 this->_impl->set_label_(idx, new_label);
2996 return *this;
2997 }
2998
3003 this->_impl->set_label_(idx, std::string(new_label));
3004 return *this;
3005 }
3006
3017 UniTensor &set_label_(const std::string &old_label, const std::string &new_label) {
3018 this->_impl->set_label_(old_label, new_label);
3019 return *this;
3020 }
3021
3025 UniTensor &set_label_(const char *old_label, const std::string &new_label) {
3026 this->_impl->set_label_(std::string(old_label), new_label);
3027 return *this;
3028 }
3029
3033 UniTensor &set_label_(const std::string &old_label, const char *new_label) {
3034 this->_impl->set_label_(old_label, std::string(new_label));
3035 return *this;
3036 }
3037
3041 UniTensor &set_label_(const char *old_label, const char *new_label) {
3042 this->_impl->set_label_(std::string(old_label), std::string(new_label));
3043 return *this;
3044 }
3045
3051 [[deprecated(
3052 "Please use set_label_(const cytnx_int64 &idx, const std::string &new_label) "
3053 "instead.")]] UniTensor &
3054 set_label(const cytnx_int64 &idx, const std::string &new_label) {
3055 return this->set_label_(idx, new_label);
3056 }
3057
3061 [[deprecated(
3062 "Please use set_label_(const cytnx_int64 &idx, const char *new_label) "
3063 "instead.")]] UniTensor &
3064 set_label(const cytnx_int64 &idx, const char *new_label) {
3065 return this->set_label_(idx, new_label);
3066 }
3067
3073 [[deprecated(
3074 "Please use set_label_(const std::string &old_label, const std::string "
3075 "&new_label) instead.")]] UniTensor &
3076 set_label(const std::string &old_label, const std::string &new_label) {
3077 return this->set_label_(old_label, new_label);
3078 }
3079
3083 [[deprecated(
3084 "Please use set_label_(const char *old_label, const std::string &new_label) "
3085 "instead.")]] UniTensor &
3086 set_label(const char *old_label, const std::string &new_label) {
3087 return this->set_label_(old_label, new_label);
3088 }
3089
3093 [[deprecated(
3094 "Please use set_label_(const std::string &old_label, const char *new_label) "
3095 "instead.")]] UniTensor &
3096 set_label(const std::string &old_label, const char *new_label) {
3097 return this->set_label_(old_label, new_label);
3098 }
3099
3103 [[deprecated(
3104 "Please use set_label_(const char *old_label, const char *new_label) "
3105 "instead.")]] UniTensor &
3106 set_label(const char *old_label, const char *new_label) {
3107 return this->set_label_(old_label, new_label);
3108 }
3109
3110 /*
3111 UniTensor &change_label(const cytnx_int64 &old_label, const cytnx_int64 &new_label){
3112 this->_impl->change_label(old_label,new_label);
3113 return *this;
3114 }
3115 */
3116
3122 [[deprecated(
3123 "Please use "
3124 "UniTensor &relabel_(const std::vector<std::string> &new_labels) "
3125 "instead.")]] UniTensor &
3126 set_labels(const std::vector<std::string> &new_labels) {
3127 this->_impl->set_labels(new_labels);
3128 return *this;
3129 }
3130
3136 [[deprecated(
3137 "Please use "
3138 "UniTensor &relabel_(const std::initializer_list<char *> &new_labels) "
3139 "instead.")]] UniTensor &
3140 set_labels(const std::initializer_list<char *> &new_labels) {
3141 std::vector<char *> new_lbls(new_labels);
3142 std::vector<std::string> vs(new_lbls.size());
3143 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3144 [](char *x) -> std::string { return std::string(x); });
3145
3146 this->_impl->set_labels(vs);
3147 return *this;
3148 }
3149
3157 this->_impl->set_rowrank_(new_rowrank);
3158 return *this;
3159 }
3160
3162 UniTensor out;
3163 out._impl = this->_impl->set_rowrank(new_rowrank);
3164 return out;
3165 }
3166
3167 template <class T>
3168 T &item() {
3169 if (this->is_blockform()) {
3171 !this->is_scalar(),
3172 "[ERROR] Cannot use item on a non-scalar UniTensor with Symmetry.\n suggestion: use "
3173 "get_block()/get_blocks() first.%s",
3174 "\n");
3175 return this->_impl->get_block_(0).item<T>();
3176 }
3177
3178 DenseUniTensor *tmp = static_cast<DenseUniTensor *>(this->_impl.get());
3179 return tmp->_block.item<T>();
3180 }
3181
3182 Scalar::Sproxy item() const {
3183 if (this->is_blockform()) {
3185 !this->is_scalar(),
3186 "[ERROR] Cannot use item on a non-scalar UniTensor with Symmetry.\n suggestion: use "
3187 "get_block()/get_blocks() first.%s",
3188 "\n");
3189 return this->_impl->get_block_(0).item();
3190 }
3191
3192 DenseUniTensor *tmp = static_cast<DenseUniTensor *>(this->_impl.get());
3193 return tmp->_block.item();
3194 }
3199 cytnx_uint64 Nblocks() const { return this->_impl->Nblocks(); }
3200
3205 cytnx_uint64 rank() const { return this->_impl->rank(); }
3206
3211 cytnx_uint64 rowrank() const { return this->_impl->rowrank(); }
3212
3218 unsigned int dtype() const { return this->_impl->dtype(); }
3219
3226 int uten_type() const { return this->_impl->uten_type(); }
3227
3232 bool is_void() const { return this->uten_type() == UTenType.Void; }
3233
3238 bool is_scalar() const { return !this->is_void() && this->rank() == 0; }
3239
3247 if (this->is_void()) return 0;
3248 cytnx_uint64 result = 1;
3249 for (const cytnx_uint64 extent : this->shape()) result *= extent;
3250 return result;
3251 }
3252
3256 bool is_empty() const { return !this->is_void() && this->size() == 0; }
3257
3263 int device() const { return this->_impl->device(); }
3264
3269 std::string name() const { return this->_impl->name(); }
3270
3276 std::string dtype_str() const { return this->_impl->dtype_str(); }
3277
3283 std::string device_str() const { return this->_impl->device_str(); }
3284
3290 std::string uten_type_str() const { return this->_impl->uten_type_str(); }
3291
3297 bool is_contiguous() const { return this->_impl->is_contiguous(); }
3298
3303 bool is_diag() const { return this->_impl->is_diag(); }
3304
3310 bool is_tag() const { return this->_impl->is_tag(); }
3311
3317 std::vector<Symmetry> syms() const { return this->_impl->syms(); }
3318
3325 const bool &is_braket_form() const { return this->_impl->is_braket_form(); }
3326
3331 const std::vector<std::string> &labels() const { return this->_impl->labels(); }
3338 cytnx_int64 get_index(std::string label) const { return this->_impl->get_index(label); }
3339
3344 const std::vector<Bond> &bonds() const { return this->_impl->bonds(); }
3345
3346 const Bond &bond_(const cytnx_uint64 &idx) const { return this->_impl->bond_(idx); }
3347 Bond &bond_(const cytnx_uint64 &idx) { return this->_impl->bond_(idx); }
3348
3349 const Bond &bond_(const std::string &label) const { return this->_impl->bond_(label); }
3350 Bond &bond_(const std::string &label) { return this->_impl->bond_(label); }
3351
3352 Bond bond(const cytnx_uint64 &idx) const { return this->_impl->bond_(idx).clone(); }
3353 Bond bond(const std::string &label) const { return this->_impl->bond_(label).clone(); }
3354
3359 std::vector<cytnx_uint64> shape() const { return this->_impl->shape(); }
3360
3367 std::vector<bool> signflip() const { return this->_impl->signflip(); }
3368
3374 bool is_blockform() const { return this->_impl->is_blockform(); }
3375
3382 UniTensor &to_(const int &device) {
3383 this->_impl->to_(device);
3384 return *this;
3385 }
3386
3396 UniTensor to(const int &device) const {
3397 UniTensor out;
3398 out._impl = this->_impl->to(device);
3399 return out;
3400 }
3401
3407 UniTensor out;
3408 out._impl = this->_impl->clone();
3409 return out;
3410 }
3411
3421 UniTensor &relabel_(const std::vector<std::string> &new_labels) {
3422 this->_impl->relabel_(new_labels);
3423 return *this;
3424 }
3430 [[deprecated(
3431 "Please use "
3432 "UniTensor &relabel_(const std::vector<std::string> &new_labels) "
3433 "instead.")]] UniTensor &
3434 relabels_(const std::vector<std::string> &new_labels) {
3435 this->_impl->relabels_(new_labels);
3436 return *this;
3437 }
3438
3450 UniTensor relabel(const std::vector<std::string> &new_labels) const {
3451 UniTensor out;
3452 out._impl = this->_impl->relabel(new_labels);
3453 return out;
3454 }
3460 [[deprecated(
3461 "Please use "
3462 "UniTensor relabel(const std::vector<std::string> &new_labels) const "
3463 "instead.")]] UniTensor
3464 relabels(const std::vector<std::string> &new_labels) const {
3465 UniTensor out;
3466 out._impl = this->_impl->relabels(new_labels);
3467 return out;
3468 }
3469
3474 UniTensor relabel(const std::initializer_list<char *> &new_labels) const {
3475 std::vector<char *> new_lbls(new_labels);
3476 std::vector<std::string> vs(new_lbls.size());
3477 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3478 [](char *x) -> std::string { return std::string(x); });
3479
3480 UniTensor out;
3481 out._impl = this->_impl->relabel(vs);
3482 return out;
3483 }
3489 [[deprecated(
3490 "Please use "
3491 "UniTensor relabel(const std::initializer_list<char *> &new_labels) const "
3492 "instead.")]] UniTensor
3493 relabels(const std::initializer_list<char *> &new_labels) const {
3494 std::vector<char *> new_lbls(new_labels);
3495 std::vector<std::string> vs(new_lbls.size());
3496 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3497 [](char *x) -> std::string { return std::string(x); });
3498
3499 UniTensor out;
3500 out._impl = this->_impl->relabels(vs);
3501 return out;
3502 }
3506 UniTensor &relabel_(const std::initializer_list<char *> &new_labels) {
3507 std::vector<char *> new_lbls(new_labels);
3508 std::vector<std::string> vs(new_lbls.size());
3509 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3510 [](char *x) -> std::string { return std::string(x); });
3511
3512 this->_impl->relabel_(vs);
3513 return *this;
3514 }
3520 [[deprecated(
3521 "Please use "
3522 "UniTensor &relabel_(const std::initializer_list<char *> &new_labels) "
3523 "instead.")]] UniTensor &
3524 relabels_(const std::initializer_list<char *> &new_labels) {
3525 std::vector<char *> new_lbls(new_labels);
3526 std::vector<std::string> vs(new_lbls.size());
3527 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3528 [](char *x) -> std::string { return std::string(x); });
3529
3530 this->_impl->relabels_(vs);
3531 return *this;
3532 }
3533
3541 UniTensor relabel(const std::vector<std::string> &old_labels,
3542 const std::vector<std::string> &new_labels) const {
3543 UniTensor out;
3544 out._impl = this->_impl->relabel(old_labels, new_labels);
3545 return out;
3546 }
3552 [[deprecated(
3553 "Please use "
3554 "UniTensor relabel(const std::vector<std::string> &old_labels, const "
3555 "std::vector<std::string> &new_labels) const "
3556 "instead.")]] UniTensor
3557 relabels(const std::vector<std::string> &old_labels,
3558 const std::vector<std::string> &new_labels) const {
3559 UniTensor out;
3560 out._impl = this->_impl->relabels(old_labels, new_labels);
3561 return out;
3562 }
3563
3579 UniTensor &relabel_(const std::vector<std::string> &old_labels,
3580 const std::vector<std::string> &new_labels) {
3581 this->_impl->relabel_(old_labels, new_labels);
3582 return *this;
3583 }
3589 [[deprecated(
3590 "Please use "
3591 "UniTensor &relabel_(const std::vector<std::string> &old_labels, const "
3592 "std::vector<std::string> &new_labels) "
3593 "instead.")]] UniTensor &
3594 relabels_(const std::vector<std::string> &old_labels,
3595 const std::vector<std::string> &new_labels) {
3596 this->_impl->relabels_(old_labels, new_labels);
3597 return *this;
3598 }
3599
3604 UniTensor relabel(const std::initializer_list<char *> &old_labels,
3605 const std::initializer_list<char *> &new_labels) const {
3606 std::vector<char *> new_lbls(new_labels);
3607 std::vector<std::string> vs(new_lbls.size());
3608 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3609 [](char *x) -> std::string { return std::string(x); });
3610
3611 std::vector<char *> old_lbls(old_labels);
3612 std::vector<std::string> vs_old(old_lbls.size());
3613 transform(old_lbls.begin(), old_lbls.end(), vs_old.begin(),
3614 [](char *x) -> std::string { return std::string(x); });
3615
3616 return this->relabel(vs_old, vs);
3617 }
3618
3624 [[deprecated(
3625 "Please use "
3626 "UniTensor relabel(const std::initializer_list<char *> &old_labels, const "
3627 "std::initializer_list<char *> &new_labels) const "
3628 "instead.")]] UniTensor
3629 relabels(const std::initializer_list<char *> &old_labels,
3630 const std::initializer_list<char *> &new_labels) const {
3631 std::vector<char *> new_lbls(new_labels);
3632 std::vector<std::string> vs(new_lbls.size());
3633 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3634 [](char *x) -> std::string { return std::string(x); });
3635
3636 std::vector<char *> old_lbls(old_labels);
3637 std::vector<std::string> vs_old(old_lbls.size());
3638 transform(old_lbls.begin(), old_lbls.end(), vs_old.begin(),
3639 [](char *x) -> std::string { return std::string(x); });
3640
3641 return this->relabels(vs_old, vs);
3642 }
3643
3648 UniTensor &relabel_(const std::initializer_list<char *> &old_labels,
3649 const std::initializer_list<char *> &new_labels) {
3650 std::vector<char *> new_lbls(new_labels);
3651 std::vector<std::string> vs(new_lbls.size());
3652 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3653 [](char *x) -> std::string { return std::string(x); });
3654
3655 std::vector<char *> old_lbls(old_labels);
3656 std::vector<std::string> vs_old(old_lbls.size());
3657 transform(old_lbls.begin(), old_lbls.end(), vs_old.begin(),
3658 [](char *x) -> std::string { return std::string(x); });
3659
3660 this->relabel_(vs_old, vs);
3661 return *this;
3662 }
3668 [[deprecated(
3669 "Please use "
3670 "UniTensor &relabel_(const std::initializer_list<char *> &old_labels, const "
3671 "std::initializer_list<char *> &new_labels) "
3672 "instead.")]] UniTensor &
3673 relabels_(const std::initializer_list<char *> &old_labels,
3674 const std::initializer_list<char *> &new_labels) {
3675 std::vector<char *> new_lbls(new_labels);
3676 std::vector<std::string> vs(new_lbls.size());
3677 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3678 [](char *x) -> std::string { return std::string(x); });
3679
3680 std::vector<char *> old_lbls(old_labels);
3681 std::vector<std::string> vs_old(old_lbls.size());
3682 transform(old_lbls.begin(), old_lbls.end(), vs_old.begin(),
3683 [](char *x) -> std::string { return std::string(x); });
3684
3685 this->relabels_(vs_old, vs);
3686 return *this;
3687 }
3688
3703 UniTensor relabel(const cytnx_int64 &inx, const std::string &new_label) const {
3704 UniTensor out;
3705 out._impl = this->_impl->relabel(inx, new_label);
3706 return out;
3707 }
3716 UniTensor &relabel_(const cytnx_int64 &inx, const std::string &new_label) {
3717 this->_impl->relabel_(inx, new_label);
3718 return *this;
3719 }
3720
3729 UniTensor &relabel_(const std::string &old_label, const std::string &new_label) {
3730 this->_impl->relabel_(old_label, new_label);
3731 return *this;
3732 }
3733
3748 UniTensor relabel(const std::string &old_label, const std::string &new_label) const {
3749 UniTensor out;
3750 out._impl = this->_impl->relabel(old_label, new_label);
3751 return out;
3752 }
3753
3760 UniTensor astype(const unsigned int &dtype) const {
3761 UniTensor out;
3762 if (this->dtype() == dtype) {
3763 out._impl = this->_impl;
3764 } else {
3765 out._impl = this->_impl->astype(dtype);
3766 }
3767 return out;
3768 }
3769
3778 UniTensor permute(const std::vector<cytnx_int64> &mapper,
3779 const cytnx_int64 &rowrank = -1) const {
3780 UniTensor out;
3781 out._impl = this->_impl->permute(mapper, rowrank);
3782 return out;
3783 }
3784
3791 UniTensor permute(const std::vector<std::string> &mapper,
3792 const cytnx_int64 &rowrank = -1) const {
3793 UniTensor out;
3794 out._impl = this->_impl->permute(mapper, rowrank);
3795 return out;
3796 }
3797
3803 UniTensor permute(const std::initializer_list<char *> &mapper,
3804 const cytnx_int64 &rowrank = -1) const {
3805 std::vector<char *> mprs = mapper;
3806 std::vector<std::string> vs(mprs.size());
3807 transform(mprs.begin(), mprs.end(), vs.begin(),
3808 [](char *x) -> std::string { return std::string(x); });
3809
3810 return this->permute(vs, rowrank);
3811 }
3812
3820 UniTensor &permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1) {
3821 this->_impl->permute_(mapper, rowrank);
3822 return *this;
3823 }
3824
3831 UniTensor &permute_(const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1) {
3832 this->_impl->permute_(mapper, rowrank);
3833 return *this;
3834 }
3835
3849 UniTensor permute_nosignflip(const std::vector<cytnx_int64> &mapper,
3850 const cytnx_int64 &rowrank = -1) const {
3851 UniTensor out;
3852 out._impl = this->_impl->permute_nosignflip(mapper, rowrank);
3853 return out;
3854 }
3855
3867 UniTensor permute_nosignflip(const std::vector<std::string> &mapper,
3868 const cytnx_int64 &rowrank = -1) const {
3869 UniTensor out;
3870 out._impl = this->_impl->permute_nosignflip(mapper, rowrank);
3871 return out;
3872 }
3873
3879 UniTensor permute_nosignflip(const std::initializer_list<const char *> &mapper,
3880 const cytnx_int64 &rowrank = -1) const {
3881 std::vector<const char *> mprs = mapper;
3882 std::vector<std::string> vs(mprs.size());
3883 transform(mprs.begin(), mprs.end(), vs.begin(),
3884 [](const char *x) -> std::string { return std::string(x); });
3885
3886 return this->permute_nosignflip(vs, rowrank);
3887 }
3888
3901 UniTensor &permute_nosignflip_(const std::vector<cytnx_int64> &mapper,
3902 const cytnx_int64 &rowrank = -1) {
3903 this->_impl->permute_nosignflip_(mapper, rowrank);
3904 return *this;
3905 }
3906
3918 UniTensor &permute_nosignflip_(const std::vector<std::string> &mapper,
3919 const cytnx_int64 &rowrank = -1) {
3920 this->_impl->permute_nosignflip_(mapper, rowrank);
3921 return *this;
3922 }
3923
3932 UniTensor twist(const std::string &label) const {
3933 UniTensor out = this->clone();
3934 out._impl->twist_(label);
3935 return out;
3936 }
3946 UniTensor out = this->clone();
3947 out._impl->twist_(idx);
3948 return out;
3949 }
3955 UniTensor &twist_(const std::string &label) {
3956 this->_impl->twist_(label);
3957 return *this;
3958 }
3965 this->_impl->twist_(idx);
3966 return *this;
3967 }
3968
3984 UniTensor out = this->clone();
3985 out._impl->fermion_twists_();
3986 return out;
3987 }
3994 this->_impl->fermion_twists_();
3995 return *this;
3996 }
3997
4005 UniTensor out;
4006 out._impl = this->_impl->contiguous();
4007 return out;
4008 }
4009
4015 this->_impl = this->_impl->contiguous_();
4016 return *this;
4017 }
4018
4028 UniTensor out;
4029 out._impl = this->_impl->apply();
4030 return out;
4031 }
4032
4039 this->_impl = this->_impl->apply_();
4040 return *this;
4041 }
4042
4047 void print_diagram(const bool &bond_info = false) const {
4048 this->_impl->print_diagram(bond_info);
4049 }
4050
4055 void print_blocks(const bool &full_info = true) const { this->_impl->print_blocks(full_info); }
4056
4062 void print_block(const cytnx_int64 &idx, const bool &full_info = true) const {
4063 this->_impl->print_block(idx, full_info);
4064 }
4065
4073 this->_impl->group_basis_();
4074 return *this;
4075 }
4076
4078 UniTensor out = this->clone();
4079 out.group_basis_();
4080 return out;
4081 }
4082
4091 template <class T>
4092 T &at(const std::vector<cytnx_uint64> &locator) {
4093 if (this->uten_type() == UTenType.Block || this->uten_type() == UTenType.BlockFermionic) {
4094 // [NEW] this will not check if it exists, if it is not then error will throw!
4095 T aux;
4096 return this->_impl->at_for_sparse(locator, aux);
4097 } else if (this->uten_type() == UTenType.Dense) {
4098 return this->get_block_().at<T>(locator);
4099 } else {
4100 cytnx_error_msg(this->uten_type() == UTenType.Void,
4101 "[ERROR] UniTensor is not initialized and of type Void.%s", "\n");
4103 this->uten_type() == UTenType.Sparse,
4104 "[ERROR] SparseUniTensor is deprecated. Use BlockUniTensor or LinOp instead.%s", "\n");
4105 cytnx_error_msg(true, "[ERROR] UniTensor type '%s' not supported\n",
4106 this->uten_type_str().c_str());
4107 }
4108 }
4109
4118 template <class T>
4119 const T &at(const std::vector<cytnx_uint64> &locator) const {
4120 if (this->uten_type() == UTenType.Block || this->uten_type() == UTenType.BlockFermionic) {
4121 // [NEW] this will not check if it exists, if it is not then error will throw!
4122 T aux;
4123 return this->_impl->at_for_sparse(locator, aux);
4124 } else if (this->uten_type() == UTenType.Dense) {
4125 return this->get_block_().at<T>(locator);
4126 } else {
4127 cytnx_error_msg(this->uten_type() == UTenType.Void,
4128 "[ERROR] UniTensor is not initialized and of type Void.%s", "\n");
4130 this->uten_type() == UTenType.Sparse,
4131 "[ERROR] SparseUniTensor is deprecated. Use BlockUniTensor or LinOp instead.%s", "\n");
4132 cytnx_error_msg(true, "[ERROR] UniTensor type '%s' not supported\n",
4133 this->uten_type_str().c_str());
4134 }
4135 }
4136
4137 template <class T>
4138 const T &at(const std::vector<std::string> &labels,
4139 const std::vector<cytnx_uint64> &locator) const {
4140 // giving label <-> locator one to one corresponding, return the element:
4141 cytnx_error_msg(locator.size() != labels.size(),
4142 "[ERROR][at] length of list should be the same for label and locator.%s",
4143 "\n");
4145 labels.size() != this->rank(),
4146 "[ERROR][at] length of lists must be the same as UniTensor.rank (# of legs)%s", "\n");
4147 std::vector<cytnx_uint64> new_locator(this->rank());
4149 for (int i = 0; i < labels.size(); i++) {
4150 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
4151 cytnx_error_msg(res == this->_impl->_labels.end(),
4152 "[ERROR] label:%s does not exist in current UniTensor.\n",
4153 labels[i].c_str());
4154 new_loc = std::distance(this->_impl->_labels.begin(), res);
4156 }
4157 return this->at<T>(new_locator);
4158 }
4159 template <class T>
4160 T &at(const std::vector<std::string> &labels, const std::vector<cytnx_uint64> &locator) {
4161 // giving label <-> locator one to one corresponding, return the element:
4162 cytnx_error_msg(locator.size() != labels.size(),
4163 "[ERROR][at] length of list should be the same for label and locator.%s",
4164 "\n");
4166 labels.size() != this->rank(),
4167 "[ERROR][at] length of lists must be the same as UniTensor.rank (# of legs)%s", "\n");
4168 std::vector<cytnx_uint64> new_locator(this->rank());
4170 for (int i = 0; i < labels.size(); i++) {
4171 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
4172 cytnx_error_msg(res == this->_impl->_labels.end(),
4173 "[ERROR] label:%s does not exist in current UniTensor.\n",
4174 labels[i].c_str());
4175 new_loc = std::distance(this->_impl->_labels.begin(), res);
4177 }
4178 return this->at<T>(new_locator);
4179 }
4180
4188 const Scalar::Sproxy at(const std::vector<cytnx_uint64> &locator) const {
4189 if (this->uten_type() == UTenType.Block || this->uten_type() == UTenType.BlockFermionic) {
4190 return this->_impl->at_for_sparse(locator);
4191 } else if (this->uten_type() == UTenType.Dense) {
4192 return this->get_block_().at(locator);
4193 } else {
4194 cytnx_error_msg(this->uten_type() == UTenType.Void,
4195 "[ERROR] UniTensor is not initialized and of type Void.%s", "\n");
4197 this->uten_type() == UTenType.Sparse,
4198 "[ERROR] SparseUniTensor is deprecated. Use BlockUniTensor or LinOp instead.%s", "\n");
4199 cytnx_error_msg(true, "[ERROR] UniTensor type '%s' not supported\n",
4200 this->uten_type_str().c_str());
4201 }
4202 }
4203
4211 Scalar::Sproxy at(const std::vector<cytnx_uint64> &locator) {
4212 if (this->uten_type() == UTenType.Block || this->uten_type() == UTenType.BlockFermionic) {
4213 return this->_impl->at_for_sparse(locator);
4214 } else if (this->uten_type() == UTenType.Dense) {
4215 return this->get_block_().at(locator);
4216 } else {
4217 cytnx_error_msg(this->uten_type() == UTenType.Void,
4218 "[ERROR] UniTensor is not initialized and of type Void.%s", "\n");
4220 this->uten_type() == UTenType.Sparse,
4221 "[ERROR] SparseUniTensor is deprecated. Use BlockUniTensor or LinOp instead.%s", "\n");
4222 cytnx_error_msg(true, "[ERROR] UniTensor type '%s' not supported\n",
4223 this->uten_type_str().c_str());
4224 }
4225 }
4226
4227 Scalar::Sproxy at(const std::vector<std::string> &labels,
4228 const std::vector<cytnx_uint64> &locator) {
4229 // giving label <-> locator one to one corresponding, return the element:
4230 cytnx_error_msg(locator.size() != labels.size(),
4231 "[ERROR][at] length of list should be the same for label and locator.%s",
4232 "\n");
4234 labels.size() != this->rank(),
4235 "[ERROR][at] length of lists must be the same as UniTensor.rank (# of legs)%s", "\n");
4236 std::vector<cytnx_uint64> new_locator(this->rank());
4238 for (int i = 0; i < labels.size(); i++) {
4239 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
4240 cytnx_error_msg(res == this->_impl->_labels.end(),
4241 "[ERROR] label:%s does not exist in current UniTensor.\n",
4242 labels[i].c_str());
4243 new_loc = std::distance(this->_impl->_labels.begin(), res);
4245 }
4246 return this->at(new_locator);
4247 }
4248
4249 const Scalar::Sproxy at(const std::vector<std::string> &labels,
4250 const std::vector<cytnx_uint64> &locator) const {
4251 // giving label <-> locator one to one corresponding, return the element:
4252 cytnx_error_msg(locator.size() != labels.size(),
4253 "[ERROR][at] length of list should be the same for label and locator.%s",
4254 "\n");
4256 labels.size() != this->rank(),
4257 "[ERROR][at] length of lists must be the same as UniTensor.rank (# of legs)%s", "\n");
4258 std::vector<cytnx_uint64> new_locator(this->rank());
4260 for (int i = 0; i < labels.size(); i++) {
4261 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
4262 cytnx_error_msg(res == this->_impl->_labels.end(),
4263 "[ERROR] label:%s does not exist in current UniTensor.\n",
4264 labels[i].c_str());
4265 new_loc = std::distance(this->_impl->_labels.begin(), res);
4267 }
4268 return this->at(new_locator);
4269 }
4270
4271 // return a copy of the block with the given block index
4280 Tensor get_block(const cytnx_uint64 &idx = 0) const { return this->_impl->get_block(idx); };
4281 //================================
4282 // return a clone of block
4294 Tensor get_block(const std::vector<cytnx_int64> &qidx, const bool &force = false) const {
4295 return this->_impl->get_block(qidx, force);
4296 }
4297
4298 Tensor get_block(const std::vector<std::string> &labels, const std::vector<cytnx_int64> &qidx,
4299 const bool &force = false) const {
4301 labels.size() != qidx.size(),
4302 "[ERROR][get_block] length of lists must be the same for both labels and qidx%s", "\n");
4303 cytnx_error_msg(labels.size() != this->rank(),
4304 "[ERROR][get_block] length of lists must be the rank (# of legs)%s", "\n");
4305
4306 std::vector<cytnx_int64> loc_id(this->rank());
4307 std::vector<cytnx_int64> new_qidx(this->rank());
4308
4310 std::vector<cytnx_uint64> new_order(this->rank());
4311 for (int i = 0; i < labels.size(); i++) {
4312 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
4313 cytnx_error_msg(res == this->_impl->_labels.end(),
4314 "[ERROR][get_block] label:%s does not exists in current Tensor.\n",
4315 labels[i].c_str());
4316 new_loc = std::distance(this->_impl->_labels.begin(), res);
4317 new_qidx[new_loc] = qidx[i];
4318 new_order[i] = new_loc;
4319 }
4320 auto out = this->_impl->get_block(new_qidx, force);
4321 if (out.dtype() != Type.Void) out.permute_(new_order);
4322 return out;
4323 }
4324
4329 Tensor get_block(const std::initializer_list<cytnx_int64> &qidx,
4330 const bool &force = false) const {
4331 std::vector<cytnx_int64> tmp = qidx;
4332 return get_block(tmp, force);
4333 }
4334
4339 Tensor get_block(const std::vector<cytnx_uint64> &qidx, const bool &force = false) const {
4340 std::vector<cytnx_int64> iqidx(qidx.begin(), qidx.end());
4341 return this->_impl->get_block(iqidx, force);
4342 }
4343
4344 Tensor get_block(const std::vector<std::string> &labels, const std::vector<cytnx_uint64> &qidx,
4345 const bool &force = false) const {
4346 std::vector<cytnx_int64> iqidx(qidx.begin(), qidx.end());
4347 return this->get_block(labels, iqidx, force);
4348 }
4349
4358 const Tensor &get_block_(const cytnx_uint64 &idx = 0) const {
4359 return this->_impl->get_block_(idx);
4360 }
4361
4366 Tensor &get_block_(const cytnx_uint64 &idx = 0) { return this->_impl->get_block_(idx); }
4367
4379 Tensor &get_block_(const std::vector<cytnx_int64> &qidx, const bool &force = false) {
4380 return this->_impl->get_block_(qidx, force);
4381 }
4382
4399 // developer note: Tensor is not the same object (Thus Tensor instead of Tensor& ),
4400 // since we permute! but they have shared data memory.
4401 Tensor get_block_(const std::vector<std::string> &labels, const std::vector<cytnx_int64> &qidx,
4402 const bool &force = false) {
4404 labels.size() != qidx.size(),
4405 "[ERROR][get_block] length of lists must be the same for both labels and qidx%s", "\n");
4406 cytnx_error_msg(labels.size() != this->rank(),
4407 "[ERROR][get_block] length of lists must be the rank (# of legs)%s", "\n");
4408
4409 std::vector<cytnx_int64> loc_id(this->rank());
4410 std::vector<cytnx_int64> new_qidx(this->rank());
4411
4413 std::vector<cytnx_uint64> new_order(this->rank());
4414 for (int i = 0; i < labels.size(); i++) {
4415 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
4416 cytnx_error_msg(res == this->_impl->_labels.end(),
4417 "[ERROR][get_block] label:%s does not exists in current Tensor.\n",
4418 labels[i].c_str());
4419 new_loc = std::distance(this->_impl->_labels.begin(), res);
4420 new_qidx[new_loc] = qidx[i];
4421 new_order[i] = new_loc;
4422 }
4423 auto out = this->_impl->get_block_(new_qidx, force);
4424 if (out.dtype() != Type.Void) {
4425 out = out.permute(new_order);
4426 }
4427 return out;
4428 }
4429
4433 Tensor &get_block_(const std::initializer_list<cytnx_int64> &qidx, const bool &force = false) {
4434 std::vector<cytnx_int64> tmp = qidx;
4435 return get_block_(tmp, force);
4436 }
4437
4441 Tensor &get_block_(const std::vector<cytnx_uint64> &qidx, const bool &force = false) {
4442 std::vector<cytnx_int64> iqidx(qidx.begin(), qidx.end());
4443 return get_block_(iqidx, force);
4444 }
4445
4446 Tensor get_block_(const std::vector<std::string> &labels, const std::vector<cytnx_uint64> &qidx,
4447 const bool &force = false) {
4448 std::vector<cytnx_int64> iqidx(qidx.begin(), qidx.end());
4449 return get_block_(labels, iqidx, force);
4450 }
4451 //================================
4452
4453 // this only work for non-symm tensor. return a shared view of block
4457 const Tensor &get_block_(const std::vector<cytnx_int64> &qidx,
4458 const bool &force = false) const {
4459 return this->_impl->get_block_(qidx, force);
4460 }
4461
4465 const Tensor &get_block_(const std::initializer_list<cytnx_int64> &qidx,
4466 const bool &force = false) const {
4467 std::vector<cytnx_int64> tmp = qidx;
4468 return this->_impl->get_block_(tmp, force);
4469 }
4470
4474 const Tensor &get_block_(const std::vector<cytnx_uint64> &qidx,
4475 const bool &force = false) const {
4476 std::vector<cytnx_int64> iqidx(qidx.begin(), qidx.end());
4477 return get_block_(iqidx, force);
4478 }
4479
4480 //================================
4492 //[dev]
4493 std::vector<Tensor> get_blocks() const { return this->_impl->get_blocks(); }
4494
4503 //[dev]
4504 const std::vector<Tensor> &get_blocks_(const bool &silent = false) const {
4505 return this->_impl->get_blocks_(silent);
4506 }
4507
4511 //[dev]
4512 std::vector<Tensor> &get_blocks_(const bool &silent = false) {
4513 return this->_impl->get_blocks_(silent);
4514 }
4515
4526 this->_impl->put_block(in, idx);
4527 return *this;
4528 }
4529
4535 [[deprecated(
4536 "Please use "
4537 "UniTensor &put_block(const Tensor &in, const cytnx_uint64 &idx) "
4538 "instead.")]] UniTensor &
4539 put_block(const Tensor &in, const cytnx_uint64 &idx, const bool &force) {
4540 this->_impl->put_block(in, idx);
4541 return *this;
4542 }
4543
4553 UniTensor &put_block(const Tensor &in_tens, const std::vector<cytnx_int64> &qidx) {
4554 this->_impl->put_block(in_tens, qidx);
4555 return *this;
4556 }
4557
4563 [[deprecated(
4564 "Please use "
4565 "UniTensor &put_block(const Tensor &in_tens, const std::vector<cytnx_int64> &qidx) "
4566 "instead.")]] UniTensor &
4567 put_block(const Tensor &in_tens, const std::vector<cytnx_int64> &qidx, const bool &force) {
4568 this->_impl->put_block(in_tens, qidx);
4569 return *this;
4570 }
4571
4580 UniTensor &put_block(Tensor &in, const std::vector<std::string> &lbls,
4581 const std::vector<cytnx_int64> &qidx) {
4583 lbls.size() != qidx.size(),
4584 "[ERROR][put_block] length of lists must be the same for both labels and qidx%s", "\n");
4585 cytnx_error_msg(lbls.size() != this->rank(),
4586 "[ERROR][put_block] length of lists must be the rank (# of legs)%s", "\n");
4587
4588 std::vector<cytnx_int64> loc_id(this->rank());
4589 std::vector<cytnx_int64> new_qidx(this->rank());
4590
4592 // std::vector<cytnx_uint64> new_order(this->rank());
4593 std::vector<cytnx_uint64> inv_order(this->rank());
4594 for (int i = 0; i < lbls.size(); i++) {
4595 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), lbls[i]);
4596 cytnx_error_msg(res == this->_impl->_labels.end(),
4597 "[ERROR][put_block] label:%s does not exists in current Tensor.\n",
4598 lbls[i].c_str());
4599 new_loc = std::distance(this->_impl->_labels.begin(), res);
4600 new_qidx[new_loc] = qidx[i];
4601 // new_order[i] = new_loc;
4602 inv_order[new_loc] = i;
4603 }
4604 this->_impl->put_block(in.permute(inv_order), new_qidx);
4605 return *this;
4606 }
4607
4613 [[deprecated(
4614 "Please use "
4615 "UniTensor &put_block(Tensor &in, const std::vector<std::string> &lbls, const "
4616 "std::vector<cytnx_int64> &qidx) "
4617 "instead.")]] UniTensor &
4618 put_block(Tensor &in, const std::vector<std::string> &lbls,
4619 const std::vector<cytnx_int64> &qidx, const bool &force) {
4620 return put_block(in, lbls, qidx);
4621 }
4622
4633 this->_impl->put_block_(in, idx);
4634 return *this;
4635 }
4636
4646 UniTensor &put_block_(Tensor &in, const std::vector<cytnx_int64> &qidx) {
4647 this->_impl->put_block_(in, qidx);
4648 return *this;
4649 }
4650
4656 [[deprecated(
4657 "Please use "
4658 "UniTensor &put_block_(Tensor &in, const std::vector<cytnx_int64> &qidx) "
4659 "instead.")]] UniTensor &
4660 put_block_(Tensor &in, const std::vector<cytnx_int64> &qidx, const bool &force) {
4661 this->_impl->put_block_(in, qidx);
4662 return *this;
4663 }
4664
4673 UniTensor &put_block_(Tensor &in, const std::vector<std::string> &lbls,
4674 const std::vector<cytnx_int64> &qidx) {
4676 lbls.size() != qidx.size(),
4677 "[ERROR][put_block_] length of lists must be the same for both labels and qidx%s", "\n");
4678 cytnx_error_msg(lbls.size() != this->rank(),
4679 "[ERROR][put_block_] length of lists must be the rank (# of legs)%s", "\n");
4680
4681 std::vector<cytnx_int64> loc_id(this->rank());
4682 std::vector<cytnx_int64> new_qidx(this->rank());
4683
4685 std::vector<cytnx_uint64> new_order(this->rank());
4686 std::vector<cytnx_uint64> inv_order(this->rank());
4687 for (int i = 0; i < lbls.size(); i++) {
4688 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), lbls[i]);
4689 cytnx_error_msg(res == this->_impl->_labels.end(),
4690 "[ERROR][put_block_] label:%s does not exists in current Tensor.\n",
4691 lbls[i].c_str());
4692 new_loc = std::distance(this->_impl->_labels.begin(), res);
4693 new_qidx[new_loc] = qidx[i];
4694 new_order[i] = new_loc;
4695 inv_order[new_loc] = i;
4696 }
4697 in.permute_(inv_order);
4698 this->_impl->put_block_(in, new_qidx);
4699 in.permute_(new_order);
4700 return *this;
4701 }
4702
4708 [[deprecated(
4709 "Please use "
4710 "UniTensor &put_block_(Tensor &in, const std::vector<std::string> &lbls, const "
4711 "std::vector<cytnx_int64> &qidx) "
4712 "instead.")]] UniTensor &
4713 put_block_(Tensor &in, const std::vector<std::string> &lbls,
4714 const std::vector<cytnx_int64> &qidx, const bool &force) {
4715 return put_block_(in, lbls, qidx);
4716 }
4717
4733 UniTensor get(const std::vector<Accessor> &accessors) const {
4734 UniTensor out;
4735 out._impl = this->_impl->get(accessors);
4736 return out;
4737 }
4738
4743 UniTensor operator[](const std::vector<cytnx::Accessor> &accessors) const {
4744 UniTensor out;
4745 out._impl = this->_impl->get(accessors);
4746 return out;
4747 }
4748 UniTensor operator[](const std::initializer_list<cytnx::Accessor> &accessors) const {
4749 std::vector<cytnx::Accessor> acc_in = accessors;
4750 return this->get(acc_in);
4751 }
4752 UniTensor operator[](const std::vector<cytnx_int64> &accessors) const {
4753 std::vector<cytnx::Accessor> acc_in;
4754 for (cytnx_int64 i = 0; i < accessors.size(); i++) {
4755 acc_in.push_back(cytnx::Accessor(accessors[i]));
4756 }
4757 return this->get(acc_in);
4758 }
4759 UniTensor operator[](const std::initializer_list<cytnx_int64> &accessors) const {
4760 std::vector<cytnx_int64> acc_in = accessors;
4761 return (*this)[acc_in];
4762 }
4763
4780 UniTensor &set(const std::vector<Accessor> &accessors, const Tensor &rhs) {
4781 this->_impl->set(accessors, rhs);
4782 return *this;
4783 }
4784 UniTensor &set(const std::vector<Accessor> &accessors, const UniTensor &rhs) {
4786 rhs.uten_type() != UTenType.Dense,
4787 "[ERROR] Cannot set elements from UniTensor with symmetry. Use at() instead.%s", "\n");
4788 cytnx_error_msg(this->is_diag(), "[ERROR] Cannot set UniTensor with is_diag=True.%s", "\n");
4790 "[ERROR] Cannot set UniTensor. incoming UniTensor is_diag=True.%s", "\n");
4791
4792 this->_impl->set(accessors, rhs.get_block());
4793 return *this;
4794 }
4795
4803 UniTensor reshape(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank = 0) {
4804 UniTensor out;
4805 out._impl = this->_impl->reshape(new_shape, rowrank);
4806 return out;
4807 }
4808
4815 UniTensor &reshape_(const std::vector<cytnx_int64> &new_shape,
4816 const cytnx_uint64 &rowrank = 0) {
4817 this->_impl->reshape_(new_shape, rowrank);
4818 return *this;
4819 }
4820
4832 UniTensor out;
4833 out._impl = this->_impl->to_dense();
4834 return out;
4835 }
4836
4842 this->_impl->to_dense_();
4843 return *this;
4844 }
4845
4851 [[deprecated(
4852 "Please use "
4853 "combineBond_(const std::vector<std::string> &indicators, const bool &force) "
4854 "instead.")]] void
4855 combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force,
4856 const bool &by_label) {
4857 this->_impl->combineBonds(indicators, force, by_label);
4858 }
4859
4865 [[deprecated(
4866 "Please use "
4867 "combineBond_(const std::vector<std::string> &indicators, const bool &force) "
4868 "instead.")]] void
4869 combineBonds(const std::vector<std::string> &indicators, const bool &force = false) {
4870 this->_impl->combineBonds(indicators, force);
4871 }
4872
4878 [[deprecated(
4879 "Please use "
4880 "combineBond_(const std::vector<std::string> &indicators, const bool &force) "
4881 "instead.")]] void
4882 combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force = false) {
4883 this->_impl->combineBonds(indicators, force);
4884 }
4885
4898 UniTensor &combineBond_(const std::vector<std::string> &indicators, const bool &force = false) {
4899 this->_impl->combineBond(indicators, force);
4900 return *this;
4901 }
4902
4915 UniTensor combineBond(const std::vector<std::string> &indicators,
4916 const bool &force = false) const {
4917 UniTensor out = this->clone();
4919 return out;
4920 }
4921
4940 UniTensor contract(const UniTensor &inR, const bool &mv_elem_self = false,
4941 const bool &mv_elem_rhs = false) const {
4942 UniTensor out;
4943 out._impl = this->_impl->contract(inR._impl, mv_elem_self, mv_elem_rhs);
4944 return out;
4945 }
4946
4948
4956 std::vector<Bond> getTotalQnums(const bool physical = false) const {
4957 return this->_impl->getTotalQnums(physical);
4958 }
4959
4963 std::vector<std::vector<cytnx_int64>> get_blocks_qnums() const {
4964 return this->_impl->get_blocks_qnums();
4965 }
4967
4972 bool same_data(const UniTensor &rhs) const {
4973 // check same type:
4974 if (this->_impl->uten_type() != rhs._impl->uten_type()) return false;
4975
4976 return this->_impl->same_data(rhs._impl);
4977 }
4978
4999 this->_impl->Add_(rhs._impl);
5000 return *this;
5001 }
5002
5023 this->_impl->Mul_(rhs._impl);
5024 return *this;
5025 }
5026
5047 this->_impl->Sub_(rhs._impl);
5048 return *this;
5049 }
5050
5071 this->_impl->Div_(rhs._impl);
5072 return *this;
5073 }
5074
5086 this->_impl->Add_(rhs);
5087 return *this;
5088 }
5089
5101 this->_impl->Mul_(rhs);
5102 return *this;
5103 }
5104
5116 this->_impl->Sub_(rhs);
5117 return *this;
5118 }
5119
5131 this->_impl->Div_(rhs);
5132 return *this;
5133 }
5134
5155
5166 UniTensor Add(const Scalar &rhs) const;
5167
5188
5199 UniTensor Mul(const Scalar &rhs) const;
5200
5221
5232 UniTensor Div(const Scalar &rhs) const;
5233
5254
5265 UniTensor Sub(const Scalar &rhs) const;
5266
5276 [[deprecated("use norm() (returns Scalar) instead")]] Tensor Norm() const {
5277 return this->_impl->Norm();
5278 };
5279
5290 Scalar norm() const { return this->_impl->Norm().item(); };
5291
5308 this->Add_(rhs);
5309 return *this;
5310 }
5311
5328 this->Sub_(rhs);
5329 return *this;
5330 }
5331
5348 this->Div_(rhs);
5349 return *this;
5350 }
5351
5368 this->Mul_(rhs);
5369 return *this;
5370 }
5371
5383 this->Add_(rhs);
5384 return *this;
5385 }
5386
5398 this->Sub_(rhs);
5399 return *this;
5400 }
5401
5413 this->Div_(rhs);
5414 return *this;
5415 }
5416
5428 this->Mul_(rhs);
5429 return *this;
5430 }
5431
5456 UniTensor Inv(double clip = -1.) const;
5457
5482 UniTensor &Inv_(double clip = -1.);
5483
5491 UniTensor Conj() const {
5492 UniTensor out;
5493 out._impl = this->_impl->Conj();
5494 return out;
5495 }
5496
5505 this->_impl->Conj_();
5506 return *this;
5507 }
5508
5523 UniTensor out;
5524 out._impl = this->_impl->Transpose();
5525 return out;
5526 }
5527
5536 this->_impl->Transpose_();
5537 return *this;
5538 }
5539
5547 UniTensor out;
5548 out._impl = this->_impl->normalize();
5549 return out;
5550 }
5551
5559 this->_impl->normalize_();
5560 return *this;
5561 }
5562
5572 UniTensor Trace(const std::string &a, const std::string &b) const {
5573 UniTensor out;
5574 out._impl = this->_impl->Trace(a, b);
5575 return out;
5576 }
5577
5587 UniTensor Trace(const cytnx_int64 &a = 0, const cytnx_int64 &b = 1) const {
5588 UniTensor out;
5589 out._impl = this->_impl->Trace(a, b);
5590 return out;
5591 }
5592
5602 UniTensor &Trace_(const std::string &a, const std::string &b) {
5603 this->_impl->Trace_(a, b);
5604 return *this;
5605 }
5606
5616 UniTensor &Trace_(const cytnx_int64 &a = 0, const cytnx_int64 &b = 1) {
5617 this->_impl->Trace_(a, b);
5618 return *this;
5619 }
5620
5630 UniTensor out;
5631 out._impl = this->_impl->Dagger();
5632 return out;
5633 }
5634
5644 this->_impl->Dagger_();
5645 return *this;
5646 }
5647
5657 this->_impl->tag_();
5658 return *this;
5659 }
5660
5664 [[deprecated("Please use tag_() instead.")]] UniTensor &tag() { return this->tag_(); }
5665
5681 UniTensor Pow(const double &p) const;
5682
5698 UniTensor &Pow_(const double &p);
5699
5706 bool elem_exists(const std::vector<cytnx_uint64> &locator) const {
5707 return this->_impl->elem_exists(locator);
5708 }
5709
5715 template <class T>
5716 [[deprecated("Use at() instead.")]] T get_elem(const std::vector<cytnx_uint64> &locator) const {
5717 return this->at<T>(locator);
5718 }
5719
5725 template <class T2>
5726 [[deprecated("Use at() instead.")]] UniTensor &set_elem(
5727 const std::vector<cytnx_uint64> &locator, const T2 &rc) {
5728 // cytnx_error_msg(true,"[ERROR] invalid type%s","\n");
5729 this->at(locator) = rc;
5730 return *this;
5731 }
5732
5739 void Save(const std::string &fname) const;
5740
5747 void Save(const char *fname) const;
5748
5757 static UniTensor Load(const std::string &fname);
5758
5767 static UniTensor Load(const char *fname);
5768
5777 UniTensor &truncate_(const std::string &label, const cytnx_uint64 &dim) {
5778 this->_impl->truncate_(label, dim);
5779 return *this;
5780 }
5781
5791 this->_impl->truncate_(bond_idx, dim);
5792 return *this;
5793 }
5794
5804 UniTensor truncate(const std::string &label, const cytnx_uint64 &dim) const {
5805 UniTensor out = this->clone();
5806 out.truncate_(label, dim);
5807 return out;
5808 }
5809
5820 UniTensor out = this->clone();
5821 out.truncate_(bond_idx, dim);
5822 return out;
5823 }
5824
5832 const std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) const {
5833 return this->_impl->get_qindices(bidx);
5834 }
5842 std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) {
5843 return this->_impl->get_qindices(bidx);
5844 }
5845
5852 const vec2d<cytnx_uint64> &get_itoi() const { return this->_impl->get_itoi(); }
5853 vec2d<cytnx_uint64> &get_itoi() { return this->_impl->get_itoi(); }
5854
5856 void _Load(std::fstream &f);
5857 void _Save(std::fstream &f) const;
5859
5875 this->_impl->from_(rhs._impl, force, tol);
5876 return *this;
5877 }
5878
5884 [[deprecated(
5885 "Please use convert_from_(const UniTensor &rhs, bool force, cytnx_double tol) "
5886 "instead.")]] UniTensor &
5887 convert_from(const UniTensor &rhs, bool force = false, cytnx_double tol = 0.) {
5888 return this->convert_from_(rhs, force, tol);
5889 }
5890
5891 // Generators:
5905 static UniTensor zeros(const std::vector<cytnx_uint64> &shape,
5906 const std::vector<std::string> &in_labels = {},
5907 unsigned int dtype = Type.Double, int device = Device.cpu,
5908 const std::string &name = "") {
5909 return UniTensor(cytnx::zeros(shape, dtype, device), false, -1, in_labels, name);
5910 }
5911 static UniTensor zeros(std::initializer_list<cytnx_uint64> shape,
5912 const std::vector<std::string> &in_labels = {},
5913 unsigned int dtype = Type.Double, int device = Device.cpu,
5914 const std::string &name = "") {
5915 return zeros(std::vector<cytnx_uint64>(shape), in_labels, dtype, device, name);
5916 }
5917
5931 static UniTensor identity(cytnx_uint64 dim, const std::vector<std::string> &in_labels = {},
5932 cytnx_bool is_diag = false, unsigned int dtype = Type.Double,
5933 int device = Device.cpu, const std::string &name = "") {
5934 if (is_diag) {
5935 return UniTensor(cytnx::ones({dim}, dtype, device), is_diag, -1, in_labels, name);
5936 } else {
5938 }
5939 }
5940
5956 static UniTensor eye(cytnx_uint64 dim, const std::vector<std::string> &in_labels = {},
5957 cytnx_bool is_diag = false, unsigned int dtype = Type.Double,
5958 int device = Device.cpu, const std::string &name = "") {
5959 return identity(dim, in_labels, is_diag, dtype, device, name);
5960 }
5961
5974 static UniTensor ones(const std::vector<cytnx_uint64> &shape,
5975 const std::vector<std::string> &in_labels = {},
5976 unsigned int dtype = Type.Double, int device = Device.cpu,
5977 const std::string &name = "") {
5978 return UniTensor(cytnx::ones(shape, dtype, device), false, -1, in_labels, name);
5979 }
5980 static UniTensor ones(std::initializer_list<cytnx_uint64> shape,
5981 const std::vector<std::string> &in_labels = {},
5982 unsigned int dtype = Type.Double, int device = Device.cpu,
5983 const std::string &name = "") {
5984 return ones(std::vector<cytnx_uint64>(shape), in_labels, dtype, device, name);
5985 }
5986
6001 static UniTensor arange(cytnx_int64 Nelem, const std::vector<std::string> &in_labels = {},
6002 const std::string &name = "") {
6003 return UniTensor(cytnx::arange(Nelem), false, -1, in_labels, name);
6004 }
6005
6024 const std::vector<std::string> &in_labels = {},
6025 unsigned int dtype = Type.Double, int device = Device.cpu,
6026 const std::string &name = "") {
6027 return UniTensor(cytnx::arange(start, end, step, dtype, device), false, -1, in_labels, name);
6028 }
6029
6050 bool endpoint = true, const std::vector<std::string> &in_labels = {},
6051 unsigned int dtype = Type.Double, int device = Device.cpu,
6052 const std::string &name = "") {
6053 return UniTensor(cytnx::linspace(start, end, Nelem, endpoint, dtype, device), false, -1,
6054 in_labels, name);
6055 }
6056
6057 // Random Generators:
6076 static UniTensor normal(const cytnx_uint64 &Nelem, const double &mean, const double &std,
6077 const std::vector<std::string> &in_labels = {},
6078 const unsigned int &seed = cytnx::random::__static_random_device(),
6079 const unsigned int &dtype = Type.Double, const int &device = Device.cpu,
6080 const std::string &name = "");
6081
6100 static UniTensor normal(const std::vector<cytnx_uint64> &shape, const double &mean,
6101 const double &std, const std::vector<std::string> &in_labels = {},
6102 const unsigned int &seed = cytnx::random::__static_random_device(),
6103 const unsigned int &dtype = Type.Double, const int &device = Device.cpu,
6104 const std::string &name = "");
6105
6124 static UniTensor uniform(const cytnx_uint64 &Nelem, const double &low, const double &high,
6125 const std::vector<std::string> &in_labels = {},
6126 const unsigned int &seed = cytnx::random::__static_random_device(),
6127 const unsigned int &dtype = Type.Double,
6128 const int &device = Device.cpu, const std::string &name = "");
6129
6167 static UniTensor uniform(const std::vector<cytnx_uint64> &shape, const double &low,
6168 const double &high, const std::vector<std::string> &in_labels = {},
6169 const unsigned int &seed = cytnx::random::__static_random_device(),
6170 const unsigned int &dtype = Type.Double,
6171 const int &device = Device.cpu, const std::string &name = "");
6172
6173 // Inplace Random Generators:
6186 UniTensor &normal_(const double &mean, const double &std,
6187 const unsigned int &seed = cytnx::random::__static_random_device());
6188
6201 UniTensor &uniform_(const double &low = 0, const double &high = 1,
6202 const unsigned int &seed = cytnx::random::__static_random_device());
6203
6204 }; // class UniTensor
6205
6207 std::ostream &operator<<(std::ostream &os, const UniTensor &in);
6209
6222 UniTensor Contract(const UniTensor &inL, const UniTensor &inR, const bool &cacheL = false,
6223 const bool &cacheR = false);
6224
6237 UniTensor Contract(const std::vector<UniTensor> &TNs, const std::string &order,
6238 const bool &optimal);
6239
6245 [[deprecated(
6246 "Please use "
6247 "UniTensor Contract(const std::vector<UniTensor> &TNs, const std::string &order, const bool "
6248 "&optimal) "
6249 "instead.")]] UniTensor
6250 Contracts(const std::vector<UniTensor> &TNs, const std::string &order, const bool &optimal);
6251
6253 void _resolve_CT(std::vector<UniTensor> &TNlist);
6254 template <class... T>
6255 void _resolve_CT(std::vector<UniTensor> &TNlist, const UniTensor &in, const T &...args) {
6256 TNlist.push_back(in);
6257 _resolve_CT(TNlist, args...);
6258 }
6260
6272 template <class... T>
6273 UniTensor Contract(const UniTensor &in, const T &...args, const std::string &order,
6274 const bool &optimal) {
6275 std::vector<UniTensor> TNlist;
6276 _resolve_CT(TNlist, in, args...);
6277 return Contract(TNlist, order, optimal);
6278 }
6279
6285 template <class... T>
6286 [[deprecated(
6287 "Please use "
6288 "UniTensor Contract(const UniTensor &in, const T &...args, const std::string &order, const "
6289 "bool &optimal) "
6290 "instead.")]] UniTensor
6291 Contracts(const UniTensor &in, const T &...args, const std::string &order,
6292 const bool &optimal) {
6293 std::vector<UniTensor> TNlist;
6294 _resolve_CT(TNlist, in, args...);
6295 return Contracts(TNlist, order, optimal);
6296 }
6297
6298} // namespace cytnx
6299
6300#endif // CYTNX_UNITENSOR_H_
constexpr Type_class Type
data type
Definition Type.hpp:553
object that mimic the python slice to access elements in C++ [this is for c++ API only].
Definition Accessor.hpp:17
the object contains auxiliary properties for each Tensor rank (bond)
Definition Bond.hpp:178
Bond clone() const
return a copy of the instance Bond
Definition Bond.hpp:451
an tensor (multi-dimensional array)
Definition Tensor.hpp:33
T & at(const std::vector< cytnx_uint64 > &locator)
Get an element at specific location.
Definition Tensor.hpp:957
Tensor Norm() const
the Norm member function. Same as linalg::Norm(const Tensor &Tin), where Tin is the current Tensor.
An Enhanced tensor specifically designed for physical Tensor network simulation.
Definition UniTensor.hpp:2773
UniTensor to(const int &device) const
move the current UniTensor to the assigned device.
Definition UniTensor.hpp:3396
UniTensor & operator*=(const UniTensor &rhs)
The multiplication assignment operator of the UniTensor.
Definition UniTensor.hpp:5367
Tensor & get_block_(const std::initializer_list< cytnx_int64 > &qidx, const bool &force=false)
Definition UniTensor.hpp:4433
std::vector< Tensor > & get_blocks_(const bool &silent=false)
Definition UniTensor.hpp:4512
Tensor & get_block_(const std::vector< cytnx_uint64 > &qidx, const bool &force=false)
Definition UniTensor.hpp:4441
void print_block(const cytnx_int64 &idx, const bool &full_info=true) const
Print out the block of the UniTensor with a given block index number.
Definition UniTensor.hpp:4062
UniTensor & operator/=(const UniTensor &rhs)
The division assignment operator of the UniTensor.
Definition UniTensor.hpp:5347
UniTensor & set_elem(const std::vector< cytnx_uint64 > &locator, const T2 &rc)
Definition UniTensor.hpp:5726
T & item()
Definition UniTensor.hpp:3168
UniTensor & tag_()
Set the UniTensor as a tagged UniTensor, in-place.
Definition UniTensor.hpp:5656
UniTensor & put_block_(Tensor &in, const std::vector< cytnx_int64 > &qidx)
Put the block into the UniTensor with given quantum indices, inplacely.
Definition UniTensor.hpp:4646
UniTensor & set_label_(const std::string &old_label, const std::string &new_label)
set a new label for bond to replace one of the current label, in-place.
Definition UniTensor.hpp:3017
bool is_contiguous() const
To tell whether the UniTensor is contiguous.
Definition UniTensor.hpp:3297
static UniTensor eye(cytnx_uint64 dim, const std::vector< std::string > &in_labels={}, cytnx_bool is_diag=false, unsigned int dtype=Type.Double, int device=Device.cpu, const std::string &name="")
Generate a 2-bond identity UniTensor.
Definition UniTensor.hpp:5956
T get_elem(const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:5716
UniTensor Div(const UniTensor &rhs) const
The division function of the UniTensor.
UniTensor & convert_from(const UniTensor &rhs, bool force=false, cytnx_double tol=0.)
Definition UniTensor.hpp:5887
Tensor get_block(const std::vector< std::string > &labels, const std::vector< cytnx_int64 > &qidx, const bool &force=false) const
Definition UniTensor.hpp:4298
UniTensor & put_block(const Tensor &in, const cytnx_uint64 &idx, const bool &force)
Definition UniTensor.hpp:4539
std::vector< cytnx_uint64 > & get_qindices(const cytnx_uint64 &bidx)
get the q-indices on each leg for the [bidx]-th block
Definition UniTensor.hpp:5842
std::vector< bool > signflip() const
Get the sign information of a fermionic UniTensor.
Definition UniTensor.hpp:3367
UniTensor & set_label_(const std::string &old_label, const char *new_label)
Definition UniTensor.hpp:3033
UniTensor & set_label(const cytnx_int64 &idx, const char *new_label)
Definition UniTensor.hpp:3064
UniTensor & operator+=(const UniTensor &rhs)
The addition assignment operator of the UniTensor.
Definition UniTensor.hpp:5307
UniTensor reshape(const std::vector< cytnx_int64 > &new_shape, const cytnx_uint64 &rowrank=0)
Reshape the UniTensor.
Definition UniTensor.hpp:4803
std::vector< Tensor > get_blocks() const
Get all the blocks of the UniTensor.
Definition UniTensor.hpp:4493
UniTensor permute(const std::initializer_list< char * > &mapper, const cytnx_int64 &rowrank=-1) const
Definition UniTensor.hpp:3803
bool is_tag() const
To tell whether the UniTensor is tagged. That is, all of the Bond in the UniTensor is directional (al...
Definition UniTensor.hpp:3310
std::string uten_type_str() const
Return the UniTensor type (cytnx::UTenType) of the UniTensor in 'string' form.
Definition UniTensor.hpp:3290
UniTensor permute_nosignflip(const std::vector< std::string > &mapper, const cytnx_int64 &rowrank=-1) const
permute the legs of the UniTensor by labels without sign flips
Definition UniTensor.hpp:3867
UniTensor(const std::vector< Bond > &bonds, const std::vector< std::string > &in_labels={}, const cytnx_int64 &rowrank=-1, const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const bool &is_diag=false, const std::string &name="")
Construct a UniTensor.
Definition UniTensor.hpp:2862
bool is_void() const
Return whether the UniTensor is uninitialized.
Definition UniTensor.hpp:3232
Tensor get_block(const std::vector< cytnx_int64 > &qidx, const bool &force=false) const
Get the block of the UniTensor for the given quantun indices.
Definition UniTensor.hpp:4294
UniTensor & contiguous_()
Make the UniTensor contiguous by coalescing the memory (storage), inplacely.
Definition UniTensor.hpp:4014
UniTensor & tag()
Definition UniTensor.hpp:5664
const Bond & bond_(const cytnx_uint64 &idx) const
Definition UniTensor.hpp:3346
bool is_scalar() const
whether the UniTensor is an initialized rank-0 scalar UniTensor
Definition UniTensor.hpp:3238
void combineBonds(const std::vector< cytnx_int64 > &indicators, const bool &force=false)
Definition UniTensor.hpp:4882
UniTensor & set_label_(const char *old_label, const char *new_label)
Definition UniTensor.hpp:3041
UniTensor & relabel_(const std::string &old_label, const std::string &new_label)
relabel the legs in the UniTensor by a given label.
Definition UniTensor.hpp:3729
const T & at(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:4138
UniTensor & relabels_(const std::initializer_list< char * > &new_labels)
Definition UniTensor.hpp:3524
UniTensor(const Tensor &in_tensor, const bool &is_diag=false, const cytnx_int64 &rowrank=-1, const std::vector< std::string > &in_labels={}, const std::string &name="")
Construct a UniTensor from a cytnx::Tensor.
Definition UniTensor.hpp:2812
Tensor & get_block_(const std::vector< cytnx_int64 > &qidx, const bool &force=false)
Get the shared view of the block for the given quantum indices.
Definition UniTensor.hpp:4379
void Init(const Tensor &in_tensor, const bool &is_diag=false, const cytnx_int64 &rowrank=-1, const std::vector< std::string > &in_labels={}, const std::string &name="")
Initialize a UniTensor from a cytnx::Tensor.
Definition UniTensor.hpp:2835
UniTensor get(const std::vector< Accessor > &accessors) const
get elements using Accessor (C++ API) / slices (python API)
Definition UniTensor.hpp:4733
UniTensor & permute_nosignflip_(const std::vector< cytnx_int64 > &mapper, const cytnx_int64 &rowrank=-1)
permute the legs of the UniTensor without fermionic sign flips, inplacely.
Definition UniTensor.hpp:3901
T & at(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &locator)
Definition UniTensor.hpp:4160
UniTensor Conj() const
Apply complex conjugate on each entry of the UniTensor.
Definition UniTensor.hpp:5491
UniTensor & set_label(const std::string &old_label, const std::string &new_label)
Definition UniTensor.hpp:3076
UniTensor set_rowrank(const cytnx_uint64 &new_rowrank) const
Definition UniTensor.hpp:3161
UniTensor & set(const std::vector< Accessor > &accessors, const UniTensor &rhs)
Definition UniTensor.hpp:4784
void Save(const std::string &fname) const
save a UniTensor to file
UniTensor & operator-=(const Scalar &rhs)
The subtraction assignment operator for a given scalar.
Definition UniTensor.hpp:5397
cytnx_uint64 rowrank() const
Return the row rank of the UniTensor.
Definition UniTensor.hpp:3211
UniTensor & put_block(const Tensor &in_tens, const std::vector< cytnx_int64 > &qidx)
Put the block into the UniTensor with given quantum indices.
Definition UniTensor.hpp:4553
UniTensor & relabels_(const std::vector< std::string > &old_labels, const std::vector< std::string > &new_labels)
Definition UniTensor.hpp:3594
UniTensor Sub(const Scalar &rhs) const
The subtraction function for a given scalar.
Tensor Norm() const
Return the norm of the UniTensor.
Definition UniTensor.hpp:5276
UniTensor Mul(const Scalar &rhs) const
The multiplication function for a given scalar.
UniTensor & twist_(const std::string &label)
Inline version.
Definition UniTensor.hpp:3955
UniTensor twist(const std::string &label) const
Apply a twist (or braids/self-swap) operation to a given bond; No effect for bosonic tensors; for a f...
Definition UniTensor.hpp:3932
UniTensor & set_labels(const std::initializer_list< char * > &new_labels)
Definition UniTensor.hpp:3140
UniTensor & relabel_(const std::initializer_list< char * > &new_labels)
Definition UniTensor.hpp:3506
UniTensor & Sub_(const Scalar &rhs)
The subtraction function for a given scalar.
Definition UniTensor.hpp:5115
UniTensor & relabel_(const cytnx_int64 &inx, const std::string &new_label)
rebable the legs in the UniTensor by given index.
Definition UniTensor.hpp:3716
UniTensor & operator/=(const Scalar &rhs)
The division assignment operator for a given scalar.
Definition UniTensor.hpp:5412
const bool & is_braket_form() const
Check whether the UniTensor is in braket form.
Definition UniTensor.hpp:3325
UniTensor Add(const Scalar &rhs) const
The addition function for a given scalar.
UniTensor operator[](const std::vector< cytnx::Accessor > &accessors) const
get elements using Accessor (C++ API) / slices (python API)
Definition UniTensor.hpp:4743
UniTensor & set_label_(const char *old_label, const std::string &new_label)
Definition UniTensor.hpp:3025
std::vector< cytnx_uint64 > shape() const
Get the shape of the UniTensor.
Definition UniTensor.hpp:3359
UniTensor to_dense()
Convert the UniTensor to non-diagonal form.
Definition UniTensor.hpp:4831
UniTensor & permute_(const std::vector< cytnx_int64 > &mapper, const cytnx_int64 &rowrank=-1)
permute the legs of the UniTensor, inplacely.
Definition UniTensor.hpp:3820
Scalar::Sproxy at(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &locator)
Definition UniTensor.hpp:4227
static UniTensor normal(const std::vector< cytnx_uint64 > &shape, const double &mean, const double &std, const std::vector< std::string > &in_labels={}, const unsigned int &seed=cytnx::random::__static_random_device(), const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const std::string &name="")
Generate a UniTensor with all elements are random numbers sampled from a normal (Gaussian) distributi...
const Tensor & get_block_(const std::vector< cytnx_int64 > &qidx, const bool &force=false) const
Definition UniTensor.hpp:4457
UniTensor & set_name_(const std::string &in)
Set the name of a UniTensor, in-place.
Definition UniTensor.hpp:2971
UniTensor & set_labels(const std::vector< std::string > &new_labels)
Definition UniTensor.hpp:3126
std::string name() const
Return the name of the UniTensor.
Definition UniTensor.hpp:3269
const Scalar::Sproxy at(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:4249
UniTensor & put_block(Tensor &in, const std::vector< std::string > &lbls, const std::vector< cytnx_int64 > &qidx)
Put the block into the UniTensor with given quantum indices, will copy the input tensor.
Definition UniTensor.hpp:4580
static UniTensor zeros(const std::vector< cytnx_uint64 > &shape, const std::vector< std::string > &in_labels={}, unsigned int dtype=Type.Double, int device=Device.cpu, const std::string &name="")
Generate a UniTensor with all elements set to zero.
Definition UniTensor.hpp:5905
UniTensor combineBond(const std::vector< std::string > &indicators, const bool &force=false) const
Combine the sevral bonds of the UniTensor, out-of-place.
Definition UniTensor.hpp:4915
UniTensor & Add_(const Scalar &rhs)
The addition function for a given scalar.
Definition UniTensor.hpp:5085
UniTensor & set(const std::vector< Accessor > &accessors, const Tensor &rhs)
set elements using Accessor (C++ API) / slices (python API)
Definition UniTensor.hpp:4780
UniTensor & Trace_(const std::string &a, const std::string &b)
Take the partial trace of the UniTensor, inplacely.
Definition UniTensor.hpp:5602
UniTensor & truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim)
truncate bond dimension of the UniTensor by the given bond index and dimension.
Definition UniTensor.hpp:5790
UniTensor & twist_(const cytnx_int64 &idx)
Inline version.
Definition UniTensor.hpp:3964
Scalar::Sproxy at(const std::vector< cytnx_uint64 > &locator)
Get an element at a specific location.
Definition UniTensor.hpp:4211
UniTensor Trace(const std::string &a, const std::string &b) const
Take the partial trace of the UniTensor.
Definition UniTensor.hpp:5572
UniTensor & set_label_(const cytnx_int64 &idx, const char *new_label)
Definition UniTensor.hpp:3002
UniTensor & Init(const std::vector< Bond > &bonds, const std::vector< std::string > &in_labels={}, const cytnx_int64 &rowrank=-1, const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const bool &is_diag=false, const std::string &name="")
Initialize the UniTensor with the given arguments.
Definition UniTensor.hpp:2909
bool same_data(const UniTensor &rhs) const
Check whether the Blocks address are the same.
Definition UniTensor.hpp:4972
UniTensor astype(const unsigned int &dtype) const
Return a new UniTensor whose elements are casted to a different data type.
Definition UniTensor.hpp:3760
UniTensor truncate(const std::string &label, const cytnx_uint64 &dim) const
truncate bond dimension of the UniTensor by the given bond label and dimension.
Definition UniTensor.hpp:5804
UniTensor Transpose() const
Take the transpose of the UniTensor.
Definition UniTensor.hpp:5522
UniTensor operator[](const std::initializer_list< cytnx_int64 > &accessors) const
Definition UniTensor.hpp:4759
UniTensor & set_label(const char *old_label, const std::string &new_label)
Definition UniTensor.hpp:3086
static UniTensor Load(const char *fname)
load a UniTensor from file
static UniTensor arange(cytnx_int64 Nelem, const std::vector< std::string > &in_labels={}, const std::string &name="")
Create a rank-1 UniTensor with incremental unsigned integer elements in the range [0,...
Definition UniTensor.hpp:6001
UniTensor & Dagger_()
Take the conjugate transpose to the UniTensor, inplacely.
Definition UniTensor.hpp:5643
T & at(const std::vector< cytnx_uint64 > &locator)
Get an element at a specific location.
Definition UniTensor.hpp:4092
UniTensor & set_rowrank_(const cytnx_uint64 &new_rowrank)
Set the rowrank of the UniTensor.
Definition UniTensor.hpp:3156
UniTensor & uniform_(const double &low=0, const double &high=1, const unsigned int &seed=cytnx::random::__static_random_device())
Generate a UniTensor with all elements are random numbers sampled from a uniform distribution,...
UniTensor & normal_(const double &mean, const double &std, const unsigned int &seed=cytnx::random::__static_random_device())
Generate a one-bond UniTensor with all elements are random numbers sampled from a normal (Gaussian) d...
UniTensor operator[](const std::initializer_list< cytnx::Accessor > &accessors) const
Definition UniTensor.hpp:4748
UniTensor & put_block_(Tensor &in, const std::vector< std::string > &lbls, const std::vector< cytnx_int64 > &qidx)
Put the block into the UniTensor with given quantum indices, inplacely.
Definition UniTensor.hpp:4673
UniTensor & set_label(const cytnx_int64 &idx, const std::string &new_label)
Definition UniTensor.hpp:3054
UniTensor permute_nosignflip(const std::vector< cytnx_int64 > &mapper, const cytnx_int64 &rowrank=-1) const
permute the legs of the UniTensor without sign flips
Definition UniTensor.hpp:3849
UniTensor & fermion_twists_()
Inline version.
Definition UniTensor.hpp:3993
UniTensor & to_dense_()
Convert the UniTensor to non-diagonal form, inplacely.
Definition UniTensor.hpp:4841
UniTensor contiguous() const
Make the UniTensor contiguous by coalescing the memory (storage).
Definition UniTensor.hpp:4004
UniTensor & put_block_(Tensor &in, const cytnx_uint64 &idx=0)
Put the block into the UniTensor with given index, inplacely.
Definition UniTensor.hpp:4632
UniTensor & combineBond_(const std::vector< std::string > &indicators, const bool &force=false)
Combine the sevral bonds of the UniTensor, in-place.
Definition UniTensor.hpp:4898
UniTensor & apply_()
Apply fermionic signflips to the UniTensor, inplacely. Subsequently, all elements returned by signfli...
Definition UniTensor.hpp:4038
Tensor get_block(const cytnx_uint64 &idx=0) const
Get the block of the UniTensor for a given block index.
Definition UniTensor.hpp:4280
const T & at(const std::vector< cytnx_uint64 > &locator) const
Get an element at a specific location.
Definition UniTensor.hpp:4119
UniTensor & operator*=(const Scalar &rhs)
The multiplication assignment operator for a given scalar.
Definition UniTensor.hpp:5427
UniTensor relabels(const std::vector< std::string > &old_labels, const std::vector< std::string > &new_labels) const
Definition UniTensor.hpp:3557
UniTensor & convert_from_(const UniTensor &rhs, bool force=false, cytnx_double tol=0.)
Copy data from a UniTensor of different type, in-place.
Definition UniTensor.hpp:5874
UniTensor normalize() const
normalize the current UniTensor instance with 2-norm.
Definition UniTensor.hpp:5546
UniTensor & relabel_(const std::vector< std::string > &new_labels)
Set new labels for all the bonds.
Definition UniTensor.hpp:3421
std::vector< Symmetry > syms() const
Return the symmetry type of the UniTensor.
Definition UniTensor.hpp:3317
UniTensor relabel(const std::vector< std::string > &new_labels) const
relabel all of the labels in UniTensor.
Definition UniTensor.hpp:3450
UniTensor & Mul_(const UniTensor &rhs)
The multiplcation function of the UniTensor.
Definition UniTensor.hpp:5022
static UniTensor linspace(cytnx_double start, cytnx_double end, cytnx_uint64 Nelem, bool endpoint=true, const std::vector< std::string > &in_labels={}, unsigned int dtype=Type.Double, int device=Device.cpu, const std::string &name="")
Generate a one-bond UniTensor with all elements are evenly spaced numbers over a specified interval.
Definition UniTensor.hpp:6049
UniTensor & permute_nosignflip_(const std::vector< std::string > &mapper, const cytnx_int64 &rowrank=-1)
permute the legs of the UniTensor without fermionic sign flips, inplacely.
Definition UniTensor.hpp:3918
void combineBonds(const std::vector< std::string > &indicators, const bool &force=false)
Definition UniTensor.hpp:4869
UniTensor relabel(const std::string &old_label, const std::string &new_label) const
relabel the legs in the UniTensor by a given label.
Definition UniTensor.hpp:3748
UniTensor & group_basis_()
Group the same quantum number basis together.
Definition UniTensor.hpp:4072
UniTensor & normalize_()
normalize the UniTensor, inplacely.
Definition UniTensor.hpp:5558
UniTensor & Inv_(double clip=-1.)
Element-wise (pseudo-)inverse, inplacely.
bool is_diag() const
To tell whether the UniTensor is in diagonal form.
Definition UniTensor.hpp:3303
int device() const
Return the device of the UniTensor.
Definition UniTensor.hpp:3263
UniTensor & Pow_(const double &p)
Take the power p of all elements, inplacely.
const Tensor & get_block_(const std::vector< cytnx_uint64 > &qidx, const bool &force=false) const
Definition UniTensor.hpp:4474
Tensor get_block_(const std::vector< std::string > &labels, const std::vector< cytnx_int64 > &qidx, const bool &force=false)
Get the shared (data) view of the block for the given quantum indices on given labels.
Definition UniTensor.hpp:4401
std::string dtype_str() const
Return the data type of the UniTensor in 'string' form.
Definition UniTensor.hpp:3276
UniTensor & operator+=(const Scalar &rhs)
The addition assignment operator for a given scalar.
Definition UniTensor.hpp:5382
UniTensor & Div_(const UniTensor &rhs)
The division function of the UniTensor.
Definition UniTensor.hpp:5070
UniTensor & Div_(const Scalar &rhs)
The division function for a given scalar.
Definition UniTensor.hpp:5130
UniTensor & put_block_(Tensor &in, const std::vector< cytnx_int64 > &qidx, const bool &force)
Definition UniTensor.hpp:4660
Bond & bond_(const std::string &label)
Definition UniTensor.hpp:3350
cytnx_uint64 rank() const
Return the rank of the UniTensor.
Definition UniTensor.hpp:3205
Bond bond(const std::string &label) const
Definition UniTensor.hpp:3353
UniTensor permute_nosignflip(const std::initializer_list< const char * > &mapper, const cytnx_int64 &rowrank=-1) const
Definition UniTensor.hpp:3879
UniTensor fermion_twists() const
Apply twists to all right bonds (>= rowrank) with bond type BD_KET.
Definition UniTensor.hpp:3983
UniTensor & Trace_(const cytnx_int64 &a=0, const cytnx_int64 &b=1)
Take the partial trace of the UniTensor, inplacely.
Definition UniTensor.hpp:5616
UniTensor relabel(const std::vector< std::string > &old_labels, const std::vector< std::string > &new_labels) const
replace part or all labels by given new labels for the bonds.
Definition UniTensor.hpp:3541
UniTensor & put_block(const Tensor &in, const cytnx_uint64 &idx=0)
Put the block into the UniTensor with given index.
Definition UniTensor.hpp:4525
UniTensor & put_block(const Tensor &in_tens, const std::vector< cytnx_int64 > &qidx, const bool &force)
Definition UniTensor.hpp:4567
UniTensor & set_name(const std::string &in)
Definition UniTensor.hpp:2979
UniTensor Trace(const cytnx_int64 &a=0, const cytnx_int64 &b=1) const
Take the partial trace of the UniTensor.
Definition UniTensor.hpp:5587
UniTensor & Add_(const UniTensor &rhs)
The addition function of the UniTensor.
Definition UniTensor.hpp:4998
UniTensor permute(const std::vector< cytnx_int64 > &mapper, const cytnx_int64 &rowrank=-1) const
permute the legs of the UniTensor
Definition UniTensor.hpp:3778
UniTensor & set_label(const std::string &old_label, const char *new_label)
Definition UniTensor.hpp:3096
UniTensor permute(const std::vector< std::string > &mapper, const cytnx_int64 &rowrank=-1) const
permute the legs of the UniTensor by labels
Definition UniTensor.hpp:3791
unsigned int dtype() const
Return the data type of the UniTensor.
Definition UniTensor.hpp:3218
UniTensor & set_label_(const cytnx_int64 &idx, const std::string &new_label)
Set a new label for bond at the assigned index, in-place.
Definition UniTensor.hpp:2994
UniTensor Pow(const double &p) const
Take the power p of all elements.
UniTensor & Mul_(const Scalar &rhs)
The multiplication function for a given scalar.
Definition UniTensor.hpp:5100
UniTensor & operator-=(const UniTensor &rhs)
The subtraction assignment operator of the UniTensor.
Definition UniTensor.hpp:5327
static UniTensor ones(std::initializer_list< cytnx_uint64 > shape, const std::vector< std::string > &in_labels={}, unsigned int dtype=Type.Double, int device=Device.cpu, const std::string &name="")
Definition UniTensor.hpp:5980
Tensor get_block_(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &qidx, const bool &force=false)
Definition UniTensor.hpp:4446
void combineBonds(const std::vector< cytnx_int64 > &indicators, const bool &force, const bool &by_label)
Definition UniTensor.hpp:4855
UniTensor & set_label(const char *old_label, const char *new_label)
Definition UniTensor.hpp:3106
bool is_blockform() const
Check whether the UniTensor is in block form.
Definition UniTensor.hpp:3374
UniTensor group_basis() const
Definition UniTensor.hpp:4077
UniTensor twist(const cytnx_int64 &idx) const
Apply a twist (or braids/self-swap) operation to a given bond; No effect for bosonic tensors; for a f...
Definition UniTensor.hpp:3945
UniTensor apply() const
Apply fermionic signflips to the UniTensor, such that all elements calling signflip() on the output t...
Definition UniTensor.hpp:4027
UniTensor Dagger() const
Take the conjugate transpose to the UniTensor.
Definition UniTensor.hpp:5629
static UniTensor uniform(const std::vector< cytnx_uint64 > &shape, const double &low, const double &high, const std::vector< std::string > &in_labels={}, const unsigned int &seed=cytnx::random::__static_random_device(), const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const std::string &name="")
Generate a UniTensor with all elements are random numbers sampled from a uniform distribution.
const std::vector< Tensor > & get_blocks_(const bool &silent=false) const
Get all the blocks of the UniTensor, inplacely.
Definition UniTensor.hpp:4504
UniTensor & relabels_(const std::initializer_list< char * > &old_labels, const std::initializer_list< char * > &new_labels)
Definition UniTensor.hpp:3673
const Tensor & get_block_(const std::initializer_list< cytnx_int64 > &qidx, const bool &force=false) const
Definition UniTensor.hpp:4465
bool elem_exists(const std::vector< cytnx_uint64 > &locator) const
Given the locator, check if the element exists.
Definition UniTensor.hpp:5706
UniTensor & Sub_(const UniTensor &rhs)
The subtraction function of the UniTensor.
Definition UniTensor.hpp:5046
UniTensor relabels(const std::initializer_list< char * > &new_labels) const
Definition UniTensor.hpp:3493
Scalar norm() const
Return the norm of the UniTensor.
Definition UniTensor.hpp:5290
UniTensor contract(const UniTensor &inR, const bool &mv_elem_self=false, const bool &mv_elem_rhs=false) const
Contract the UniTensor with common labels.
Definition UniTensor.hpp:4940
const Tensor & get_block_(const cytnx_uint64 &idx=0) const
Get the shared view of the block for the given block index.
Definition UniTensor.hpp:4358
UniTensor & relabel_(const std::vector< std::string > &old_labels, const std::vector< std::string > &new_labels)
relabel part or all of the labels in UniTensor by given new labels
Definition UniTensor.hpp:3579
static UniTensor identity(cytnx_uint64 dim, const std::vector< std::string > &in_labels={}, cytnx_bool is_diag=false, unsigned int dtype=Type.Double, int device=Device.cpu, const std::string &name="")
Generate an identity UniTensor with two bonds.
Definition UniTensor.hpp:5931
static UniTensor Load(const std::string &fname)
load a UniTensor from file
UniTensor & permute_(const std::vector< std::string > &mapper, const cytnx_int64 &rowrank=-1)
permute the legs of the UniTensor, inplacely.
Definition UniTensor.hpp:3831
const Bond & bond_(const std::string &label) const
Definition UniTensor.hpp:3349
Bond & bond_(const cytnx_uint64 &idx)
Definition UniTensor.hpp:3347
cytnx_uint64 size() const
Return the total number of logical elements in the UniTensor.
Definition UniTensor.hpp:3246
static UniTensor normal(const cytnx_uint64 &Nelem, const double &mean, const double &std, const std::vector< std::string > &in_labels={}, const unsigned int &seed=cytnx::random::__static_random_device(), const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const std::string &name="")
Generate a one-bond UniTensor with all elements are random numbers sampled from a normal (Gaussian) d...
UniTensor Inv(double clip=-1.) const
Element-wise (pseudo-)inverse.
UniTensor relabel(const cytnx_int64 &inx, const std::string &new_label) const
rebabel the legs in the UniTensor by given index.
Definition UniTensor.hpp:3703
UniTensor Mul(const UniTensor &rhs) const
The multiplication function of the UniTensor.
UniTensor & reshape_(const std::vector< cytnx_int64 > &new_shape, const cytnx_uint64 &rowrank=0)
Reshape the UniTensor, inplacely.
Definition UniTensor.hpp:4815
bool is_empty() const
whether the UniTensor is initialized and has no logical elements
Definition UniTensor.hpp:3256
void print_diagram(const bool &bond_info=false) const
Plot the diagram of the UniTensor.
Definition UniTensor.hpp:4047
UniTensor relabels(const std::initializer_list< char * > &old_labels, const std::initializer_list< char * > &new_labels) const
Definition UniTensor.hpp:3629
Tensor get_block(const std::vector< cytnx_uint64 > &qidx, const bool &force=false) const
Definition UniTensor.hpp:4339
const std::vector< cytnx_uint64 > & get_qindices(const cytnx_uint64 &bidx) const
get the q-indices on each leg for the [bidx]-th block
Definition UniTensor.hpp:5832
UniTensor Div(const Scalar &rhs) const
The division function for a given scalar.
const std::vector< std::string > & labels() const
Return the labels of the UniTensor.
Definition UniTensor.hpp:3331
UniTensor & relabel_(const std::initializer_list< char * > &old_labels, const std::initializer_list< char * > &new_labels)
Definition UniTensor.hpp:3648
cytnx_int64 get_index(std::string label) const
Get the index of an desired label string.
Definition UniTensor.hpp:3338
UniTensor & to_(const int &device)
move the current UniTensor to the assigned device (inplace).
Definition UniTensor.hpp:3382
const std::vector< Bond > & bonds() const
Get the bonds of the UniTensor.
Definition UniTensor.hpp:3344
Tensor get_block(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &qidx, const bool &force=false) const
Definition UniTensor.hpp:4344
UniTensor truncate(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim) const
truncate bond dimension of the UniTensor by the given bond index and dimension.
Definition UniTensor.hpp:5819
UniTensor & Transpose_()
Take the transpose of the UniTensor, inplacely.
Definition UniTensor.hpp:5535
static UniTensor uniform(const cytnx_uint64 &Nelem, const double &low, const double &high, const std::vector< std::string > &in_labels={}, const unsigned int &seed=cytnx::random::__static_random_device(), const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const std::string &name="")
Generate a one-bond UniTensor with all elements are random numbers sampled from a uniform distributio...
UniTensor & put_block(Tensor &in, const std::vector< std::string > &lbls, const std::vector< cytnx_int64 > &qidx, const bool &force)
Definition UniTensor.hpp:4618
Tensor get_block(const std::initializer_list< cytnx_int64 > &qidx, const bool &force=false) const
Definition UniTensor.hpp:4329
UniTensor clone() const
Clone (deep copy) the UniTensor.
Definition UniTensor.hpp:3406
vec2d< cytnx_uint64 > & get_itoi()
Definition UniTensor.hpp:5853
void print_blocks(const bool &full_info=true) const
Print all blocks of the UniTensor.
Definition UniTensor.hpp:4055
Scalar::Sproxy item() const
Definition UniTensor.hpp:3182
const vec2d< cytnx_uint64 > & get_itoi() const
get the q-indices on each leg for all the blocks
Definition UniTensor.hpp:5852
std::string device_str() const
Return the device of the UniTensor in 'string' form.
Definition UniTensor.hpp:3283
UniTensor & put_block_(Tensor &in, const std::vector< std::string > &lbls, const std::vector< cytnx_int64 > &qidx, const bool &force)
Definition UniTensor.hpp:4713
UniTensor relabels(const std::vector< std::string > &new_labels) const
Definition UniTensor.hpp:3464
static UniTensor ones(const std::vector< cytnx_uint64 > &shape, const std::vector< std::string > &in_labels={}, unsigned int dtype=Type.Double, int device=Device.cpu, const std::string &name="")
Generate a UniTensor with all elements set to one.
Definition UniTensor.hpp:5974
UniTensor relabel(const std::initializer_list< char * > &old_labels, const std::initializer_list< char * > &new_labels) const
Definition UniTensor.hpp:3604
UniTensor Sub(const UniTensor &rhs) const
The subtraction function of the UniTensor.
UniTensor & Conj_()
Apply complex conjugate on each entry of the UniTensor.
Definition UniTensor.hpp:5504
static UniTensor arange(cytnx_double start, cytnx_double end, cytnx_double step=1, const std::vector< std::string > &in_labels={}, unsigned int dtype=Type.Double, int device=Device.cpu, const std::string &name="")
Create a rank-1 UniTensor with incremental elements in the range [start,end) with given step-size ste...
Definition UniTensor.hpp:6023
UniTensor operator[](const std::vector< cytnx_int64 > &accessors) const
Definition UniTensor.hpp:4752
UniTensor relabel(const std::initializer_list< char * > &new_labels) const
relables all of the labels in UniTensor.
Definition UniTensor.hpp:3474
cytnx_uint64 Nblocks() const
Return the number of blocks in the UniTensor.
Definition UniTensor.hpp:3199
void Save(const char *fname) const
save a UniTensor to file
Bond bond(const cytnx_uint64 &idx) const
Definition UniTensor.hpp:3352
static UniTensor zeros(std::initializer_list< cytnx_uint64 > shape, const std::vector< std::string > &in_labels={}, unsigned int dtype=Type.Double, int device=Device.cpu, const std::string &name="")
Definition UniTensor.hpp:5911
UniTensor Add(const UniTensor &rhs) const
The addition function of the UniTensor.
UniTensor & truncate_(const std::string &label, const cytnx_uint64 &dim)
truncate bond dimension of the UniTensor by the given bond label and dimension.
Definition UniTensor.hpp:5777
UniTensor & relabels_(const std::vector< std::string > &new_labels)
Definition UniTensor.hpp:3434
const Scalar::Sproxy at(const std::vector< cytnx_uint64 > &locator) const
Get an element at a specific location.
Definition UniTensor.hpp:4188
int uten_type() const
Return the UniTensor type (cytnx::UTenType) of the UniTensor.
Definition UniTensor.hpp:3226
Tensor & get_block_(const cytnx_uint64 &idx=0)
Definition UniTensor.hpp:4366
#define cytnx_warning_msg(is_true, format,...)
Definition cytnx_error.hpp:125
#define cytnx_error_msg(is_true, format,...)
Definition cytnx_error.hpp:118
cytnx::UniTensor Conj(const cytnx::UniTensor &UT)
Elementwise conjugate of the UniTensor.
cytnx::UniTensor Trace(const cytnx::UniTensor &Tin, const cytnx_int64 &a=0, const cytnx_int64 &b=1)
Perform the trace over two legs of a UniTensor.
void Conj_(cytnx::UniTensor &UT)
Inplace elementwise conjugate of the UniTensor.
Tensor Norm(const Tensor &Tl)
Calculate the norm of a tensor.
std::random_device __static_random_device
Definition UniTensor.hpp:27
Definition Accessor.hpp:12
Device_class Device
data on which devices.
UniTensorType_class UTenType
UniTensor type.
@ Void
Definition Symmetry.hpp:30
Tensor zeros(const std::vector< cytnx_uint64 > &shape, unsigned int dtype=Type.Double, int device=Device.cpu)
Create a Tensor with all elements initialized to zero.
UniTensor Contract(const UniTensor &inL, const UniTensor &inR, const bool &cacheL=false, const bool &cacheR=false)
Contract two UniTensor by tracing the ranks with common labels.
Tensor linspace(cytnx_double start, cytnx_double end, cytnx_uint64 Nelem, bool endpoint=true, unsigned int dtype=Type.Double, int device=Device.cpu)
Tensor ones(const std::vector< cytnx_uint64 > &shape, unsigned int dtype=Type.Double, int device=Device.cpu)
Create a Tensor with all elements initialized to one.
UniTensor Contracts(const std::vector< UniTensor > &TNs, const std::string &order, const bool &optimal)
Tensor arange(cytnx_int64 Nelem)
Create a rank-1 Tensor with incremental unsigned integer elements in the range [0,...
Tensor identity(cytnx_uint64 Dim, unsigned int dtype=Type.Double, int device=Device.cpu)
Create a square rank-2 Tensor with the diagonal initialized to one and all other elements set to zero...