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#ifdef BACKEND_TORCH
23#else
24 #include "backend/Scalar.hpp"
25
26// namespace cytnx{
27namespace cytnx {
28 namespace random {
29 extern std::random_device __static_random_device;
30 }
31
33 class UniTensorType_class {
34 public:
35 enum : int { Void = -99, Dense = 0, Sparse = 1, Block = 2, BlockFermionic = 3 };
36 std::string getname(const int &ut_type) const;
37 };
39
56 extern UniTensorType_class UTenType;
57
59 // class DenseUniTensor;
60 // class SparseUniTensor;
61 class UniTensor_base : public intrusive_ptr_base<UniTensor_base> {
62 public:
63 int uten_type_id; // the unitensor type id.
64 bool _is_braket_form;
65 bool _is_tag;
66 bool _is_diag;
67 cytnx_int64 _rowrank;
68 std::string _name;
69 std::vector<std::string> _labels;
70 std::vector<Bond> _bonds;
71
72 bool _update_braket() {
73 if (_bonds.size() == 0) return false;
74
75 if (this->_bonds[0].type() != bondType::BD_REG) {
76 // check:
77 for (unsigned int i = 0; i < this->_bonds.size(); i++) {
78 if (i < this->_rowrank) {
79 if (this->_bonds[i].type() != bondType::BD_KET) return false;
80 } else {
81 if (this->_bonds[i].type() != bondType::BD_BRA) return false;
82 }
83 }
84 return true;
85 } else {
86 return false;
87 }
88 }
89
90 friend class UniTensor; // allow wrapper to access the private elems
91 friend class DenseUniTensor;
92 // friend class SparseUniTensor;
93 friend class BlockUniTensor;
94 friend class BlockFermionicUniTensor;
95
96 UniTensor_base()
97 : _is_tag(false),
98 _name(std::string("")),
99 _is_braket_form(false),
100 _rowrank(0),
101 _is_diag(false),
102 uten_type_id(UTenType.Void){};
103
104 // copy&assignment constr., use intrusive_ptr's !!
105 UniTensor_base(const UniTensor_base &rhs);
106 UniTensor_base &operator=(UniTensor_base &rhs);
107
108 cytnx_uint64 rowrank() const { return this->_rowrank; }
109 bool is_diag() const { return this->_is_diag; }
110 const bool &is_braket_form() const { return this->_is_braket_form; }
111 const bool &is_tag() const { return this->_is_tag; }
112 const std::vector<std::string> &labels() const { return this->_labels; }
119 cytnx_int64 get_index(std::string label) const {
120 std::vector<std::string> labels = this->_labels;
121 for (cytnx_uint64 i = 0; i < labels.size(); i++) {
122 if (labels[i] == label) return i;
123 }
124 return -1;
125 }
126 const std::vector<Bond> &bonds() const { return this->_bonds; }
127 std::vector<Bond> &bonds() { return this->_bonds; }
128
129 Bond &bond_(const cytnx_uint64 &idx) {
130 cytnx_error_msg(idx >= this->_bonds.size(), "[ERROR][bond] index %d out of bound, total %d\n",
131 idx, this->_bonds.size());
132 return this->_bonds[idx];
133 }
134
135 Bond &bond_(const std::string &label) {
136 auto res = std::find(this->_labels.begin(), this->_labels.end(), label);
137 cytnx_error_msg(res == this->_labels.end(), "[ERROR] label %s not exists.\n", label.c_str());
138 cytnx_uint64 idx = std::distance(this->_labels.begin(), res);
139
140 return this->bond_(idx);
141 }
142
143 const std::string &name() const { return this->_name; }
144 cytnx_uint64 rank() const { return this->_labels.size(); }
145 void set_name(const std::string &in) { this->_name = in; }
146
158 void set_label(const std::string &oldlabel, const std::string &new_label) {
159 cytnx_int64 idx;
160 auto res = std::find(this->_labels.begin(), this->_labels.end(), oldlabel);
161 cytnx_error_msg(res == this->_labels.end(), "[ERROR] label %s not exists.\n",
162 oldlabel.c_str());
163 idx = std::distance(this->_labels.begin(), res);
164
165 cytnx_error_msg(idx >= this->_labels.size(), "[ERROR] index exceed the rank of UniTensor%s",
166 "\n");
167 // check in:
168 bool is_dup = false;
169 for (cytnx_uint64 i = 0; i < this->_labels.size(); i++) {
170 if (i == idx) continue;
171 if (new_label == this->_labels[i]) {
172 is_dup = true;
173 break;
174 }
175 }
176 cytnx_error_msg(is_dup, "[ERROR] alreay has a label that is the same as the input label%s",
177 "\n");
178 this->_labels[idx] = new_label;
179 }
180 void set_label(const cytnx_int64 &inx, const std::string &new_label) {
181 cytnx_error_msg(inx < 0, "[ERROR] index is negative%s", "\n");
182 cytnx_error_msg(inx >= this->_labels.size(), "[ERROR] index exceed the rank of UniTensor%s",
183 "\n");
184 // check in:
185 bool is_dup = false;
186 for (cytnx_uint64 i = 0; i < this->_labels.size(); i++) {
187 if (i == inx) continue;
188 if (new_label == this->_labels[i]) {
189 is_dup = true;
190 break;
191 }
192 }
193 cytnx_error_msg(is_dup, "[ERROR] alreay has a label that is the same as the input label%s",
194 "\n");
195 this->_labels[inx] = new_label;
196 }
197
198 [[deprecated("Please use relabel_(const std::vector<std::string> &new_labels) instead.")]] void
199 set_labels(const std::vector<std::string> &new_labels);
200 void relabel_(const std::vector<std::string> &new_labels); // implemented
201 [[deprecated("Please use relabel_(const std::vector<std::string> &new_labels) instead.")]] void
202 relabels_(const std::vector<std::string> &new_labels); // implemented
203 void relabel_(const std::vector<std::string> &old_labels,
204 const std::vector<std::string> &new_labels); // implemented
205 [[deprecated(
206 "Please use relabel_(const std::vector<std::string> &old_labels, const "
207 "std::vector<std::string> &new_labels) instead.")]] void
208 relabels_(const std::vector<std::string> &old_labels,
209 const std::vector<std::string> &new_labels); // implemented
210 void relabel_(const std::string &old_label, const std::string &new_label) {
211 this->set_label(old_label, new_label);
212 }
213 void relabel_(const cytnx_int64 &inx, const std::string &new_label) {
214 this->set_label(inx, new_label);
215 }
216
217 int uten_type() { return this->uten_type_id; }
218 std::string uten_type_str() const { return UTenType.getname(this->uten_type_id); }
219
221
222 // string labels!
223 virtual void Init(const std::vector<Bond> &bonds,
224 const std::vector<std::string> &in_labels = {},
225 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
226 const int &device = Device.cpu, const bool &is_diag = false,
227 const bool &no_alloc = false, const std::string &name = "");
228
229 virtual void Init_by_Tensor(const Tensor &in, const bool &is_diag = false,
230 const cytnx_int64 &rowrank = -1, const std::string &name = "");
231 virtual std::vector<cytnx_uint64> shape() const;
232 virtual std::vector<bool> signflip() const;
233 virtual std::vector<bool> &signflip_();
234 virtual bool is_blockform() const;
235 virtual bool is_contiguous() const;
236 virtual void to_(const int &device);
237 virtual boost::intrusive_ptr<UniTensor_base> to(const int &device);
238 virtual boost::intrusive_ptr<UniTensor_base> clone() const;
239 virtual unsigned int dtype() const;
240 virtual int device() const;
241 virtual std::string dtype_str() const;
242 virtual std::string device_str() const;
243 virtual void set_rowrank_(const cytnx_uint64 &new_rowrank);
244 virtual boost::intrusive_ptr<UniTensor_base> set_rowrank(const cytnx_uint64 &new_rowrank) const;
245
246 virtual boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,
247 const cytnx_int64 &rowrank = -1);
248 virtual boost::intrusive_ptr<UniTensor_base> permute(const std::vector<std::string> &mapper,
249 const cytnx_int64 &rowrank = -1);
250 // virtual boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,
251 // const cytnx_int64 &rowrank = -1);
252
253 virtual void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1);
254 virtual void permute_(const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1);
255
256 virtual boost::intrusive_ptr<UniTensor_base> permute_nosignflip(
257 const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1);
258 virtual boost::intrusive_ptr<UniTensor_base> permute_nosignflip(
259 const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1);
260 virtual void permute_nosignflip_(const std::vector<cytnx_int64> &mapper,
261 const cytnx_int64 &rowrank = -1);
262 virtual void permute_nosignflip_(const std::vector<std::string> &mapper,
263 const cytnx_int64 &rowrank = -1);
264 // virtual void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank =
265 // -1);
266
267 virtual void twist_(const cytnx_int64 &idx);
268 virtual void twist_(const std::string &label);
269 virtual void fermion_twists_();
270
271 virtual boost::intrusive_ptr<UniTensor_base> contiguous_();
272 virtual boost::intrusive_ptr<UniTensor_base> contiguous();
273 virtual boost::intrusive_ptr<UniTensor_base> apply_();
274 virtual boost::intrusive_ptr<UniTensor_base> apply();
275 virtual void print_diagram(const bool &bond_info = false) const;
276 virtual void print_blocks(const bool &full_info = true) const;
277 virtual void print_block(const cytnx_int64 &idx, const bool &full_info = true) const;
278
279 virtual boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const;
280
281 virtual cytnx_uint64 Nblocks() const { return 0; };
282 virtual Tensor get_block(const cytnx_uint64 &idx = 0) const; // return a copy of block
283 virtual Tensor get_block(const std::vector<cytnx_int64> &qnum,
284 const bool &force) const; // return a copy of block
285
286 virtual const Tensor &get_block_(const cytnx_uint64 &idx = 0)
287 const; // return a share view of block, this only work for non-symm tensor.
288 virtual const Tensor &get_block_(const std::vector<cytnx_int64> &qnum,
289 const bool &force) const; // return a copy of block
290 virtual Tensor &get_block_(const cytnx_uint64 &idx = 0); // return a share view of block, this
291 // only work for non-symm tensor.
292 virtual Tensor &get_block_(const std::vector<cytnx_int64> &qnum,
293 const bool &force); // return a copy of block
294 virtual bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const;
295
296 virtual std::vector<Tensor> get_blocks() const;
297 virtual const std::vector<Tensor> &get_blocks_(const bool &) const;
298 virtual std::vector<Tensor> &get_blocks_(const bool &);
299
300 virtual void put_block(const Tensor &in, const cytnx_uint64 &idx = 0);
301 virtual void put_block_(Tensor &in, const cytnx_uint64 &idx = 0);
302 virtual void put_block(const Tensor &in, const std::vector<cytnx_int64> &qnum);
303 virtual void put_block_(Tensor &in, const std::vector<cytnx_int64> &qnum);
304
305 // this will only work on non-symm tensor (DenseUniTensor)
306 virtual boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors);
307
308 // this will only work on non-symm tensor (DenseUniTensor)
309 virtual void set(const std::vector<Accessor> &accessors, const Tensor &rhs);
310
311 virtual void reshape_(const std::vector<cytnx_int64> &new_shape,
312 const cytnx_uint64 &rowrank = 0);
313 virtual boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape,
314 const cytnx_uint64 &rowrank = 0);
315 virtual boost::intrusive_ptr<UniTensor_base> to_dense();
316 virtual void to_dense_();
317 virtual void combineBond(const std::vector<std::string> &indicators, const bool &force = false);
318 virtual void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force,
319 const bool &by_label);
320 virtual void combineBonds(const std::vector<std::string> &indicators,
321 const bool &force = false);
322 virtual void combineBonds(const std::vector<cytnx_int64> &indicators,
323 const bool &force = false);
324 virtual boost::intrusive_ptr<UniTensor_base> contract(
325 const boost::intrusive_ptr<UniTensor_base> &rhs, const bool &mv_elem_self = false,
326 const bool &mv_elem_rhs = false);
327 virtual std::vector<Bond> getTotalQnums(const bool &physical = false);
328 virtual std::vector<std::vector<cytnx_int64>> get_blocks_qnums() const;
329 virtual void Trace_(const std::string &a, const std::string &b);
330 virtual void Trace_(const cytnx_int64 &a, const cytnx_int64 &b);
331
332 virtual boost::intrusive_ptr<UniTensor_base> Trace(const std::string &a, const std::string &b);
333 virtual boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b);
334
335 virtual boost::intrusive_ptr<UniTensor_base> relabel(
336 const std::vector<std::string> &new_labels);
337 virtual boost::intrusive_ptr<UniTensor_base> relabels(
338 const std::vector<std::string> &new_labels);
339
340 virtual boost::intrusive_ptr<UniTensor_base> relabel(
341 const std::vector<std::string> &old_labels, const std::vector<std::string> &new_labels);
342 virtual boost::intrusive_ptr<UniTensor_base> relabels(
343 const std::vector<std::string> &old_labels, const std::vector<std::string> &new_labels);
344
345 virtual boost::intrusive_ptr<UniTensor_base> relabel(const std::string &old_label,
346 const std::string &new_label);
347
348 virtual boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx,
349 const std::string &new_label);
350
351 virtual std::vector<Symmetry> syms() const;
352
353 // arithmetic
354 virtual void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
355 virtual void Add_(const Scalar &rhs);
356
357 virtual void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
358 virtual void Mul_(const Scalar &rhs);
359
360 virtual void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
361 virtual void Sub_(const Scalar &rhs);
362 virtual void lSub_(const Scalar &lhs);
363
364 virtual void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
365 virtual void Div_(const Scalar &rhs);
366 virtual void lDiv_(const Scalar &lhs);
367
368 virtual Tensor Norm() const;
369 virtual boost::intrusive_ptr<UniTensor_base> normalize();
370 virtual void normalize_();
371
372 virtual boost::intrusive_ptr<UniTensor_base> Conj();
373 virtual void Conj_();
374
375 virtual boost::intrusive_ptr<UniTensor_base> Transpose();
376 virtual void Transpose_();
377
378 virtual boost::intrusive_ptr<UniTensor_base> Dagger();
379 virtual void Dagger_();
380
381 virtual void tag();
382
383 virtual void truncate_(const std::string &label, const cytnx_uint64 &dim);
384 virtual void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim);
385
386 virtual bool elem_exists(const std::vector<cytnx_uint64> &locator) const;
387
388 // this a workaround, as virtual function cannot template.
389 virtual Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator);
390 virtual const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const;
391
392 virtual cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
393 const cytnx_complex128 &aux);
394 virtual cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
395 const cytnx_complex64 &aux);
396 virtual cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator,
397 const cytnx_double &aux);
398 virtual cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator,
399 const cytnx_float &aux);
400 virtual cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
401 const cytnx_uint64 &aux);
402 virtual cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
403 const cytnx_int64 &aux);
404 virtual cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
405 const cytnx_uint32 &aux);
406 virtual cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
407 const cytnx_int32 &aux);
408 virtual cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
409 const cytnx_uint16 &aux);
410 virtual cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
411 const cytnx_int16 &aux);
412
413 virtual const cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
414 const cytnx_complex128 &aux) const;
415 virtual const cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
416 const cytnx_complex64 &aux) const;
417 virtual const cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator,
418 const cytnx_double &aux) const;
419 virtual const cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator,
420 const cytnx_float &aux) const;
421 virtual const cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
422 const cytnx_uint64 &aux) const;
423 virtual const cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
424 const cytnx_int64 &aux) const;
425 virtual const cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
426 const cytnx_uint32 &aux) const;
427 virtual const cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
428 const cytnx_int32 &aux) const;
429 virtual const cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
430 const cytnx_uint16 &aux) const;
431 virtual const cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
432 const cytnx_int16 &aux) const;
433
434 virtual void from_(const boost::intrusive_ptr<UniTensor_base> &rhs, bool force,
435 cytnx_double tol = 0.);
436
437 virtual void group_basis_();
438 virtual const std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) const;
439 virtual std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx);
440 virtual const vec2d<cytnx_uint64> &get_itoi() const;
441 virtual vec2d<cytnx_uint64> &get_itoi();
442
443 virtual void _save_dispatch(std::fstream &f) const;
444 virtual void _load_dispatch(std::fstream &f);
445
446 virtual ~UniTensor_base(){};
447 };
449
450 //======================================================================
452 class DenseUniTensor : public UniTensor_base {
453 protected:
454 public:
455 Tensor _block;
456 std::vector<Tensor> _interface_block; // this is serves as interface for get_blocks_();
457 DenseUniTensor *clone_meta() const {
458 DenseUniTensor *tmp = new DenseUniTensor();
459 tmp->_bonds = vec_clone(this->_bonds);
460 tmp->_labels = this->_labels;
461 tmp->_is_braket_form = this->_is_braket_form;
462 tmp->_rowrank = this->_rowrank;
463 tmp->_is_diag = this->_is_diag;
464 tmp->_name = this->_name;
465 tmp->_is_tag = this->_is_tag;
466 return tmp;
467 }
468 //------------------------------------------
469
470 DenseUniTensor() { this->uten_type_id = UTenType.Dense; };
471 friend class UniTensor; // allow wrapper to access the private elems
472 // virtual functions
473
474 // void Init(const std::vector<Bond> &bonds, const std::vector<cytnx_int64> &in_labels = {},
475 // const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
476 // const int &device = Device.cpu, const bool &is_diag = false,
477 // const bool &no_alloc = false);
478
479 void Init(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
480 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
481 const int &device = Device.cpu, const bool &is_diag = false,
482 const bool &no_alloc = false, const std::string &name = "");
483 // this only work for non-symm tensor
484 void Init_by_Tensor(const Tensor &in_tensor, const bool &is_diag = false,
485 const cytnx_int64 &rowrank = -1, const std::string &name = "");
486 std::vector<cytnx_uint64> shape() const {
487 if (this->_is_diag) {
488 std::vector<cytnx_uint64> shape = this->_block.shape();
489 shape.push_back(shape[0]);
490 return shape;
491 } else {
492 return this->_block.shape();
493 }
494 }
495 bool is_blockform() const { return false; }
496 void to_(const int &device) { this->_block.to_(device); }
497 boost::intrusive_ptr<UniTensor_base> to(const int &device) {
498 if (this->device() == device) {
499 std::vector<Tensor> _interface_block; // this is serves as interface for get_blocks_();
500 return this;
501 } else {
502 boost::intrusive_ptr<UniTensor_base> out = this->clone();
503 out->to_(device);
504 return out;
505 }
506 }
507 void set_rowrank_(const cytnx_uint64 &new_rowrank) {
508 cytnx_error_msg(new_rowrank > this->_labels.size(),
509 "[ERROR] rowrank cannot exceed the rank of UniTensor.%s", "\n");
510 if (this->is_diag()) {
511 cytnx_error_msg(new_rowrank != 1, "[ERROR] rowrank should be [==1] when is_diag =true!.%s",
512 "\n");
513 }
514
515 this->_rowrank = new_rowrank;
516 }
517
518 boost::intrusive_ptr<UniTensor_base> set_rowrank(const cytnx_uint64 &new_rowrank) const {
519 DenseUniTensor *out_raw = this->clone_meta();
520 out_raw->_block = this->_block;
521 out_raw->set_rowrank_(new_rowrank);
522 boost::intrusive_ptr<UniTensor_base> out(out_raw);
523 return out;
524 }
525
526 boost::intrusive_ptr<UniTensor_base> clone() const {
527 DenseUniTensor *tmp = this->clone_meta();
528 tmp->_block = this->_block.clone();
529 boost::intrusive_ptr<UniTensor_base> out(tmp);
530 return out;
531 };
532 bool is_contiguous() const { return this->_block.is_contiguous(); }
533 unsigned int dtype() const { return this->_block.dtype(); }
534 int device() const { return this->_block.device(); }
535 std::string dtype_str() const { return Type.getname(this->_block.dtype()); }
536 std::string device_str() const { return Device.getname(this->_block.device()); }
546 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,
547 const cytnx_int64 &rowrank = -1);
548 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<std::string> &mapper,
549 const cytnx_int64 &rowrank = -1);
550
559 void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1);
560 void permute_(const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1);
561
562 void twist_(const cytnx_int64 &idx) override {
563 // do nothing for bosonic UniTensor
564 return;
565 }
566 void twist_(const std::string &label) override {
567 // do nothing for bosonic UniTensor
568 return;
569 }
570
571 void fermion_twists_() override {
572 // do nothing for bosonic UniTensor
573 return;
574 }
575
576 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &new_labels);
577 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &new_labels);
578
579 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &old_labels,
580 const std::vector<std::string> &new_labels);
581 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &old_labels,
582 const std::vector<std::string> &new_labels);
583
594 boost::intrusive_ptr<UniTensor_base> relabel(const std::string &old_label,
595 const std::string &new_label);
596 boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx,
597 const std::string &new_label);
598
599 boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const {
600 DenseUniTensor *tmp = this->clone_meta();
601 tmp->_block = this->_block.astype(dtype);
602 boost::intrusive_ptr<UniTensor_base> out(tmp);
603 return tmp;
604 }
605
606 std::vector<Symmetry> syms() const {
607 cytnx_error_msg(true, "[ERROR][DenseUniTensor] dense unitensor does not have symmetry.%s",
608 "\n");
609 return std::vector<Symmetry>();
610 }
611
612 boost::intrusive_ptr<UniTensor_base> contiguous_() {
613 this->_block.contiguous_();
614 return boost::intrusive_ptr<UniTensor_base>(this);
615 }
616 boost::intrusive_ptr<UniTensor_base> contiguous() {
617 // if contiguous then return self!
618 if (this->is_contiguous()) {
619 boost::intrusive_ptr<UniTensor_base> out(this);
620 return out;
621 } else {
622 DenseUniTensor *tmp = this->clone_meta();
623 tmp->_block = this->_block.contiguous();
624 boost::intrusive_ptr<UniTensor_base> out(tmp);
625 return out;
626 }
627 }
628
629 boost::intrusive_ptr<UniTensor_base> apply_() {
630 return boost::intrusive_ptr<UniTensor_base>(this);
631 }
632 boost::intrusive_ptr<UniTensor_base> apply() {
633 // just return self
634 boost::intrusive_ptr<UniTensor_base> out(this);
635 return out;
636 }
637
638 void print_diagram(const bool &bond_info = false) const;
639 void print_blocks(const bool &full_info = true) const;
640 void print_block(const cytnx_int64 &idx, const bool &full_info = true) const;
641 Tensor get_block() const { return this->_block.clone(); }
642 Tensor get_block(const cytnx_uint64 &idx) const {
643 cytnx_error_msg(idx != 0,
644 "[ERROR][DenseUniTensor] Dense tensor has only one block, block number %llu "
645 "invalid. Use get_block(0).\n",
646 (unsigned long long)idx);
647 return this->_block.clone();
648 }
649
650 Tensor get_block(const std::vector<cytnx_int64> &qnum, const bool &force) const {
652 true, "[ERROR][DenseUniTensor] try to get_block() using qnum on a non-symmetry UniTensor%s",
653 "\n");
654 return Tensor();
655 }
656 // return a share view of block, this only work for non-symm tensor.
657 const Tensor &get_block_(const std::vector<cytnx_int64> &qnum, const bool &force) const {
659 true,
660 "[ERROR][DenseUniTensor] try to get_block_() using qnum on a non-symmetry UniTensor%s",
661 "\n");
662 return this->_block;
663 }
664 Tensor &get_block_(const std::vector<cytnx_int64> &qnum, const bool &force) {
666 true,
667 "[ERROR][DenseUniTensor] try to get_block_() using qnum on a non-symmetry UniTensor%s",
668 "\n");
669 return this->_block;
670 }
671
672 // return a share view of block, this only work for non-symm tensor.
673 Tensor &get_block_() { return this->_block; }
674 Tensor &get_block_(const cytnx_uint64 &idx) {
675 cytnx_error_msg(idx != 0,
676 "[ERROR][DenseUniTensor] Dense tensor has only one block, block number %llu "
677 "invalid. Use get_block_(0).\n",
678 (unsigned long long)idx);
679 return this->_block;
680 }
681 // return a share view of block, this only work for non-symm tensor.
682 const Tensor &get_block_() const { return this->_block; }
683 const Tensor &get_block_(const cytnx_uint64 &idx) const {
684 cytnx_error_msg(idx != 0,
685 "[ERROR][DenseUniTensor] Dense tensor has only one block, block number %llu "
686 "invalid. Use get_block_(0).\n",
687 (unsigned long long)idx);
688 return this->_block;
689 }
690
691 cytnx_uint64 Nblocks() const { return 1; };
692 std::vector<Tensor> get_blocks() const {
693 std::vector<Tensor> out;
695 true, "[ERROR][DenseUniTensor] Cannot use get_blocks(), use get_block() instead!%s", "\n");
696 return out; // this will not share memory!!
697 }
698 const std::vector<Tensor> &get_blocks_(const bool &silent = false) const {
700 true, "[ERROR][DenseUniTensor] Cannot use get_blocks_(), use get_block_() instead!%s",
701 "\n");
702 return this->_interface_block; // this will not share memory!!
703 }
704 std::vector<Tensor> &get_blocks_(const bool &silent = false) {
706 true, "[ERROR][DenseUniTensor] Cannot use get_blocks_(), use get_block_() instead!%s",
707 "\n");
708 return this->_interface_block; // this will not share memory!!
709 }
710
711 void put_block(const Tensor &in) {
712 // We don't check the dtype for DenseUniTensor, since it'll be more convenient to change
713 // DenseUniTensor's dtype
714
715 // cytnx_error_msg(in.dtype() != this->dtype(),
716 // "[ERROR][DenseUniTensor][put_block] The input tensor dtype does not
717 // match.%s",
718 // "\n");
719 cytnx_error_msg(in.device() != this->device(),
720 "[ERROR][DenseUniTensor][put_block] The input tensor device does not "
721 "match.%s",
722 "\n");
723 // We shouldn't check the contiguous
724 // cytnx_error_msg(!in.contiguous());
725 if (this->is_diag()) {
727 in.shape() != this->_block.shape(),
728 "[ERROR][DenseUniTensor][put_block] the input tensor shape does not match.%s", "\n");
729 this->_block = in.clone();
730 } else {
732 in.shape() != this->shape(),
733 "[ERROR][DenseUniTensor][put_block] the input tensor shape does not match.%s", "\n");
734 this->_block = in.clone();
735 }
736 }
737 void put_block(const Tensor &in, const cytnx_uint64 &idx) {
738 cytnx_error_msg(idx != 0,
739 "[ERROR][DenseUniTensor] Dense tensor has only one block, block number %llu "
740 "invalid. Use put_block(0).\n",
741 (unsigned long long)idx);
742 put_block(in);
743 }
744 // share view of the block
745 void put_block_(Tensor &in) {
746 // We don't check the dtype for DenseUniTensor, since it'll be more convenient to change
747 // DenseUniTensor's dtype
748
749 // cytnx_error_msg(in.dtype() != this->dtype(),
750 // "[ERROR][DenseUniTensor][put_block] The input tensor dtype does not
751 // match.%s",
752 // "\n");
753 cytnx_error_msg(in.device() != this->device(),
754 "[ERROR][DenseUniTensor][put_block] The input tensor device does not "
755 "match.%s",
756 "\n");
757 // We shouldn't check the contiguous
758 // cytnx_error_msg(!in.contiguous());
759 if (this->is_diag()) {
761 in.shape() != this->_block.shape(),
762 "[ERROR][DenseUniTensor][put_block] the input tensor shape does not match.%s", "\n");
763 this->_block = in;
764 } else {
766 in.shape() != this->shape(),
767 "[ERROR][DenseUniTensor][put_block] the input tensor shape does not match.%s", "\n");
768 this->_block = in;
769 }
770 }
771 void put_block_(Tensor &in, const cytnx_uint64 &idx) {
772 cytnx_error_msg(idx != 0,
773 "[ERROR][DenseUniTensor] Dense tensor has only one block, block number %llu "
774 "invalid. Use put_block_(0).\n",
775 (unsigned long long)idx);
776 put_block_(in);
777 }
778
779 void put_block(const Tensor &in, const std::vector<cytnx_int64> &qnum) {
781 true, "[ERROR][DenseUniTensor] try to put_block using qnum on a non-symmetry UniTensor%s",
782 "\n");
783 }
784 void put_block_(Tensor &in, const std::vector<cytnx_int64> &qnum) {
786 true, "[ERROR][DenseUniTensor] try to put_block using qnum on a non-symmetry UniTensor%s",
787 "\n");
788 }
789 // these two methods only work on non-symm tensor (DenseUniTensor)
790 boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors);
791 void set(const std::vector<Accessor> &accessors, const Tensor &rhs);
792
793 void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank = 0);
794 boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape,
795 const cytnx_uint64 &rowrank = 0);
796 boost::intrusive_ptr<UniTensor_base> to_dense();
797 void to_dense_();
798 void combineBond(const std::vector<std::string> &indicators, const bool &force = true);
799 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force,
800 const bool &by_label);
801 void combineBonds(const std::vector<std::string> &indicators, const bool &force = true);
802 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force = true);
803 boost::intrusive_ptr<UniTensor_base> contract(const boost::intrusive_ptr<UniTensor_base> &rhs,
804 const bool &mv_elem_self = false,
805 const bool &mv_elem_rhs = false);
806 std::vector<Bond> getTotalQnums(const bool &physical = false) {
807 cytnx_error_msg(true, "[ERROR][DenseUniTensor] %s",
808 "getTotalQnums can only operate on UniTensor with symmetry.\n");
809 return std::vector<Bond>();
810 }
811
812 std::vector<std::vector<cytnx_int64>> get_blocks_qnums() const {
813 cytnx_error_msg(true, "[ERROR][DenseUniTensor] %s",
814 "get_blocks_qnums can only operate on UniTensor with symmetry.\n");
815 return std::vector<std::vector<cytnx_int64>>();
816 }
817
818 bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const {
819 if (rhs->uten_type() != UTenType.Dense) return false;
820
821 return this->get_block_().same_data(rhs->get_block_());
822 }
823
824 ~DenseUniTensor(){};
825
826 // arithmetic
827 void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
828 void Add_(const Scalar &rhs);
829
830 void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
831 void Mul_(const Scalar &rhs);
832
833 void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
834 void Sub_(const Scalar &rhs);
835 void lSub_(const Scalar &lhs);
836
837 void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
838 void Div_(const Scalar &rhs);
839 void lDiv_(const Scalar &lhs);
840
841 void Conj_() { this->_block.Conj_(); };
842
843 boost::intrusive_ptr<UniTensor_base> Conj() {
844 boost::intrusive_ptr<UniTensor_base> out = this->clone();
845 out->Conj_();
846 return out;
847 }
848
849 boost::intrusive_ptr<UniTensor_base> Transpose() {
850 boost::intrusive_ptr<UniTensor_base> out = this->clone();
851 out->Transpose_();
852 return out;
853 }
854 void Transpose_();
855
856 boost::intrusive_ptr<UniTensor_base> normalize() {
857 boost::intrusive_ptr<UniTensor_base> out = this->clone();
858 out->normalize_();
859 return out;
860 }
861 void normalize_();
862
863 boost::intrusive_ptr<UniTensor_base> Dagger() {
864 boost::intrusive_ptr<UniTensor_base> out = this->Conj();
865 out->Transpose_();
866 return out;
867 }
868 void Dagger_() {
869 this->Conj_();
870 this->Transpose_();
871 }
881 void Trace_(const cytnx_int64 &a, const cytnx_int64 &b);
882 void Trace_(const std::string &a, const std::string &b);
883 boost::intrusive_ptr<UniTensor_base> Trace(const std::string &a, const std::string &b) {
884 boost::intrusive_ptr<UniTensor_base> out = this->clone();
885 out->Trace_(a, b);
886 return out;
887 }
888 boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b) {
889 boost::intrusive_ptr<UniTensor_base> out = this->clone();
890 out->Trace_(a, b);
891 return out;
892 }
893
894 Tensor Norm() const;
895
896 const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const {
898 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
899 "\n");
900 return Scalar::Sproxy();
901 }
902 const cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
903 const cytnx_complex128 &aux) const {
905 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
906 "\n");
907 return cytnx_complex128(0, 0);
908 }
909 const cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
910 const cytnx_complex64 &aux) const {
912 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
913 "\n");
914 return cytnx_complex64(0, 0);
915 }
916 const cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator,
917 const cytnx_double &aux) const {
919 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
920 "\n");
921 return 0;
922 }
923 const cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator,
924 const cytnx_float &aux) const {
926 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
927 "\n");
928 return 0;
929 }
930 const cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
931 const cytnx_uint64 &aux) const {
933 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
934 "\n");
935 return 0;
936 }
937 const cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
938 const cytnx_int64 &aux) const {
940 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
941 "\n");
942 return 0;
943 }
944 const cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
945 const cytnx_uint32 &aux) const {
947 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
948 "\n");
949 return 0;
950 }
951 const cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
952 const cytnx_int32 &aux) const {
954 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
955 "\n");
956 return 0;
957 }
958 const cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
959 const cytnx_uint16 &aux) const {
961 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
962 "\n");
963 return 0;
964 }
965 const cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
966 const cytnx_int16 &aux) const {
968 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
969 "\n");
970 return 0;
971 }
972
973 Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) {
975 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
976 "\n");
977 return Scalar::Sproxy();
978 }
979 cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
980 const cytnx_complex128 &aux) {
982 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
983 "\n");
984 return *(cytnx_complex128 *)nullptr;
985 }
986 cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
987 const cytnx_complex64 &aux) {
989 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
990 "\n");
991 return *(cytnx_complex64 *)nullptr;
992 }
993 cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux) {
995 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
996 "\n");
997 return *(cytnx_double *)nullptr;
998 }
999 cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux) {
1001 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1002 "\n");
1003 return *(cytnx_float *)nullptr;
1004 }
1005 cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux) {
1007 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1008 "\n");
1009 return *(cytnx_uint64 *)nullptr;
1010 }
1011 cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux) {
1013 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1014 "\n");
1015 return *(cytnx_int64 *)nullptr;
1016 }
1017 cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux) {
1019 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1020 "\n");
1021 return *(cytnx_uint32 *)nullptr;
1022 }
1023 cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux) {
1025 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1026 "\n");
1027 return *(cytnx_int32 *)nullptr;
1028 }
1029 cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux) {
1031 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1032 "\n");
1033 return *(cytnx_uint16 *)nullptr;
1034 }
1035 cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux) {
1037 true, "[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s",
1038 "\n");
1039 return *(cytnx_int16 *)nullptr;
1040 }
1041
1042 bool elem_exists(const std::vector<cytnx_uint64> &locator) const {
1044 true, "[ERROR][DenseUniTensor] elem_exists can only be used on UniTensor with Symmetry.%s",
1045 "\n");
1046 }
1047 void tag() {
1048 if (!this->is_tag()) {
1049 for (int i = 0; i < this->_rowrank; i++) {
1050 this->_bonds[i].set_type(BD_KET);
1051 }
1052 for (int i = this->_rowrank; i < this->_bonds.size(); i++) {
1053 this->_bonds[i].set_type(BD_BRA);
1054 }
1055 this->_is_tag = true;
1056 this->_is_braket_form = this->_update_braket();
1057 }
1058 }
1068 void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim);
1069 void truncate_(const std::string &label, const cytnx_uint64 &dim);
1070
1071 void from_(const boost::intrusive_ptr<UniTensor_base> &rhs, bool force, cytnx_double tol = 0.);
1072
1073 void group_basis_() {
1074 cytnx_warning_msg(true, "[WARNING] group basis will not have any effect on DensUniTensor.%s",
1075 "\n");
1076 }
1077
1078 void _save_dispatch(std::fstream &f) const;
1079 void _load_dispatch(std::fstream &f);
1080
1081 const std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) const {
1082 cytnx_error_msg(true, "[ERROR] get_qindices can only be unsed on UniTensor with Symmetry.%s",
1083 "\n");
1084 }
1085 std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) {
1086 cytnx_error_msg(true, "[ERROR] get_qindices can only be unsed on UniTensor with Symmetry.%s",
1087 "\n");
1088 }
1089
1090 const vec2d<cytnx_uint64> &get_itoi() const {
1091 cytnx_error_msg(true, "[ERROR] get_itoi can only be unsed on UniTensor with Symmetry.%s",
1092 "\n");
1093 }
1094 vec2d<cytnx_uint64> &get_itoi() {
1095 cytnx_error_msg(true, "[ERROR] get_itoi can only be unsed on UniTensor with Symmetry.%s",
1096 "\n");
1097 }
1098
1099 // end virtual function
1100 };
1102
1103 //======================================================================
1105 class BlockUniTensor : public UniTensor_base {
1106 protected:
1107 public:
1108 std::vector<std::vector<cytnx_uint64>>
1109 _inner_to_outer_idx; // stores the qindices for each block
1110 std::vector<Tensor> _blocks;
1111 Tensor NullRefTensor; // this returns when access block does not exists!
1112
1113 // given an index list [loc], get qnums from this->_bonds[loc] and return the combined qnums
1114 // calculated from Symm object! this assume 1. symmetry are the same for each bond!
1115 // 2. total_qns are feeded with size len(symmetry)
1116 void _fx_get_total_fluxs(std::vector<cytnx_uint64> &loc, const std::vector<Symmetry> &syms,
1117 std::vector<cytnx_int64> &total_qns) {
1118 memset(&total_qns[0], 0, sizeof(cytnx_int64) * total_qns.size());
1119
1120 for (cytnx_int32 i = 0; i < syms.size(); i++) {
1121 if (this->_bonds[0].type() == BD_BRA)
1122 total_qns[i] = syms[i].reverse_rule(this->_bonds[0]._impl->_qnums[loc[0]][i]);
1123 else
1124 total_qns[i] = this->_bonds[0]._impl->_qnums[loc[0]][i];
1125
1126 for (auto j = 1; j < loc.size(); j++) {
1127 if (this->_bonds[j].type() == BD_BRA)
1128 total_qns[i] = syms[i].combine_rule(
1129 total_qns[i], syms[i].reverse_rule(this->_bonds[j]._impl->_qnums[loc[j]][i]));
1130 else {
1131 total_qns[i] =
1132 syms[i].combine_rule(total_qns[i], this->_bonds[j]._impl->_qnums[loc[j]][i]);
1133 }
1134 }
1135 }
1136 }
1137
1138 void _fx_locate_elem(cytnx_int64 &bidx, std::vector<cytnx_uint64> &loc_in_T,
1139 const std::vector<cytnx_uint64> &locator) const;
1140
1141 // internal function, grouping all duplicate qnums in all bonds
1142 void _fx_group_duplicates(const std::vector<cytnx_uint64> &dup_bond_idxs,
1143 const std::vector<std::vector<cytnx_uint64>> &idx_mappers);
1144
1145 void set_meta(BlockUniTensor *tmp, const bool &inner, const bool &outer) const {
1146 // outer meta
1147 if (outer) {
1148 tmp->_bonds = vec_clone(this->_bonds);
1149 tmp->_labels = this->_labels;
1150 tmp->_is_braket_form = this->_is_braket_form;
1151 tmp->_rowrank = this->_rowrank;
1152 tmp->_name = this->_name;
1153 }
1154
1155 tmp->_is_diag = this->_is_diag;
1156
1157 // inner meta
1158 if (inner) {
1159 tmp->_inner_to_outer_idx = this->_inner_to_outer_idx;
1160 }
1161 }
1162
1163 BlockUniTensor *clone_meta(const bool &inner, const bool &outer) const {
1164 BlockUniTensor *tmp = new BlockUniTensor();
1165 this->set_meta(tmp, inner, outer);
1166 return tmp;
1167 };
1168
1169 friend class UniTensor;
1170 BlockUniTensor() {
1171 this->uten_type_id = UTenType.Block;
1172 this->_is_tag = true;
1173 }
1174
1175 // virtual functions:
1176 // void Init(const std::vector<Bond> &bonds, const std::vector<cytnx_int64> &in_labels = {},
1177 // const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
1178 // const int &device = Device.cpu, const bool &is_diag = false,
1179 // const bool &no_alloc = false);
1180
1181 void Init(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
1182 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
1183 const int &device = Device.cpu, const bool &is_diag = false,
1184 const bool &no_alloc = false, const std::string &name = "");
1185
1186 void Init_by_Tensor(const Tensor &in_tensor, const bool &is_diag = false,
1187 const cytnx_int64 &rowrank = -1, const std::string &name = "") {
1189 true, "[ERROR][BlockUniTensor] Cannot use Init_by_tensor() on a BlockUniTensor.%s", "\n");
1190 }
1191
1192 std::vector<cytnx_uint64> shape() const {
1193 std::vector<cytnx_uint64> out(this->_bonds.size());
1194 for (cytnx_uint64 i = 0; i < out.size(); i++) {
1195 out[i] = this->_bonds[i].dim();
1196 }
1197 return out;
1198 }
1199
1200 bool is_blockform() const { return true; }
1201 bool is_contiguous() const {
1202 bool out = true;
1203 for (int i = 0; i < this->_blocks.size(); i++) {
1204 out &= this->_blocks[i].is_contiguous();
1205 }
1206 return out;
1207 };
1208
1209 cytnx_uint64 Nblocks() const { return this->_blocks.size(); };
1210
1211 void to_(const int &device) {
1212 for (cytnx_uint64 i = 0; i < this->_blocks.size(); i++) {
1213 this->_blocks[i].to_(device);
1214 }
1215 };
1216
1217 boost::intrusive_ptr<UniTensor_base> to(const int &device) {
1218 if (this->device() == device) {
1219 return this;
1220 } else {
1221 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1222 out->to_(device);
1223 return out;
1224 }
1225 };
1226
1227 boost::intrusive_ptr<UniTensor_base> clone() const {
1228 BlockUniTensor *tmp = this->clone_meta(true, true);
1229 tmp->_blocks = vec_clone(this->_blocks);
1230 boost::intrusive_ptr<UniTensor_base> out(tmp);
1231 return out;
1232 };
1233
1234 unsigned int dtype() const {
1235 //[21 Aug 2024] This is a copy from BlockUniTensor;
1236 #ifdef UNI_DEBUG
1237 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
1238 "\n");
1239 #endif
1240 return this->_blocks.size() < 1 ? Type.Void : this->_blocks[0].dtype();
1241 };
1242 int device() const {
1243 //[21 Aug 2024] This is a copy from BlockUniTensor;
1244 #ifdef UNI_DEBUG
1245 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
1246 "\n");
1247 #endif
1248 return this->_blocks.size() < 1 ? -404 : this->_blocks[0].device();
1249 };
1250 std::string dtype_str() const {
1251 //[21 Aug 2024] This is a copy from BlockUniTensor;
1252 #ifdef UNI_DEBUG
1253 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
1254 "\n");
1255 #endif
1256 return this->_blocks.size() < 1 ? "Void, no valid blocks" : this->_blocks[0].dtype_str();
1257 };
1258 std::string device_str() const {
1259 //[21 Aug 2024] This is a copy from BlockUniTensor;
1260 #ifdef UNI_DEBUG
1261 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
1262 "\n");
1263 #endif
1264 return this->_blocks.size() < 1 ? "None, no valid blocks" : this->_blocks[0].device_str();
1265 };
1266
1267 Tensor get_block(const cytnx_uint64 &idx = 0) const {
1268 cytnx_error_msg(idx >= this->_blocks.size(), "[ERROR][BlockUniTensor] index out of range%s",
1269 "\n");
1270 return this->_blocks[idx].clone();
1271 };
1272
1273 // this one for Block will return the indicies!!
1274 Tensor get_block(const std::vector<cytnx_int64> &indices, const bool &force_return) const {
1275 cytnx_error_msg(indices.size() != this->rank(),
1276 "[ERROR][get_block][BlockUniTensor] len(indices) must be the same as the "
1277 "Tensor rank (number of legs).%s",
1278 "\n");
1279
1280 std::vector<cytnx_uint64> inds(indices.begin(), indices.end());
1281
1282 // find if the indices specify exists!
1283 cytnx_int64 b = -1;
1284 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
1285 if (inds == this->_inner_to_outer_idx[i]) {
1286 b = i;
1287 break;
1288 }
1289 }
1290
1291 if (b < 0) {
1292 if (force_return) {
1293 return NullRefTensor;
1294 } else {
1295 cytnx_error_msg(true,
1296 "[ERROR][get_block][BlockUniTensor] no avaliable block exists, "
1297 "force_return=false, so "
1298 "error throws. \n If you want to return an empty block without "
1299 "error when block is "
1300 "not avaliable, set force_return=True.%s",
1301 "\n");
1302 }
1303 } else {
1304 return this->_blocks[b].clone();
1305 }
1306 }
1307
1308 const Tensor &get_block_(const cytnx_uint64 &idx = 0) const {
1309 cytnx_error_msg(idx >= this->_blocks.size(), "[ERROR][BlockUniTensor] index out of range%s",
1310 "\n");
1311 return this->_blocks[idx];
1312 };
1313
1314 Tensor &get_block_(const cytnx_uint64 &idx = 0) {
1315 cytnx_error_msg(idx >= this->_blocks.size(), "[ERROR][BlockUniTensor] index out of range%s",
1316 "\n");
1317 return this->_blocks[idx];
1318 };
1319
1320 const Tensor &get_block_(const std::vector<cytnx_int64> &indices,
1321 const bool &force_return) const {
1322 cytnx_error_msg(indices.size() != this->rank(),
1323 "[ERROR][get_block][BlockUniTensor] len(indices) must be the same as the "
1324 "Tensor rank (number of legs).%s",
1325 "\n");
1326
1327 std::vector<cytnx_uint64> inds(indices.begin(), indices.end());
1328
1329 // find if the indices specify exists!
1330 cytnx_int64 b = -1;
1331 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
1332 if (inds == this->_inner_to_outer_idx[i]) {
1333 b = i;
1334 break;
1335 }
1336 }
1337
1338 if (b < 0) {
1339 if (force_return) {
1340 return this->NullRefTensor;
1341 } else {
1342 cytnx_error_msg(true,
1343 "[ERROR][get_block][BlockUniTensor] no avaliable block exists, "
1344 "force_return=false, so "
1345 "error throws. \n If you want to return an empty block without "
1346 "error when block is "
1347 "not avaliable, set force_return=True.%s",
1348 "\n");
1349 }
1350 } else {
1351 return this->_blocks[b];
1352 }
1353 }
1354
1355 Tensor &get_block_(const std::vector<cytnx_int64> &indices, const bool &force_return) {
1356 cytnx_error_msg(indices.size() != this->rank(),
1357 "[ERROR][get_block][BlockUniTensor] len(indices) must be the same as the "
1358 "Tensor rank (number of legs).%s",
1359 "\n");
1360
1361 std::vector<cytnx_uint64> inds(indices.begin(), indices.end());
1362
1363 // find if the indices specify exists!
1364 cytnx_int64 b = -1;
1365 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
1366 if (inds == this->_inner_to_outer_idx[i]) {
1367 b = i;
1368 break;
1369 }
1370 }
1371
1372 if (b < 0) {
1373 if (force_return) {
1374 return this->NullRefTensor;
1375 } else {
1376 cytnx_error_msg(true,
1377 "[ERROR][get_block][BlockUniTensor] no avaliable block exists, "
1378 "force_return=false, so "
1379 "error throws. \n If you want to return an empty block without "
1380 "error when block is "
1381 "not avaliable, set force_return=True.%s",
1382 "\n");
1383 }
1384 } else {
1385 return this->_blocks[b];
1386 }
1387 }
1388
1389 std::vector<Tensor> get_blocks() const { return vec_clone(this->_blocks); }
1390 const std::vector<Tensor> &get_blocks_(const bool &) const { return this->_blocks; }
1391 std::vector<Tensor> &get_blocks_(const bool &) { return this->_blocks; }
1392
1393 bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const {
1394 if (rhs->uten_type() != UTenType.Block) return false;
1395 if (rhs->get_blocks_(1).size() != this->get_blocks_(1).size()) return false;
1396
1397 for (int i = 0; i < rhs->get_blocks_(1).size(); i++)
1398 if (this->get_blocks_(1)[i].same_data(rhs->get_blocks_(1)[i]) == false) return false;
1399
1400 return true;
1401 }
1402
1403 void set_rowrank_(const cytnx_uint64 &new_rowrank) {
1404 cytnx_error_msg(new_rowrank > this->rank(),
1405 "[ERROR][BlockUniTensor] rowrank should be [>=0] and [<=UniTensor.rank].%s",
1406 "\n");
1407 if (this->is_diag()) {
1408 cytnx_error_msg(new_rowrank != 1,
1409 "[ERROR][BlockUniTensor] rowrank should be [==1] when is_diag =true!.%s",
1410 "\n");
1411 }
1412 this->_rowrank = new_rowrank;
1413 this->_is_braket_form = this->_update_braket();
1414 }
1415
1416 boost::intrusive_ptr<UniTensor_base> set_rowrank(const cytnx_uint64 &new_rowrank) const {
1417 BlockUniTensor *tmp = this->clone_meta(true, true);
1418 tmp->_blocks = this->_blocks;
1419 tmp->set_rowrank_(new_rowrank);
1420 boost::intrusive_ptr<UniTensor_base> out(tmp);
1421 return out;
1422 }
1423
1424 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,
1425 const cytnx_int64 &rowrank = -1);
1426 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<std::string> &mapper,
1427 const cytnx_int64 &rowrank = -1);
1428
1429 void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1);
1430 void permute_(const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1);
1431
1432 void twist_(const cytnx_int64 &idx) override {
1433 // do nothing for bosonic UniTensor
1434 return;
1435 }
1436 void fermion_twists_() override {
1437 // do nothing for bosonic UniTensor
1438 return;
1439 }
1440 void twist_(const std::string &label) override {
1441 // do nothing for bosonic UniTensor
1442 return;
1443 }
1444
1445 boost::intrusive_ptr<UniTensor_base> contiguous_() {
1446 for (unsigned int b = 0; b < this->_blocks.size(); b++) this->_blocks[b].contiguous_();
1447 return boost::intrusive_ptr<UniTensor_base>(this);
1448 }
1449 boost::intrusive_ptr<UniTensor_base> contiguous();
1450
1451 boost::intrusive_ptr<UniTensor_base> apply_() {
1452 return boost::intrusive_ptr<UniTensor_base>(this);
1453 }
1454 boost::intrusive_ptr<UniTensor_base> apply() {
1455 // just return self
1456 boost::intrusive_ptr<UniTensor_base> out(this);
1457 return out;
1458 }
1459
1460 void print_diagram(const bool &bond_info = false) const;
1461 void print_blocks(const bool &full_info = true) const;
1462 void print_block(const cytnx_int64 &idx, const bool &full_info = true) const;
1463
1464 boost::intrusive_ptr<UniTensor_base> contract(const boost::intrusive_ptr<UniTensor_base> &rhs,
1465 const bool &mv_elem_self = false,
1466 const bool &mv_elem_rhs = false);
1467
1468 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &new_labels);
1469 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &new_labels);
1470
1471 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &old_labels,
1472 const std::vector<std::string> &new_labels);
1473 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &old_labels,
1474 const std::vector<std::string> &new_labels);
1475
1476 boost::intrusive_ptr<UniTensor_base> relabel(const std::string &old_label,
1477 const std::string &new_label);
1478 boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx,
1479 const std::string &new_label);
1480
1481 std::vector<Symmetry> syms() const;
1482
1483 void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank = 0) {
1484 cytnx_error_msg(true, "[ERROR] Cannot reshape a UniTensor with symmetry.%s", "\n");
1485 }
1486 boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape,
1487 const cytnx_uint64 &rowrank = 0) {
1488 cytnx_error_msg(true, "[ERROR] Cannot reshape a UniTensor with symmetry.%s", "\n");
1489 return nullptr;
1490 }
1491
1492 boost::intrusive_ptr<UniTensor_base> to_dense();
1493 void to_dense_();
1494
1495 boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const {
1496 BlockUniTensor *tmp = this->clone_meta(true, true);
1497 tmp->_blocks.resize(this->_blocks.size());
1498 for (cytnx_int64 blk = 0; blk < this->_blocks.size(); blk++) {
1499 tmp->_blocks[blk] = this->_blocks[blk].astype(dtype);
1500 }
1501 boost::intrusive_ptr<UniTensor_base> out(tmp);
1502 return out;
1503 };
1504
1505 // this will only work on non-symm tensor (DenseUniTensor)
1506 boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors) {
1508 true,
1509 "[ERROR][BlockUniTensor][get] Cannot use get on a UniTensor with "
1510 "Symmetry.\n suggestion: try get_block/get_block_/get_blocks/get_blocks_ first.%s",
1511 "\n");
1512 return nullptr;
1513 }
1514
1515 // this will only work on non-symm tensor (DenseUniTensor)
1516 void set(const std::vector<Accessor> &accessors, const Tensor &rhs) {
1518 true,
1519 "[ERROR][BlockUniTensor][get] Cannot use get on a UniTensor with "
1520 "Symmetry.\n suggestion: try get_block/get_block_/get_blocks/get_blocks_ first.%s",
1521 "\n");
1522 }
1523
1524 void put_block(const Tensor &in, const cytnx_uint64 &idx = 0) {
1525 cytnx_error_msg(in.dtype() != this->dtype(),
1526 "[ERROR][BlockUniTensor][put_block] The input tensor dtype does not match.%s",
1527 "\n");
1528 cytnx_error_msg(in.device() != this->device(),
1529 "[ERROR][BlockUniTensor][put_block] The input tensor device does not "
1530 "match.%s",
1531 "\n");
1532 // We shouldn't check the contiguous
1533 // cytnx_error_msg(!in.contiguous());
1534 cytnx_error_msg(idx >= this->_blocks.size(), "[ERROR][BlockUniTensor] index out of range%s",
1535 "\n");
1536 cytnx_error_msg(in.shape() != this->_blocks[idx].shape(),
1537 "[ERROR][BlockUniTensor] the shape of input tensor does not match the shape "
1538 "of block @ idx=%d\n",
1539 idx);
1540
1541 this->_blocks[idx] = in.clone();
1542 }
1543 void put_block_(Tensor &in, const cytnx_uint64 &idx = 0) {
1544 cytnx_error_msg(in.dtype() != this->dtype(),
1545 "[ERROR][BlockUniTensor][put_block] The input tensor dtype does not match.%s",
1546 "\n");
1547 cytnx_error_msg(in.device() != this->device(),
1548 "[ERROR][BlockUniTensor][put_block] The input tensor device does not "
1549 "match.%s",
1550 "\n");
1551 // We shouldn't check the contiguous
1552 // cytnx_error_msg(!in.contiguous());
1553 cytnx_error_msg(idx >= this->_blocks.size(), "[ERROR][BlockUniTensor] index out of range%s",
1554 "\n");
1555 cytnx_error_msg(in.shape() != this->_blocks[idx].shape(),
1556 "[ERROR][BlockUniTensor] the shape of input tensor does not match the shape "
1557 "of block @ idx=%d\n",
1558 idx);
1559
1560 this->_blocks[idx] = in;
1561 }
1562 void put_block(const Tensor &in, const std::vector<cytnx_int64> &indices) {
1563 cytnx_error_msg(in.dtype() != this->dtype(),
1564 "[ERROR][BlockUniTensor][put_block] The input tensor dtype does not match.%s",
1565 "\n");
1566 cytnx_error_msg(in.device() != this->device(),
1567 "[ERROR][BlockUniTensor][put_block] The input tensor device does not "
1568 "match.%s",
1569 "\n");
1570 // We shouldn't check the contiguous
1571 // cytnx_error_msg(!in.contiguous());
1572 cytnx_error_msg(indices.size() != this->rank(),
1573 "[ERROR][put_block][BlockUniTensor] len(indices) must be the same as the "
1574 "Tensor rank (number of legs).%s",
1575 "\n");
1576
1577 std::vector<cytnx_uint64> inds(indices.begin(), indices.end());
1578
1579 // find if the indices specify exists!
1580 cytnx_int64 b = -1;
1581 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
1582 if (inds == this->_inner_to_outer_idx[i]) {
1583 b = i;
1584 break;
1585 }
1586 }
1587
1588 if (b < 0) {
1589 cytnx_error_msg(true, "[ERROR][put_block][BlockUniTensor] no avaliable block exists.%s",
1590 "\n");
1591 } else {
1593 in.shape() != this->_blocks[b].shape(),
1594 "[ERROR][BlockUniTensor] the shape of input tensor does not match the shape "
1595 "of block @ idx=%d\n",
1596 b);
1597
1598 this->_blocks[b] = in.clone();
1599 }
1600 }
1601 void put_block_(Tensor &in, const std::vector<cytnx_int64> &indices) {
1602 cytnx_error_msg(in.dtype() != this->dtype(),
1603 "[ERROR][BlockUniTensor][put_block] The input tensor dtype does not match.%s",
1604 "\n");
1605 cytnx_error_msg(in.device() != this->device(),
1606 "[ERROR][BlockUniTensor][put_block] The input tensor device does not "
1607 "match.%s",
1608 "\n");
1609 // We shouldn't check the contiguous
1610 // cytnx_error_msg(!in.contiguous());
1611 cytnx_error_msg(indices.size() != this->rank(),
1612 "[ERROR][put_block][BlockUniTensor] len(indices) must be the same as the "
1613 "Tensor rank (number of legs).%s",
1614 "\n");
1615
1616 std::vector<cytnx_uint64> inds(indices.begin(), indices.end());
1617
1618 // find if the indices specify exists!
1619 cytnx_int64 b = -1;
1620 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
1621 if (inds == this->_inner_to_outer_idx[i]) {
1622 b = i;
1623 break;
1624 }
1625 }
1626
1627 if (b < 0) {
1628 cytnx_error_msg(true, "[ERROR][put_block][BlockUniTensor] no avaliable block exists.%s",
1629 "\n");
1630 } else {
1632 in.shape() != this->_blocks[b].shape(),
1633 "[ERROR][BlockUniTensor] the shape of input tensor does not match the shape "
1634 "of block @ idx=%d\n",
1635 b);
1636 this->_blocks[b] = in;
1637 }
1638 }
1639
1640 void tag() {
1641 // no-use!
1642 }
1643
1644 boost::intrusive_ptr<UniTensor_base> Conj() {
1645 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1646 out->Conj_();
1647 return out;
1648 }
1649
1650 void Conj_() {
1651 for (int i = 0; i < this->_blocks.size(); i++) {
1652 this->_blocks[i].Conj_();
1653 }
1654 };
1655
1656 void Transpose_();
1657 boost::intrusive_ptr<UniTensor_base> Transpose() {
1658 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1659 out->Transpose_();
1660 return out;
1661 }
1662
1663 void normalize_();
1664 boost::intrusive_ptr<UniTensor_base> normalize() {
1665 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1666 out->normalize_();
1667 return out;
1668 }
1669
1670 boost::intrusive_ptr<UniTensor_base> Dagger() {
1671 boost::intrusive_ptr<UniTensor_base> out = this->Conj();
1672 out->Transpose_();
1673 return out;
1674 }
1675 void Dagger_() {
1676 this->Conj_();
1677 this->Transpose_();
1678 }
1679
1680 void Trace_(const std::string &a, const std::string &b);
1681 void Trace_(const cytnx_int64 &a, const cytnx_int64 &b);
1682
1683 boost::intrusive_ptr<UniTensor_base> Trace(const std::string &a, const std::string &b) {
1684 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1685 out->Trace_(a, b);
1686 if (out->rank() == 0) {
1687 DenseUniTensor *tmp = new DenseUniTensor();
1688 tmp->_block = ((BlockUniTensor *)out.get())->_blocks[0];
1689 out = boost::intrusive_ptr<UniTensor_base>(tmp);
1690 }
1691 return out;
1692 }
1693 boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b) {
1694 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1695 out->Trace_(a, b);
1696 if (out->rank() == 0) {
1697 DenseUniTensor *tmp = new DenseUniTensor();
1698 tmp->_block = ((BlockUniTensor *)out.get())->_blocks[0];
1699 out = boost::intrusive_ptr<UniTensor_base>(tmp);
1700 }
1701 return out;
1702 }
1703
1704 Tensor Norm() const;
1705
1706 bool elem_exists(const std::vector<cytnx_uint64> &locator) const;
1707
1708 const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const;
1709 const cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1710 const cytnx_complex128 &aux) const;
1711 const cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1712 const cytnx_complex64 &aux) const;
1713 const cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1714 const cytnx_double &aux) const;
1715 const cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1716 const cytnx_float &aux) const;
1717 const cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1718 const cytnx_uint64 &aux) const;
1719 const cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1720 const cytnx_int64 &aux) const;
1721 const cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1722 const cytnx_uint32 &aux) const;
1723 const cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1724 const cytnx_int32 &aux) const;
1725 const cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1726 const cytnx_uint16 &aux) const;
1727 const cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1728 const cytnx_int16 &aux) const;
1729
1730 Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator);
1731 cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1732 const cytnx_complex128 &aux);
1733 cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
1734 const cytnx_complex64 &aux);
1735 cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux);
1736 cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux);
1737 cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux);
1738 cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux);
1739 cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux);
1740 cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux);
1741 cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux);
1742 cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux);
1743
1744 void _save_dispatch(std::fstream &f) const;
1745 void _load_dispatch(std::fstream &f);
1746
1747 // this will remove the [q_index]-th qnum at [bond_idx]-th Bond!
1748 void truncate_(const std::string &label, const cytnx_uint64 &q_index);
1749 void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &q_index);
1750
1751 void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1752 void Add_(const Scalar &rhs) {
1754 true,
1755 "[ERROR] Cannot perform elementwise arithmetic '+' between Scalar and BlockUniTensor.\n %s "
1756 "\n",
1757 "This operation would destroy the block structure. [Suggest] Avoid or use get/put_block(s) "
1758 "to do operation on blocks.");
1759 }
1760
1761 void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1762 void Mul_(const Scalar &rhs);
1763
1764 void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1765 void Sub_(const Scalar &rhs) {
1767 true,
1768 "[ERROR] Cannot perform elementwise arithmetic '-' between Scalar and BlockUniTensor.\n %s "
1769 "\n",
1770 "This operation would destroy the block structure. [Suggest] Avoid or use get/put_block(s) "
1771 "to do operation on blocks.");
1772 }
1773 void lSub_(const Scalar &lhs) {
1775 true,
1776 "[ERROR] Cannot perform elementwise arithmetic '-' between Scalar and BlockUniTensor.\n %s "
1777 "\n",
1778 "This operation would destroy the block structure. [Suggest] Avoid or use get/put_block(s) "
1779 "to do operation on blocks.");
1780 }
1781
1782 void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1783 void Div_(const Scalar &rhs);
1784 void lDiv_(const Scalar &lhs) {
1786 true,
1787 "[ERROR] Cannot perform elementwise arithmetic '/' between Scalar and BlockUniTensor.\n %s "
1788 "\n",
1789 "This operation would cause division by zero on non-block elements. [Suggest] Avoid or use "
1790 "get/put_block(s) to do operation on blocks.");
1791 }
1792 void from_(const boost::intrusive_ptr<UniTensor_base> &rhs, bool force, cytnx_double tol = 0.);
1793
1794 void group_basis_();
1795
1796 void combineBond(const std::vector<std::string> &indicators, const bool &force = false);
1797 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force = false);
1798 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force,
1799 const bool &by_label);
1800 void combineBonds(const std::vector<std::string> &indicators, const bool &force = false);
1801
1802 const std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) const {
1804 bidx >= this->Nblocks(),
1805 "[ERROR][BlockUniTensor] bidx out of bound! only %d blocks in current UTen.\n",
1806 this->Nblocks());
1807 return this->_inner_to_outer_idx[bidx];
1808 }
1809 std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) {
1811 bidx >= this->Nblocks(),
1812 "[ERROR][BlockUniTensor] bidx out of bound! only %d blocks in current UTen.\n",
1813 this->Nblocks());
1814 return this->_inner_to_outer_idx[bidx];
1815 }
1816
1817 const vec2d<cytnx_uint64> &get_itoi() const { return this->_inner_to_outer_idx; }
1818 vec2d<cytnx_uint64> &get_itoi() { return this->_inner_to_outer_idx; }
1819 };
1821
1822 //======================================================================
1824 class BlockFermionicUniTensor : public UniTensor_base {
1825 //[21 Aug 2024] This is a copy from BlockUniTensor; additionally sign flips are stored as
1826 //_signflip and taken care of in all the methods
1827 public:
1828 std::vector<std::vector<cytnx_uint64>>
1829 _inner_to_outer_idx; // stores the qindices for each block
1830 std::vector<Tensor> _blocks;
1831 Tensor NullRefTensor; // this returns when accessed block does not exists!
1832 // additional informaiton for fermions:
1833 std::vector<cytnx_bool>
1834 _signflip; // if true, the sign of the corresponding block needs to be flipped
1835
1836 // given an index list [loc], get qnums from this->_bonds[loc] and return the combined qnums
1837 // calculated from Symm object! this assume 1. symmetry are the same for each bond!
1838 // 2. total_qns are feeded with size len(symmetry)
1839 void _fx_get_total_fluxs(std::vector<cytnx_uint64> &loc, const std::vector<Symmetry> &syms,
1840 std::vector<cytnx_int64> &total_qns) {
1841 //[21 Aug 2024] This is a copy from BlockUniTensor;
1842 memset(&total_qns[0], 0, sizeof(cytnx_int64) * total_qns.size());
1843
1844 for (cytnx_int32 i = 0; i < syms.size(); i++) {
1845 if (this->_bonds[0].type() == BD_BRA)
1846 total_qns[i] = syms[i].reverse_rule(this->_bonds[0]._impl->_qnums[loc[0]][i]);
1847 else
1848 total_qns[i] = this->_bonds[0]._impl->_qnums[loc[0]][i];
1849
1850 for (auto j = 1; j < loc.size(); j++) {
1851 if (this->_bonds[j].type() == BD_BRA)
1852 total_qns[i] = syms[i].combine_rule(
1853 total_qns[i], syms[i].reverse_rule(this->_bonds[j]._impl->_qnums[loc[j]][i]));
1854 else {
1855 total_qns[i] =
1856 syms[i].combine_rule(total_qns[i], this->_bonds[j]._impl->_qnums[loc[j]][i]);
1857 }
1858 }
1859 }
1860 }
1861
1862 void _fx_locate_elem(cytnx_int64 &bidx, std::vector<cytnx_uint64> &loc_in_T,
1863 const std::vector<cytnx_uint64> &locator) const;
1864
1865 // internal function, grouping all duplicate qnums in all bonds
1866 void _fx_group_duplicates(const std::vector<cytnx_uint64> &dup_bond_idxs,
1867 const std::vector<std::vector<cytnx_uint64>> &idx_mappers);
1868
1869 void set_meta(BlockFermionicUniTensor *tmp, const bool &inner, const bool &outer) const {
1870 //[21 Aug 2024] This is a copy from BlockUniTensor; additionally, _signflip is set
1871 // outer meta
1872 if (outer) {
1873 tmp->_bonds = vec_clone(this->_bonds);
1874 tmp->_labels = this->_labels;
1875 tmp->_is_braket_form = this->_is_braket_form;
1876 tmp->_rowrank = this->_rowrank;
1877 tmp->_name = this->_name;
1878 // tmp->_signflip = vec_clone(this->_signflip);
1879 tmp->_signflip = this->_signflip;
1880 }
1881
1882 tmp->_is_diag = this->_is_diag;
1883
1884 // inner meta
1885 if (inner) {
1886 tmp->_inner_to_outer_idx = this->_inner_to_outer_idx;
1887 }
1888 }
1889
1890 BlockFermionicUniTensor *clone_meta(const bool &inner, const bool &outer) const {
1891 //[21 Aug 2024] This is a copy from BlockUniTensor;
1892 BlockFermionicUniTensor *tmp = new BlockFermionicUniTensor();
1893 this->set_meta(tmp, inner, outer);
1894 return tmp;
1895 };
1896
1897 friend class UniTensor;
1898 BlockFermionicUniTensor() {
1899 //[21 Aug 2024] This is a copy from BlockUniTensor;
1900 this->uten_type_id = UTenType.BlockFermionic;
1901 this->_is_tag = true;
1902 }
1903
1904 void Init(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
1905 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
1906 const int &device = Device.cpu, const bool &is_diag = false,
1907 const bool &no_alloc = false, const std::string &name = "");
1908
1909 void Init_by_Tensor(const Tensor &in_tensor, const bool &is_diag = false,
1910 const cytnx_int64 &rowrank = -1, const std::string &name = "") {
1911 cytnx_error_msg(true,
1912 "[ERROR][BlockFermionicUniTensor] Cannot use Init_by_tensor() on a "
1913 "BlockFermionicUniTensor.%s",
1914 "\n");
1915 }
1916
1917 std::vector<cytnx_uint64> shape() const {
1918 //[21 Aug 2024] This is a copy from BlockUniTensor;
1919 std::vector<cytnx_uint64> out(this->_bonds.size());
1920 for (cytnx_uint64 i = 0; i < out.size(); i++) {
1921 out[i] = this->_bonds[i].dim();
1922 }
1923 return out;
1924 }
1925
1926 bool is_blockform() const {
1927 //[21 Aug 2024] This is a copy from BlockUniTensor;
1928 return true;
1929 }
1930
1931 bool is_contiguous() const {
1932 //[21 Aug 2024] This is a copy from BlockUniTensor;
1933 bool out = true;
1934 for (int i = 0; i < this->_blocks.size(); i++) {
1935 out &= this->_blocks[i].is_contiguous();
1936 }
1937 return out;
1938 };
1939
1940 cytnx_uint64 Nblocks() const {
1941 //[21 Aug 2024] This is a copy from BlockUniTensor;
1942 return this->_blocks.size();
1943 };
1944
1945 std::vector<bool> signflip() const override { return this->_signflip; };
1946 std::vector<bool> &signflip_() override { return this->_signflip; };
1947
1948 void to_(const int &device) {
1949 //[21 Aug 2024] This is a copy from BlockUniTensor;
1950 for (cytnx_uint64 i = 0; i < this->_blocks.size(); i++) {
1951 this->_blocks[i].to_(device);
1952 }
1953 };
1954
1955 boost::intrusive_ptr<UniTensor_base> to(const int &device) {
1956 //[21 Aug 2024] This is a copy from BlockUniTensor;
1957 if (this->device() == device) {
1958 return this;
1959 } else {
1960 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1961 out->to_(device);
1962 return out;
1963 }
1964 };
1965
1966 boost::intrusive_ptr<UniTensor_base> clone() const {
1967 //[21 Aug 2024] This is a copy from BlockUniTensor; changed to BlockFermionicUniTensor as
1968 // output
1969 BlockFermionicUniTensor *tmp = this->clone_meta(true, true);
1970 tmp->_blocks = vec_clone(this->_blocks);
1971 boost::intrusive_ptr<UniTensor_base> out(tmp);
1972 return out;
1973 };
1974
1975 unsigned int dtype() const {
1976 //[21 Aug 2024] This is a copy from BlockUniTensor;
1977 #ifdef UNI_DEBUG
1978 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
1979 "\n");
1980 #endif
1981 return this->_blocks.size() < 1 ? Type.Void : this->_blocks[0].dtype();
1982 };
1983 int device() const {
1984 //[21 Aug 2024] This is a copy from BlockUniTensor;
1985 #ifdef UNI_DEBUG
1986 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
1987 "\n");
1988 #endif
1989 return this->_blocks.size() < 1 ? -404 : this->_blocks[0].device();
1990 };
1991 std::string dtype_str() const {
1992 //[21 Aug 2024] This is a copy from BlockUniTensor;
1993 #ifdef UNI_DEBUG
1994 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
1995 "\n");
1996 #endif
1997 return this->_blocks.size() < 1 ? "Void, no valid blocks" : this->_blocks[0].dtype_str();
1998 };
1999 std::string device_str() const {
2000 //[21 Aug 2024] This is a copy from BlockUniTensor;
2001 #ifdef UNI_DEBUG
2002 cytnx_error_msg(this->_blocks.size() == 0, "[ERROR][internal] empty blocks for blockform.%s",
2003 "\n");
2004 #endif
2005 return this->_blocks.size() < 1 ? "None, no valid blocks" : this->_blocks[0].device_str();
2006 };
2007
2008 Tensor get_block(const cytnx_uint64 &idx = 0) const {
2009 //[21 Aug 2024] This is a copy from BlockUniTensor;
2010 cytnx_error_msg(idx >= this->_blocks.size(),
2011 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2012 return this->_blocks[idx].clone();
2013 };
2014
2015 // this one for Block will return the indicies!!
2016 Tensor get_block(const std::vector<cytnx_int64> &indices, const bool &force_return) const {
2017 //[21 Aug 2024] This is a copy from BlockUniTensor;
2019 indices.size() != this->rank(),
2020 "[ERROR][get_block][BlockFermionicUniTensor] len(indices) must be the same as the "
2021 "Tensor rank (number of legs).%s",
2022 "\n");
2023
2024 std::vector<cytnx_uint64> inds(indices.begin(), indices.end());
2025
2026 // find if the indices specify exists!
2027 cytnx_int64 b = -1;
2028 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
2029 if (inds == this->_inner_to_outer_idx[i]) {
2030 b = i;
2031 break;
2032 }
2033 }
2034
2035 if (b < 0) {
2036 if (force_return) {
2037 return NullRefTensor;
2038 } else {
2039 cytnx_error_msg(true,
2040 "[ERROR][get_block][BlockFermionicUniTensor] no avaliable block exists, "
2041 "force_return=false, so "
2042 "error throws. \n If you want to return an empty block without "
2043 "error when block is "
2044 "not avaliable, set force_return=True.%s",
2045 "\n");
2046 }
2047 } else {
2048 return this->_blocks[b].clone();
2049 }
2050 }
2051
2052 const Tensor &get_block_(const cytnx_uint64 &idx = 0) const {
2053 //[21 Aug 2024] This is a copy from BlockUniTensor;
2054 cytnx_error_msg(idx >= this->_blocks.size(),
2055 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2056 return this->_blocks[idx];
2057 };
2058
2059 Tensor &get_block_(const cytnx_uint64 &idx = 0) {
2060 //[21 Aug 2024] This is a copy from BlockUniTensor;
2061 cytnx_error_msg(idx >= this->_blocks.size(),
2062 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2063 return this->_blocks[idx];
2064 };
2065
2066 const Tensor &get_block_(const std::vector<cytnx_int64> &indices,
2067 const bool &force_return) const {
2068 //[21 Aug 2024] This is a copy from BlockUniTensor;
2070 indices.size() != this->rank(),
2071 "[ERROR][get_block][BlockFermionicUniTensor] len(indices) must be the same as the "
2072 "Tensor rank (number of legs).%s",
2073 "\n");
2074
2075 std::vector<cytnx_uint64> inds(indices.begin(), indices.end());
2076
2077 // find if the indices specify exists!
2078 cytnx_int64 b = -1;
2079 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
2080 if (inds == this->_inner_to_outer_idx[i]) {
2081 b = i;
2082 break;
2083 }
2084 }
2085
2086 if (b < 0) {
2087 if (force_return) {
2088 return this->NullRefTensor;
2089 } else {
2090 cytnx_error_msg(true,
2091 "[ERROR][get_block][BlockFermionicUniTensor] no avaliable block exists, "
2092 "force_return=false, so "
2093 "error throws. \n If you want to return an empty block without "
2094 "error when block is "
2095 "not avaliable, set force_return=True.%s",
2096 "\n");
2097 }
2098 } else {
2099 return this->_blocks[b];
2100 }
2101 }
2102
2103 Tensor &get_block_(const std::vector<cytnx_int64> &indices, const bool &force_return) {
2104 //[21 Aug 2024] This is a copy from BlockUniTensor;
2106 indices.size() != this->rank(),
2107 "[ERROR][get_block][BlockFermionicUniTensor] len(indices) must be the same as the "
2108 "Tensor rank (number of legs).%s",
2109 "\n");
2110
2111 std::vector<cytnx_uint64> inds(indices.begin(), indices.end());
2112
2113 // find if the indices specify exists!
2114 cytnx_int64 b = -1;
2115 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
2116 if (inds == this->_inner_to_outer_idx[i]) {
2117 b = i;
2118 break;
2119 }
2120 }
2121
2122 if (b < 0) {
2123 if (force_return) {
2124 return this->NullRefTensor;
2125 } else {
2126 cytnx_error_msg(true,
2127 "[ERROR][get_block][BlockFermionicUniTensor] no avaliable block exists, "
2128 "force_return=false, so "
2129 "error throws. \n If you want to return an empty block without "
2130 "error when block is "
2131 "not avaliable, set force_return=True.%s",
2132 "\n");
2133 }
2134 } else {
2135 return this->_blocks[b];
2136 }
2137 }
2138
2139 std::vector<Tensor> get_blocks() const {
2140 //[21 Aug 2024] This is a copy from BlockUniTensor;
2141 return vec_clone(this->_blocks);
2142 }
2143 const std::vector<Tensor> &get_blocks_(const bool &) const {
2144 //[21 Aug 2024] This is a copy from BlockUniTensor;
2145 return this->_blocks;
2146 }
2147 std::vector<Tensor> &get_blocks_(const bool &) {
2148 //[21 Aug 2024] This is a copy from BlockUniTensor;
2149 return this->_blocks;
2150 }
2151
2152 bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const {
2153 //[21 Aug 2024] This is a copy from BlockUniTensor; changed to BlockFermionic UTenType
2154 if (rhs->uten_type() != UTenType.BlockFermionic) return false;
2155 if (rhs->get_blocks_(1).size() != this->get_blocks_(1).size()) return false;
2156
2157 for (int i = 0; i < rhs->get_blocks_(1).size(); i++)
2158 if (this->get_blocks_(1)[i].same_data(rhs->get_blocks_(1)[i]) == false) return false;
2159
2160 return true;
2161 }
2162
2163 void set_rowrank_(const cytnx_uint64 &new_rowrank) {
2164 //[21 Aug 2024] This is a copy from BlockUniTensor;
2166 new_rowrank > this->rank(),
2167 "[ERROR][BlockFermionicUniTensor] rowrank should be [>=0] and [<=UniTensor.rank].%s", "\n");
2168 if (this->is_diag()) {
2170 new_rowrank != 1,
2171 "[ERROR][BlockFermionicUniTensor] rowrank should be [==1] when is_diag =true!.%s", "\n");
2172 }
2173 this->_rowrank = new_rowrank;
2174 this->_is_braket_form = this->_update_braket();
2175 }
2176
2177 boost::intrusive_ptr<UniTensor_base> set_rowrank(const cytnx_uint64 &new_rowrank) const {
2178 //[21 Aug 2024] This is a copy from BlockUniTensor; output type changed to
2179 // BlockFermionicUniTensor
2180 BlockFermionicUniTensor *tmp = this->clone_meta(true, true);
2181 tmp->_blocks = this->_blocks;
2182 tmp->set_rowrank_(new_rowrank);
2183 boost::intrusive_ptr<UniTensor_base> out(tmp);
2184 return out;
2185 }
2186
2187 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,
2188 const cytnx_int64 &rowrank = -1);
2189 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<std::string> &mapper,
2190 const cytnx_int64 &rowrank = -1);
2191
2192 void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1) override;
2193 void permute_(const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1) override;
2194
2195 boost::intrusive_ptr<UniTensor_base> permute_nosignflip(
2196 const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1) override;
2197 boost::intrusive_ptr<UniTensor_base> permute_nosignflip(
2198 const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1) override;
2199 void permute_nosignflip_(const std::vector<cytnx_int64> &mapper,
2200 const cytnx_int64 &rowrank = -1) override;
2201 void permute_nosignflip_(const std::vector<std::string> &mapper,
2202 const cytnx_int64 &rowrank = -1) override;
2203
2204 void twist_(const cytnx_int64 &idx) override;
2205 void twist_(const std::string &label) override;
2206 void fermion_twists_() override;
2207
2208 // Helper function; implements the sign flips when permuting indices
2209 std::vector<bool> _swapsigns_(const std::vector<cytnx_int64> &mapper) const;
2210 std::vector<bool> _lhssigns_(const std::vector<cytnx_int64> &mapper,
2211 const cytnx_int64 contrno) const;
2212 std::vector<bool> _swapsigns_(const std::vector<cytnx_uint64> &mapper) const;
2213 std::vector<bool> _lhssigns_(const std::vector<cytnx_uint64> &mapper,
2214 const cytnx_uint64 contrno) const;
2215
2216 boost::intrusive_ptr<UniTensor_base> contiguous_() {
2217 //[21 Aug 2024] This is a copy from BlockUniTensor;
2218 for (unsigned int b = 0; b < this->_blocks.size(); b++) this->_blocks[b].contiguous_();
2219 return boost::intrusive_ptr<UniTensor_base>(this);
2220 }
2221 boost::intrusive_ptr<UniTensor_base> contiguous();
2222
2223 boost::intrusive_ptr<UniTensor_base> apply_();
2224 boost::intrusive_ptr<UniTensor_base> apply();
2225
2226 void print_diagram(const bool &bond_info = false) const;
2227 void print_blocks(const bool &full_info = true) const;
2228 void print_block(const cytnx_int64 &idx, const bool &full_info = true) const;
2229
2230 boost::intrusive_ptr<UniTensor_base> contract(const boost::intrusive_ptr<UniTensor_base> &rhs,
2231 const bool &mv_elem_self = false,
2232 const bool &mv_elem_rhs = false);
2233
2234 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &new_labels);
2235 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &new_labels);
2236
2237 boost::intrusive_ptr<UniTensor_base> relabel(const std::vector<std::string> &old_labels,
2238 const std::vector<std::string> &new_labels);
2239 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<std::string> &old_labels,
2240 const std::vector<std::string> &new_labels);
2241
2242 boost::intrusive_ptr<UniTensor_base> relabel(const std::string &old_label,
2243 const std::string &new_label);
2244 boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx,
2245 const std::string &new_label);
2246 std::vector<Symmetry> syms() const;
2247
2248 void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank = 0) {
2249 cytnx_error_msg(true, "[ERROR] Cannot reshape a UniTensor with symmetry.%s", "\n");
2250 }
2251 boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape,
2252 const cytnx_uint64 &rowrank = 0) {
2253 cytnx_error_msg(true, "[ERROR] Cannot reshape a UniTensor with symmetry.%s", "\n");
2254 return nullptr;
2255 }
2256
2257 boost::intrusive_ptr<UniTensor_base> to_dense();
2258 void to_dense_();
2259
2260 boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const {
2261 //[21 Aug 2024] This is a copy from BlockUniTensor; the tensor type was adapted
2262 BlockFermionicUniTensor *tmp = this->clone_meta(true, true);
2263 tmp->_blocks.resize(this->_blocks.size());
2264 for (cytnx_int64 blk = 0; blk < this->_blocks.size(); blk++) {
2265 tmp->_blocks[blk] = this->_blocks[blk].astype(dtype);
2266 }
2267 boost::intrusive_ptr<UniTensor_base> out(tmp);
2268 return out;
2269 };
2270
2271 // this will only work on non-symm tensor (DenseUniTensor)
2272 boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors) {
2274 true,
2275 "[ERROR][BlockFermionicUniTensor][get] Cannot use get on a UniTensor with "
2276 "Symmetry.\n suggestion: try get_block/get_block_/get_blocks/get_blocks_ first.%s",
2277 "\n");
2278 return nullptr;
2279 }
2280
2281 // this will only work on non-symm tensor (DenseUniTensor)
2282 void set(const std::vector<Accessor> &accessors, const Tensor &rhs) {
2283 //[21 Aug 2024] This is a copy from BlockUniTensor;
2285 true,
2286 "[ERROR][BlockFermionicUniTensor][get] Cannot use get on a UniTensor with "
2287 "Symmetry.\n suggestion: try get_block/get_block_/get_blocks/get_blocks_ first.%s",
2288 "\n");
2289 }
2290
2291 void put_block(const Tensor &in, const cytnx_uint64 &idx = 0) {
2292 //[21 Aug 2024] This is a copy from BlockUniTensor;
2294 in.dtype() != this->dtype(),
2295 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor dtype does not match.%s",
2296 "\n");
2298 in.device() != this->device(),
2299 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor device does not "
2300 "match.%s",
2301 "\n");
2302 // We shouldn't check the contiguous
2303 // cytnx_error_msg(!in.contiguous());
2304 cytnx_error_msg(idx >= this->_blocks.size(),
2305 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2307 in.shape() != this->_blocks[idx].shape(),
2308 "[ERROR][BlockFermionicUniTensor] the shape of input tensor does not match the shape "
2309 "of block @ idx=%d\n",
2310 idx);
2311
2312 this->_blocks[idx] = in.clone();
2313 }
2314 void put_block_(Tensor &in, const cytnx_uint64 &idx = 0) {
2315 //[21 Aug 2024] This is a copy from BlockUniTensor;
2317 in.dtype() != this->dtype(),
2318 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor dtype does not match.%s",
2319 "\n");
2321 in.device() != this->device(),
2322 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor device does not "
2323 "match.%s",
2324 "\n");
2325 // We shouldn't check the contiguous
2326 // cytnx_error_msg(!in.contiguous());
2327 cytnx_error_msg(idx >= this->_blocks.size(),
2328 "[ERROR][BlockFermionicUniTensor] index out of range%s", "\n");
2330 in.shape() != this->_blocks[idx].shape(),
2331 "[ERROR][BlockFermionicUniTensor] the shape of input tensor does not match the shape "
2332 "of block @ idx=%d\n",
2333 idx);
2334
2335 this->_blocks[idx] = in;
2336 }
2337 void put_block(const Tensor &in, const std::vector<cytnx_int64> &indices) {
2338 //[21 Aug 2024] This is a copy from BlockUniTensor;
2340 in.dtype() != this->dtype(),
2341 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor dtype does not match.%s",
2342 "\n");
2344 in.device() != this->device(),
2345 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor device does not "
2346 "match.%s",
2347 "\n");
2348 // We shouldn't check the contiguous
2349 // cytnx_error_msg(!in.contiguous());
2351 indices.size() != this->rank(),
2352 "[ERROR][put_block][BlockFermionicUniTensor] len(indices) must be the same as the "
2353 "Tensor rank (number of legs).%s",
2354 "\n");
2355
2356 std::vector<cytnx_uint64> inds(indices.begin(), indices.end());
2357
2358 // find if the indices specify exists!
2359 cytnx_int64 b = -1;
2360 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
2361 if (inds == this->_inner_to_outer_idx[i]) {
2362 b = i;
2363 break;
2364 }
2365 }
2366
2367 if (b < 0) {
2369 true, "[ERROR][put_block][BlockFermionicUniTensor] no avaliable block exists.%s", "\n");
2370 } else {
2372 in.shape() != this->_blocks[b].shape(),
2373 "[ERROR][BlockFermionicUniTensor] the shape of input tensor does not match the shape "
2374 "of block @ idx=%d\n",
2375 b);
2376
2377 this->_blocks[b] = in.clone();
2378 }
2379 }
2380 void put_block_(Tensor &in, const std::vector<cytnx_int64> &indices) {
2381 //[21 Aug 2024] This is a copy from BlockUniTensor;
2383 in.dtype() != this->dtype(),
2384 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor dtype does not match.%s",
2385 "\n");
2387 in.device() != this->device(),
2388 "[ERROR][BlockFermionicUniTensor][put_block] The input tensor device does not "
2389 "match.%s",
2390 "\n");
2391 // We shouldn't check the contiguous
2392 // cytnx_error_msg(!in.contiguous());
2394 indices.size() != this->rank(),
2395 "[ERROR][put_block][BlockFermionicUniTensor] len(indices) must be the same as the "
2396 "Tensor rank (number of legs).%s",
2397 "\n");
2398
2399 std::vector<cytnx_uint64> inds(indices.begin(), indices.end());
2400
2401 // find if the indices specify exists!
2402 cytnx_int64 b = -1;
2403 for (cytnx_uint64 i = 0; i < this->_inner_to_outer_idx.size(); i++) {
2404 if (inds == this->_inner_to_outer_idx[i]) {
2405 b = i;
2406 break;
2407 }
2408 }
2409
2410 if (b < 0) {
2412 true, "[ERROR][put_block][BlockFermionicUniTensor] no avaliable block exists.%s", "\n");
2413 } else {
2415 in.shape() != this->_blocks[b].shape(),
2416 "[ERROR][BlockFermionicUniTensor] the shape of input tensor does not match the shape "
2417 "of block @ idx=%d\n",
2418 b);
2419 this->_blocks[b] = in;
2420 }
2421 }
2422
2423 void tag() {
2424 // no-use!
2425 }
2426
2427 boost::intrusive_ptr<UniTensor_base> Conj() {
2428 //[21 Aug 2024] This is a copy from BlockUniTensor;
2429 boost::intrusive_ptr<UniTensor_base> out = this->clone();
2430 out->Conj_();
2431 return out;
2432 }
2433
2434 void Conj_() {
2435 //[21 Aug 2024] This is a copy from BlockUniTensor;
2436 for (int i = 0; i < this->_blocks.size(); i++) {
2437 this->_blocks[i].Conj_();
2438 }
2439 };
2440
2441 // Transpose(_) changes the index order without sign flips and reverses the bond directions for
2442 // fermionic tensors
2443 void Transpose_();
2444 boost::intrusive_ptr<UniTensor_base> Transpose() {
2445 //[21 Aug 2024] This is a copy from BlockUniTensor;
2446 boost::intrusive_ptr<UniTensor_base> out = this->clone();
2447 out->Transpose_();
2448 return out;
2449 }
2450
2451 void normalize_();
2452 boost::intrusive_ptr<UniTensor_base> normalize() {
2453 //[21 Aug 2024] This is a copy from BlockUniTensor;
2454 boost::intrusive_ptr<UniTensor_base> out = this->clone();
2455 out->normalize_();
2456 return out;
2457 }
2458
2459 boost::intrusive_ptr<UniTensor_base> Dagger() {
2460 //[21 Aug 2024] This is a copy from BlockUniTensor;
2461 boost::intrusive_ptr<UniTensor_base> out = this->Conj();
2462 out->Transpose_();
2463 return out;
2464 }
2465 void Dagger_() {
2466 //[21 Aug 2024] This is a copy from BlockUniTensor;
2467 this->Conj_();
2468 this->Transpose_();
2469 }
2470
2471 void Trace_(const std::string &a, const std::string &b);
2472 void Trace_(const cytnx_int64 &a, const cytnx_int64 &b);
2473
2474 boost::intrusive_ptr<UniTensor_base> Trace(const std::string &a, const std::string &b) {
2475 //[21 Aug 2024] This is a copy from BlockUniTensor; the tensor type was adapted
2476 boost::intrusive_ptr<UniTensor_base> out = this->clone();
2477 out->Trace_(a, b);
2478 if (out->rank() == 0) {
2479 DenseUniTensor *tmp = new DenseUniTensor();
2480 tmp->_block = ((BlockFermionicUniTensor *)out.get())->_blocks[0];
2481 out = boost::intrusive_ptr<UniTensor_base>(tmp);
2482 }
2483 return out;
2484 }
2485 boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b) {
2486 //[21 Aug 2024] This is a copy from BlockUniTensor; the tensor type was adapted
2487 boost::intrusive_ptr<UniTensor_base> out = this->clone();
2488 out->Trace_(a, b);
2489 if (out->rank() == 0) {
2490 DenseUniTensor *tmp = new DenseUniTensor();
2491 tmp->_block = ((BlockFermionicUniTensor *)out.get())->_blocks[0];
2492 out = boost::intrusive_ptr<UniTensor_base>(tmp);
2493 }
2494 return out;
2495 }
2496
2497 Tensor Norm() const;
2498
2499 bool elem_exists(const std::vector<cytnx_uint64> &locator) const;
2500
2501 const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const;
2502 const cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2503 const cytnx_complex128 &aux) const;
2504 const cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2505 const cytnx_complex64 &aux) const;
2506 const cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2507 const cytnx_double &aux) const;
2508 const cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2509 const cytnx_float &aux) const;
2510 const cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2511 const cytnx_uint64 &aux) const;
2512 const cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2513 const cytnx_int64 &aux) const;
2514 const cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2515 const cytnx_uint32 &aux) const;
2516 const cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2517 const cytnx_int32 &aux) const;
2518 const cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2519 const cytnx_uint16 &aux) const;
2520 const cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2521 const cytnx_int16 &aux) const;
2522
2523 Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator);
2524 cytnx_complex128 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2525 const cytnx_complex128 &aux);
2526 cytnx_complex64 &at_for_sparse(const std::vector<cytnx_uint64> &locator,
2527 const cytnx_complex64 &aux);
2528 cytnx_double &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux);
2529 cytnx_float &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux);
2530 cytnx_uint64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux);
2531 cytnx_int64 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux);
2532 cytnx_uint32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux);
2533 cytnx_int32 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux);
2534 cytnx_uint16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux);
2535 cytnx_int16 &at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux);
2536
2537 void _save_dispatch(std::fstream &f) const;
2538 void _load_dispatch(std::fstream &f);
2539
2540 // this will remove the [q_index]-th qnum at [bond_idx]-th Bond!
2541 void truncate_(const std::string &label, const cytnx_uint64 &q_index);
2542 void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &q_index);
2543
2544 void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
2545 void Add_(const Scalar &rhs) {
2546 cytnx_error_msg(true,
2547 "[ERROR] Cannot perform elementwise arithmetic '+' between Scalar and "
2548 "BlockFermionicUniTensor.\n %s "
2549 "\n",
2550 "This operation would destroy the block structure. [Suggest] Avoid or use "
2551 "get/put_block(s) to do operation on blocks.");
2552 }
2553
2554 void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
2555 void Mul_(const Scalar &rhs);
2556
2557 void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
2558 void Sub_(const Scalar &rhs) {
2559 cytnx_error_msg(true,
2560 "[ERROR] Cannot perform elementwise arithmetic '-' between Scalar and "
2561 "BlockFermionicUniTensor.\n %s "
2562 "\n",
2563 "This operation would destroy the block structure. [Suggest] Avoid or use "
2564 "get/put_block(s) to do operation on blocks.");
2565 }
2566 void lSub_(const Scalar &lhs) {
2567 cytnx_error_msg(true,
2568 "[ERROR] Cannot perform elementwise arithmetic '-' between Scalar and "
2569 "BlockFermionicUniTensor.\n %s "
2570 "\n",
2571 "This operation would destroy the block structure. [Suggest] Avoid or use "
2572 "get/put_block(s) to do operation on blocks.");
2573 }
2574
2575 void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
2576 void Div_(const Scalar &rhs);
2577 void lDiv_(const Scalar &lhs) {
2578 cytnx_error_msg(true,
2579 "[ERROR] Cannot perform elementwise arithmetic '/' between Scalar and "
2580 "BlockFermionicUniTensor.\n %s "
2581 "\n",
2582 "This operation would cause division by zero on non-block elements. "
2583 "[Suggest] Avoid or use get/put_block(s) to do operation on blocks.");
2584 }
2585 void from_(const boost::intrusive_ptr<UniTensor_base> &rhs, bool force, cytnx_double tol = 0.);
2586
2587 void group_basis_();
2588
2589 void combineBond(const std::vector<std::string> &indicators, const bool &force = false);
2590 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force = false);
2591 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force,
2592 const bool &by_label);
2593 void combineBonds(const std::vector<std::string> &indicators, const bool &force = false);
2594
2595 const std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) const {
2596 //[21 Aug 2024] This is a copy from BlockUniTensor;
2598 bidx >= this->Nblocks(),
2599 "[ERROR][BlockFermionicUniTensor] bidx out of bound! only %d blocks in current UTen.\n",
2600 this->Nblocks());
2601 return this->_inner_to_outer_idx[bidx];
2602 }
2603 std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) {
2604 //[21 Aug 2024] This is a copy from BlockUniTensor;
2606 bidx >= this->Nblocks(),
2607 "[ERROR][BlockFermionicUniTensor] bidx out of bound! only %d blocks in current UTen.\n",
2608 this->Nblocks());
2609 return this->_inner_to_outer_idx[bidx];
2610 }
2611
2612 const vec2d<cytnx_uint64> &get_itoi() const {
2613 //[21 Aug 2024] This is a copy from BlockUniTensor;
2614 return this->_inner_to_outer_idx;
2615 }
2616 vec2d<cytnx_uint64> &get_itoi() {
2617 //[21 Aug 2024] This is a copy from BlockUniTensor;
2618 return this->_inner_to_outer_idx;
2619 }
2620
2621 void beauty_print_block(std::ostream &os, const cytnx_uint64 &Nin, const cytnx_uint64 &Nout,
2622 const std::vector<cytnx_uint64> &qn_indices,
2623 const std::vector<Bond> &bonds, const Tensor &block) const;
2624 };
2626
2627 //======================================================================
2628
2630 class UniTensor_options {
2631 public:
2632 bool _is_diag;
2633 int _dtype;
2634 int _device;
2635 int _rowrank;
2636
2637 UniTensor_options() {
2638 this->_is_diag = false;
2639 this->_dtype = Type.Double;
2640 this->_device = Device.cpu;
2641 this->_rowrank = -1;
2642 }
2643
2644 UniTensor_options(const UniTensor_options &rhs) {
2645 this->_is_diag = rhs._is_diag;
2646 this->_dtype = rhs._dtype;
2647 this->_device = rhs._device;
2648 this->_rowrank = rhs._rowrank;
2649 }
2650
2651 UniTensor_options &operator=(const UniTensor_options &rhs) {
2652 this->_is_diag = rhs._is_diag;
2653 this->_dtype = rhs._dtype;
2654 this->_device = rhs._device;
2655 this->_rowrank = rhs._rowrank;
2656 return *this;
2657 }
2658
2659 UniTensor_options &is_diag(const bool &in) {
2660 this->_is_diag = in;
2661 return *this;
2662 }
2663 UniTensor_options &dtype(const int &in) {
2664 this->_dtype = in;
2665 return *this;
2666 }
2667 UniTensor_options &device(const int &in) {
2668 this->_device = in;
2669 return *this;
2670 }
2671 UniTensor_options &rowrank(const int &in) {
2672 this->_rowrank = in;
2673 return *this;
2674 }
2675 };
2677
2680 public:
2682 boost::intrusive_ptr<UniTensor_base> _impl;
2683 UniTensor() : _impl(new UniTensor_base()){};
2684 UniTensor(const UniTensor &rhs) { this->_impl = rhs._impl; }
2685 UniTensor &operator=(const UniTensor &rhs) {
2686 this->_impl = rhs._impl;
2687 return *this;
2688 }
2690
2692
2718 explicit UniTensor(const Tensor &in_tensor, const bool &is_diag = false,
2719 const cytnx_int64 &rowrank = -1,
2720 const std::vector<std::string> &in_labels = {}, const std::string &name = "")
2721 : _impl(new UniTensor_base()) {
2722 this->Init(in_tensor, is_diag, rowrank, in_labels, name);
2723 }
2741 void Init(const Tensor &in_tensor, const bool &is_diag = false, const cytnx_int64 &rowrank = -1,
2742 const std::vector<std::string> &in_labels = {}, const std::string &name = "") {
2743 boost::intrusive_ptr<UniTensor_base> out(new DenseUniTensor());
2744 out->Init_by_Tensor(in_tensor, is_diag, rowrank, name);
2745 this->_impl = out;
2746 if (in_labels.size() != 0) this->set_labels(in_labels);
2747 }
2749
2751
2768 UniTensor(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
2769 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
2770 const int &device = Device.cpu, const bool &is_diag = false,
2771 const std::string &name = "")
2772 : _impl(new UniTensor_base()) {
2773 #ifdef UNI_DEBUG
2775 true,
2776 "[DEBUG] message: entry for UniTensor(const std::vector<Bond> &bonds, const "
2777 "std::vector<std::string> &in_labels={}, const cytnx_int64 &rowrank=-1, const unsigned "
2778 "int "
2779 "&dtype=Type.Double, const int &device = Device.cpu, const bool &is_diag=false)%s",
2780 "\n");
2781 #endif
2782 this->Init(bonds, in_labels, rowrank, dtype, device, is_diag, name);
2783 }
2784
2786 /* [developing]
2787 void Init(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
2788 const UniTensor_options &UToptions = UniTensor_options(), const std::string &name =
2789 ""){ this->Init(bonds,in_labels, UToptions._rowrank, UToptions._dtype , UToptions._device ,
2790 UToptions._is_diag,
2791 name);
2792 }
2793 */
2795
2815 UniTensor &Init(const std::vector<Bond> &bonds, const std::vector<std::string> &in_labels = {},
2816 const cytnx_int64 &rowrank = -1, const unsigned int &dtype = Type.Double,
2817 const int &device = Device.cpu, const bool &is_diag = false,
2818 const std::string &name = "") {
2819 // checking type:
2820 bool is_sym = false;
2821 int sym_fver = -1;
2822 bool fermionic = false;
2823
2824 for (cytnx_uint64 i = 0; i < bonds.size(); i++) {
2825 // check
2826 if (bonds[i].syms().size() != 0) {
2827 is_sym = true;
2828 if (sym_fver == -1)
2829 sym_fver = bonds[i]._impl->_degs.size();
2830 else {
2831 cytnx_error_msg((bool(sym_fver) ^ bool(bonds[i]._impl->_degs.size())),
2832 "[ERROR] When initializing a UniTensor with symmetries, all Bonds must "
2833 "be in the same format!%s",
2834 "\n");
2835 }
2836 if (!fermionic) {
2837 std::vector<Symmetry> symms = bonds[i].syms();
2838 for (cytnx_uint64 i = 0; i < symms.size(); i++) {
2839 if (symms[i].is_fermionic()) fermionic = true;
2840 }
2841 }
2842 } else
2844 is_sym, "[ERROR] Cannot have bonds with mixing of symmetry and non-symmetry.%s", "\n");
2845 }
2846
2847 // dynamical dispatch:
2848 if (is_sym) {
2849 #ifdef UNI_DEBUG
2850 cytnx_warning_msg(true, "[DEBUG] message: entry dispatch: UniTensor: symmetric%s", "\n");
2851 #endif
2852 // cytnx_warning_msg(true,"[warning, still developing, some functions will display
2853 // \"[Developing]\"][SparseUniTensor]%s","\n");
2854 if (sym_fver == 0) {
2855 // boost::intrusive_ptr<UniTensor_base> out(new SparseUniTensor());
2856 // this->_impl = out;
2857 cytnx_error_msg(true,
2858 "[ERROR] internal error! [legacy Sparse entry] the Bond is symmetry but "
2859 "the version is not properly determined!%s",
2860 "\n")
2861 } else if (sym_fver == -1) {
2862 cytnx_error_msg(true,
2863 "[ERROR] internal error! the Bond is symmetry but the version is not "
2864 "properly determined!%s",
2865 "\n");
2866 } else {
2867 if (fermionic) {
2868 boost::intrusive_ptr<UniTensor_base> out(new BlockFermionicUniTensor());
2869 this->_impl = out;
2870 } else {
2871 boost::intrusive_ptr<UniTensor_base> out(new BlockUniTensor());
2872 this->_impl = out;
2873 }
2874 }
2875 } else {
2876 boost::intrusive_ptr<UniTensor_base> out(new DenseUniTensor());
2877 this->_impl = out;
2878 }
2879 this->_impl->Init(bonds, in_labels, rowrank, dtype, device, is_diag, false, name);
2880 return *this;
2881 }
2882
2889 UniTensor &set_name(const std::string &in) {
2890 this->_impl->set_name(in);
2891 return *this;
2892 }
2893
2904 UniTensor &set_label(const cytnx_int64 &idx, const std::string &new_label) {
2905 this->_impl->set_label(idx, new_label);
2906 return *this;
2907 }
2908
2913 this->_impl->set_label(idx, std::string(new_label));
2914 return *this;
2915 }
2916
2927 UniTensor &set_label(const std::string &old_label, const std::string &new_label) {
2928 this->_impl->set_label(old_label, new_label);
2929 return *this;
2930 }
2931
2935 UniTensor &set_label(const char *old_label, const std::string &new_label) {
2936 this->_impl->set_label(std::string(old_label), new_label);
2937 return *this;
2938 }
2939
2943 UniTensor &set_label(const std::string &old_label, const char *new_label) {
2944 this->_impl->set_label(old_label, std::string(new_label));
2945 return *this;
2946 }
2947
2951 UniTensor &set_label(const char *old_label, const char *new_label) {
2952 this->_impl->set_label(std::string(old_label), std::string(new_label));
2953 return *this;
2954 }
2955
2956 /*
2957 UniTensor &change_label(const cytnx_int64 &old_label, const cytnx_int64 &new_label){
2958 this->_impl->change_label(old_label,new_label);
2959 return *this;
2960 }
2961 */
2962
2968 [[deprecated(
2969 "Please use "
2970 "UniTensor &relabel_(const std::vector<std::string> &new_labels) "
2971 "instead.")]] UniTensor &
2972 set_labels(const std::vector<std::string> &new_labels) {
2973 this->_impl->set_labels(new_labels);
2974 return *this;
2975 }
2976
2982 [[deprecated(
2983 "Please use "
2984 "UniTensor &relabel_(const std::initializer_list<char *> &new_labels) "
2985 "instead.")]] UniTensor &
2986 set_labels(const std::initializer_list<char *> &new_labels) {
2987 std::vector<char *> new_lbls(new_labels);
2988 std::vector<std::string> vs(new_lbls.size());
2989 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
2990 [](char *x) -> std::string { return std::string(x); });
2991
2992 this->_impl->set_labels(vs);
2993 return *this;
2994 }
2995
3003 this->_impl->set_rowrank_(new_rowrank);
3004 return *this;
3005 }
3006
3008 UniTensor out;
3009 out._impl = this->_impl->set_rowrank(new_rowrank);
3010 return out;
3011 }
3012
3013 template <class T>
3014 T &item() {
3016 "[ERROR] Cannot use item on UniTensor with Symmetry.\n suggestion: use "
3017 "get_block()/get_blocks() first.%s",
3018 "\n");
3019
3020 DenseUniTensor *tmp = static_cast<DenseUniTensor *>(this->_impl.get());
3021 return tmp->_block.item<T>();
3022 }
3023
3024 Scalar::Sproxy item() const {
3026 "[ERROR] Cannot use item on UniTensor with Symmetry.\n suggestion: use "
3027 "get_block()/get_blocks() first.%s",
3028 "\n");
3029
3030 DenseUniTensor *tmp = static_cast<DenseUniTensor *>(this->_impl.get());
3031 return tmp->_block.item();
3032 }
3037 cytnx_uint64 Nblocks() const { return this->_impl->Nblocks(); }
3038
3043 cytnx_uint64 rank() const { return this->_impl->rank(); }
3044
3049 cytnx_uint64 rowrank() const { return this->_impl->rowrank(); }
3050
3056 unsigned int dtype() const { return this->_impl->dtype(); }
3057
3064 int uten_type() const { return this->_impl->uten_type(); }
3065
3071 int device() const { return this->_impl->device(); }
3072
3077 std::string name() const { return this->_impl->name(); }
3078
3084 std::string dtype_str() const { return this->_impl->dtype_str(); }
3085
3091 std::string device_str() const { return this->_impl->device_str(); }
3092
3098 std::string uten_type_str() const { return this->_impl->uten_type_str(); }
3099
3105 bool is_contiguous() const { return this->_impl->is_contiguous(); }
3106
3111 bool is_diag() const { return this->_impl->is_diag(); }
3112
3118 bool is_tag() const { return this->_impl->is_tag(); }
3119
3125 std::vector<Symmetry> syms() const { return this->_impl->syms(); }
3126
3133 const bool &is_braket_form() const { return this->_impl->is_braket_form(); }
3134
3139 const std::vector<std::string> &labels() const { return this->_impl->labels(); }
3146 cytnx_int64 get_index(std::string label) const { return this->_impl->get_index(label); }
3147
3152 const std::vector<Bond> &bonds() const { return this->_impl->bonds(); }
3153
3157 std::vector<Bond> &bonds() { return this->_impl->bonds(); }
3158
3159 const Bond &bond_(const cytnx_uint64 &idx) const { return this->_impl->bond_(idx); }
3160 Bond &bond_(const cytnx_uint64 &idx) { return this->_impl->bond_(idx); }
3161
3162 const Bond &bond_(const std::string &label) const { return this->_impl->bond_(label); }
3163 Bond &bond_(const std::string &label) { return this->_impl->bond_(label); }
3164
3165 Bond bond(const cytnx_uint64 &idx) const { return this->_impl->bond_(idx).clone(); }
3166 Bond bond(const std::string &label) const { return this->_impl->bond_(label).clone(); }
3167
3172 std::vector<cytnx_uint64> shape() const { return this->_impl->shape(); }
3173
3180 std::vector<bool> signflip() const { return this->_impl->signflip(); }
3181
3190 std::vector<bool> &signflip_() { return this->_impl->signflip_(); }
3191
3197 bool is_blockform() const { return this->_impl->is_blockform(); }
3198
3205 UniTensor &to_(const int &device) {
3206 this->_impl->to_(device);
3207 return *this;
3208 }
3209
3219 UniTensor to(const int &device) const {
3220 UniTensor out;
3221 out._impl = this->_impl->to(device);
3222 return out;
3223 }
3224
3230 UniTensor out;
3231 out._impl = this->_impl->clone();
3232 return out;
3233 }
3234
3244 UniTensor &relabel_(const std::vector<std::string> &new_labels) {
3245 this->_impl->relabel_(new_labels);
3246 return *this;
3247 }
3253 [[deprecated(
3254 "Please use "
3255 "UniTensor &relabel_(const std::vector<std::string> &new_labels) "
3256 "instead.")]] UniTensor &
3257 relabels_(const std::vector<std::string> &new_labels) {
3258 this->_impl->relabels_(new_labels);
3259 return *this;
3260 }
3261
3273 UniTensor relabel(const std::vector<std::string> &new_labels) const {
3274 UniTensor out;
3275 out._impl = this->_impl->relabel(new_labels);
3276 return out;
3277 }
3283 [[deprecated(
3284 "Please use "
3285 "UniTensor relabel(const std::vector<std::string> &new_labels) const "
3286 "instead.")]] UniTensor
3287 relabels(const std::vector<std::string> &new_labels) const {
3288 UniTensor out;
3289 out._impl = this->_impl->relabels(new_labels);
3290 return out;
3291 }
3292
3297 UniTensor relabel(const std::initializer_list<char *> &new_labels) const {
3298 std::vector<char *> new_lbls(new_labels);
3299 std::vector<std::string> vs(new_lbls.size());
3300 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3301 [](char *x) -> std::string { return std::string(x); });
3302
3303 UniTensor out;
3304 out._impl = this->_impl->relabel(vs);
3305 return out;
3306 }
3312 [[deprecated(
3313 "Please use "
3314 "UniTensor relabel(const std::initializer_list<char *> &new_labels) const "
3315 "instead.")]] UniTensor
3316 relabels(const std::initializer_list<char *> &new_labels) const {
3317 std::vector<char *> new_lbls(new_labels);
3318 std::vector<std::string> vs(new_lbls.size());
3319 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3320 [](char *x) -> std::string { return std::string(x); });
3321
3322 UniTensor out;
3323 out._impl = this->_impl->relabels(vs);
3324 return out;
3325 }
3329 UniTensor &relabel_(const std::initializer_list<char *> &new_labels) {
3330 std::vector<char *> new_lbls(new_labels);
3331 std::vector<std::string> vs(new_lbls.size());
3332 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3333 [](char *x) -> std::string { return std::string(x); });
3334
3335 this->_impl->relabel_(vs);
3336 return *this;
3337 }
3343 [[deprecated(
3344 "Please use "
3345 "UniTensor &relabel_(const std::initializer_list<char *> &new_labels) "
3346 "instead.")]] UniTensor &
3347 relabels_(const std::initializer_list<char *> &new_labels) {
3348 std::vector<char *> new_lbls(new_labels);
3349 std::vector<std::string> vs(new_lbls.size());
3350 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3351 [](char *x) -> std::string { return std::string(x); });
3352
3353 this->_impl->relabels_(vs);
3354 return *this;
3355 }
3356
3364 UniTensor relabel(const std::vector<std::string> &old_labels,
3365 const std::vector<std::string> &new_labels) const {
3366 UniTensor out;
3367 out._impl = this->_impl->relabel(old_labels, new_labels);
3368 return out;
3369 }
3375 [[deprecated(
3376 "Please use "
3377 "UniTensor relabel(const std::vector<std::string> &old_labels, const "
3378 "std::vector<std::string> &new_labels) const "
3379 "instead.")]] UniTensor
3380 relabels(const std::vector<std::string> &old_labels,
3381 const std::vector<std::string> &new_labels) const {
3382 UniTensor out;
3383 out._impl = this->_impl->relabels(old_labels, new_labels);
3384 return out;
3385 }
3386
3402 UniTensor &relabel_(const std::vector<std::string> &old_labels,
3403 const std::vector<std::string> &new_labels) {
3404 this->_impl->relabel_(old_labels, new_labels);
3405 return *this;
3406 }
3412 [[deprecated(
3413 "Please use "
3414 "UniTensor &relabel_(const std::vector<std::string> &old_labels, const "
3415 "std::vector<std::string> &new_labels) "
3416 "instead.")]] UniTensor &
3417 relabels_(const std::vector<std::string> &old_labels,
3418 const std::vector<std::string> &new_labels) {
3419 this->_impl->relabels_(old_labels, new_labels);
3420 return *this;
3421 }
3422
3427 UniTensor relabel(const std::initializer_list<char *> &old_labels,
3428 const std::initializer_list<char *> &new_labels) const {
3429 std::vector<char *> new_lbls(new_labels);
3430 std::vector<std::string> vs(new_lbls.size());
3431 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3432 [](char *x) -> std::string { return std::string(x); });
3433
3434 std::vector<char *> old_lbls(old_labels);
3435 std::vector<std::string> vs_old(old_lbls.size());
3436 transform(old_lbls.begin(), old_lbls.end(), vs_old.begin(),
3437 [](char *x) -> std::string { return std::string(x); });
3438
3439 return this->relabel(vs_old, vs);
3440 }
3441
3447 [[deprecated(
3448 "Please use "
3449 "UniTensor relabel(const std::initializer_list<char *> &old_labels, const "
3450 "std::initializer_list<char *> &new_labels) const "
3451 "instead.")]] UniTensor
3452 relabels(const std::initializer_list<char *> &old_labels,
3453 const std::initializer_list<char *> &new_labels) const {
3454 std::vector<char *> new_lbls(new_labels);
3455 std::vector<std::string> vs(new_lbls.size());
3456 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3457 [](char *x) -> std::string { return std::string(x); });
3458
3459 std::vector<char *> old_lbls(old_labels);
3460 std::vector<std::string> vs_old(old_lbls.size());
3461 transform(old_lbls.begin(), old_lbls.end(), vs_old.begin(),
3462 [](char *x) -> std::string { return std::string(x); });
3463
3464 return this->relabels(vs_old, vs);
3465 }
3466
3471 UniTensor &relabel_(const std::initializer_list<char *> &old_labels,
3472 const std::initializer_list<char *> &new_labels) {
3473 std::vector<char *> new_lbls(new_labels);
3474 std::vector<std::string> vs(new_lbls.size());
3475 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3476 [](char *x) -> std::string { return std::string(x); });
3477
3478 std::vector<char *> old_lbls(old_labels);
3479 std::vector<std::string> vs_old(old_lbls.size());
3480 transform(old_lbls.begin(), old_lbls.end(), vs_old.begin(),
3481 [](char *x) -> std::string { return std::string(x); });
3482
3483 this->relabel_(vs_old, vs);
3484 return *this;
3485 }
3491 [[deprecated(
3492 "Please use "
3493 "UniTensor &relabel_(const std::initializer_list<char *> &old_labels, const "
3494 "std::initializer_list<char *> &new_labels) "
3495 "instead.")]] UniTensor &
3496 relabels_(const std::initializer_list<char *> &old_labels,
3497 const std::initializer_list<char *> &new_labels) {
3498 std::vector<char *> new_lbls(new_labels);
3499 std::vector<std::string> vs(new_lbls.size());
3500 transform(new_lbls.begin(), new_lbls.end(), vs.begin(),
3501 [](char *x) -> std::string { return std::string(x); });
3502
3503 std::vector<char *> old_lbls(old_labels);
3504 std::vector<std::string> vs_old(old_lbls.size());
3505 transform(old_lbls.begin(), old_lbls.end(), vs_old.begin(),
3506 [](char *x) -> std::string { return std::string(x); });
3507
3508 this->relabels_(vs_old, vs);
3509 return *this;
3510 }
3511
3526 UniTensor relabel(const cytnx_int64 &inx, const std::string &new_label) const {
3527 UniTensor out;
3528 out._impl = this->_impl->relabel(inx, new_label);
3529 return out;
3530 }
3539 UniTensor &relabel_(const cytnx_int64 &inx, const std::string &new_label) {
3540 this->_impl->relabel_(inx, new_label);
3541 return *this;
3542 }
3543
3552 UniTensor &relabel_(const std::string &old_label, const std::string &new_label) {
3553 this->_impl->relabel_(old_label, new_label);
3554 return *this;
3555 }
3556
3571 UniTensor relabel(const std::string &old_label, const std::string &new_label) const {
3572 UniTensor out;
3573 out._impl = this->_impl->relabel(old_label, new_label);
3574 return out;
3575 }
3576
3583 UniTensor astype(const unsigned int &dtype) const {
3584 UniTensor out;
3585 if (this->dtype() == dtype) {
3586 out._impl = this->_impl;
3587 } else {
3588 out._impl = this->_impl->astype(dtype);
3589 }
3590 return out;
3591 }
3592
3601 UniTensor permute(const std::vector<cytnx_int64> &mapper,
3602 const cytnx_int64 &rowrank = -1) const {
3603 UniTensor out;
3604 out._impl = this->_impl->permute(mapper, rowrank);
3605 return out;
3606 }
3607
3614 UniTensor permute(const std::vector<std::string> &mapper,
3615 const cytnx_int64 &rowrank = -1) const {
3616 UniTensor out;
3617 out._impl = this->_impl->permute(mapper, rowrank);
3618 return out;
3619 }
3620
3626 UniTensor permute(const std::initializer_list<char *> &mapper,
3627 const cytnx_int64 &rowrank = -1) const {
3628 std::vector<char *> mprs = mapper;
3629 std::vector<std::string> vs(mprs.size());
3630 transform(mprs.begin(), mprs.end(), vs.begin(),
3631 [](char *x) -> std::string { return std::string(x); });
3632
3633 return this->permute(vs, rowrank);
3634 }
3635
3643 UniTensor &permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank = -1) {
3644 this->_impl->permute_(mapper, rowrank);
3645 return *this;
3646 }
3647
3654 UniTensor &permute_(const std::vector<std::string> &mapper, const cytnx_int64 &rowrank = -1) {
3655 this->_impl->permute_(mapper, rowrank);
3656 return *this;
3657 }
3658
3672 UniTensor permute_nosignflip(const std::vector<cytnx_int64> &mapper,
3673 const cytnx_int64 &rowrank = -1) const {
3674 UniTensor out;
3675 out._impl = this->_impl->permute_nosignflip(mapper, rowrank);
3676 return out;
3677 }
3678
3690 UniTensor permute_nosignflip(const std::vector<std::string> &mapper,
3691 const cytnx_int64 &rowrank = -1) const {
3692 UniTensor out;
3693 out._impl = this->_impl->permute_nosignflip(mapper, rowrank);
3694 return out;
3695 }
3696
3702 UniTensor permute_nosignflip(const std::initializer_list<char *> &mapper,
3703 const cytnx_int64 &rowrank = -1) const {
3704 std::vector<char *> mprs = mapper;
3705 std::vector<std::string> vs(mprs.size());
3706 transform(mprs.begin(), mprs.end(), vs.begin(),
3707 [](char *x) -> std::string { return std::string(x); });
3708
3709 return this->permute_nosignflip(vs, rowrank);
3710 }
3711
3724 UniTensor &permute_nosignflip_(const std::vector<cytnx_int64> &mapper,
3725 const cytnx_int64 &rowrank = -1) {
3726 this->_impl->permute_nosignflip_(mapper, rowrank);
3727 return *this;
3728 }
3729
3741 UniTensor &permute_nosignflip_(const std::vector<std::string> &mapper,
3742 const cytnx_int64 &rowrank = -1) {
3743 this->_impl->permute_nosignflip_(mapper, rowrank);
3744 return *this;
3745 }
3746
3755 UniTensor twist(const std::string &label) const {
3756 UniTensor out = this->clone();
3757 out._impl->twist_(label);
3758 return out;
3759 }
3769 UniTensor out = this->clone();
3770 out._impl->twist_(idx);
3771 return out;
3772 }
3778 UniTensor &twist_(const std::string &label) {
3779 this->_impl->twist_(label);
3780 return *this;
3781 }
3788 this->_impl->twist_(idx);
3789 return *this;
3790 }
3791
3807 UniTensor out = this->clone();
3808 out._impl->fermion_twists_();
3809 return out;
3810 }
3817 this->_impl->fermion_twists_();
3818 return *this;
3819 }
3820
3828 UniTensor out;
3829 out._impl = this->_impl->contiguous();
3830 return out;
3831 }
3832
3838 this->_impl = this->_impl->contiguous_();
3839 return *this;
3840 }
3841
3851 UniTensor out;
3852 out._impl = this->_impl->apply();
3853 return out;
3854 }
3855
3862 this->_impl = this->_impl->apply_();
3863 return *this;
3864 }
3865
3870 void print_diagram(const bool &bond_info = false) const {
3871 this->_impl->print_diagram(bond_info);
3872 }
3873
3878 void print_blocks(const bool &full_info = true) const { this->_impl->print_blocks(full_info); }
3879
3885 void print_block(const cytnx_int64 &idx, const bool &full_info = true) const {
3886 this->_impl->print_block(idx, full_info);
3887 }
3888
3896 this->_impl->group_basis_();
3897 return *this;
3898 }
3899
3901 UniTensor out = this->clone();
3902 out.group_basis_();
3903 return out;
3904 }
3905
3914 template <class T>
3915 T &at(const std::vector<cytnx_uint64> &locator) {
3916 if (this->uten_type() == UTenType.Block || this->uten_type() == UTenType.BlockFermionic) {
3917 // [NEW] this will not check if it exists, if it is not then error will throw!
3918 T aux;
3919 return this->_impl->at_for_sparse(locator, aux);
3920
3921 } else if (this->uten_type() == UTenType.Sparse) {
3922 if (this->_impl->elem_exists(locator)) {
3923 T aux;
3924 return this->_impl->at_for_sparse(locator, aux);
3925 } else {
3926 cytnx_error_msg(true, "[ERROR][SparseUniTensor] invalid location. break qnum block.%s",
3927 "\n");
3928 }
3929 } else {
3930 return this->get_block_().at<T>(locator);
3931 }
3932 }
3933
3942 template <class T>
3943 const T &at(const std::vector<cytnx_uint64> &locator) const {
3944 if (this->uten_type() == UTenType.Block || this->uten_type() == UTenType.BlockFermionic) {
3945 // [NEW] this will not check if it exists, if it is not then error will throw!
3946 T aux;
3947 return this->_impl->at_for_sparse(locator, aux);
3948
3949 } else if (this->uten_type() == UTenType.Sparse) {
3950 if (this->_impl->elem_exists(locator)) {
3951 T aux; // [workaround] use aux to dispatch.
3952 return this->_impl->at_for_sparse(locator, aux);
3953 } else {
3954 cytnx_error_msg(true, "[ERROR][SparseUniTensor] invalid location. break qnum block.%s",
3955 "\n");
3956 }
3957 } else {
3958 return this->get_block_().at<T>(locator);
3959 }
3960 }
3961
3962 template <class T>
3963 const T &at(const std::vector<std::string> &labels,
3964 const std::vector<cytnx_uint64> &locator) const {
3965 // giving label <-> locator one to one corresponding, return the element:
3966 cytnx_error_msg(locator.size() != labels.size(),
3967 "[ERROR][at] length of list should be the same for label and locator.%s",
3968 "\n");
3970 labels.size() != this->rank(),
3971 "[ERROR][at] length of lists must be the same as UniTensor.rank (# of legs)%s", "\n");
3972 std::vector<cytnx_uint64> new_locator(this->rank());
3974 for (int i = 0; i < labels.size(); i++) {
3975 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
3976 cytnx_error_msg(res == this->_impl->_labels.end(),
3977 "[ERROR] label:%s does not exist in current UniTensor.\n",
3978 labels[i].c_str());
3979 new_loc = std::distance(this->_impl->_labels.begin(), res);
3981 }
3982 return this->at<T>(new_locator);
3983 }
3984 template <class T>
3985 T &at(const std::vector<std::string> &labels, const std::vector<cytnx_uint64> &locator) {
3986 // giving label <-> locator one to one corresponding, return the element:
3987 cytnx_error_msg(locator.size() != labels.size(),
3988 "[ERROR][at] length of list should be the same for label and locator.%s",
3989 "\n");
3991 labels.size() != this->rank(),
3992 "[ERROR][at] length of lists must be the same as UniTensor.rank (# of legs)%s", "\n");
3993 std::vector<cytnx_uint64> new_locator(this->rank());
3995 for (int i = 0; i < labels.size(); i++) {
3996 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
3997 cytnx_error_msg(res == this->_impl->_labels.end(),
3998 "[ERROR] label:%s does not exist in current UniTensor.\n",
3999 labels[i].c_str());
4000 new_loc = std::distance(this->_impl->_labels.begin(), res);
4002 }
4003 return this->at<T>(new_locator);
4004 }
4005
4013 const Scalar::Sproxy at(const std::vector<cytnx_uint64> &locator) const {
4014 if (this->uten_type() == UTenType.Block || this->uten_type() == UTenType.BlockFermionic) {
4015 return this->_impl->at_for_sparse(locator);
4016 } else if (this->uten_type() == UTenType.Sparse) {
4017 if (this->_impl->elem_exists(locator)) {
4018 return this->_impl->at_for_sparse(locator);
4019 } else {
4020 cytnx_error_msg(true, "[ERROR][SparseUniTensor] invalid location. break qnum block.%s",
4021 "\n");
4022 }
4023 } else {
4024 return this->get_block_().at(locator);
4025 }
4026 }
4027
4035 Scalar::Sproxy at(const std::vector<cytnx_uint64> &locator) {
4036 if (this->uten_type() == UTenType.Block || this->uten_type() == UTenType.BlockFermionic) {
4037 return this->_impl->at_for_sparse(locator);
4038 } else if (this->uten_type() == UTenType.Sparse) {
4039 if (this->_impl->elem_exists(locator)) {
4040 return this->_impl->at_for_sparse(locator);
4041 } else {
4042 cytnx_error_msg(true, "[ERROR][SparseUniTensor] invalid location. break qnum block.%s",
4043 "\n");
4044 }
4045 } else {
4046 return this->get_block_().at(locator);
4047 }
4048 }
4049
4050 Scalar::Sproxy at(const std::vector<std::string> &labels,
4051 const std::vector<cytnx_uint64> &locator) {
4052 // giving label <-> locator one to one corresponding, return the element:
4053 cytnx_error_msg(locator.size() != labels.size(),
4054 "[ERROR][at] length of list should be the same for label and locator.%s",
4055 "\n");
4057 labels.size() != this->rank(),
4058 "[ERROR][at] length of lists must be the same as UniTensor.rank (# of legs)%s", "\n");
4059 std::vector<cytnx_uint64> new_locator(this->rank());
4061 for (int i = 0; i < labels.size(); i++) {
4062 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
4063 cytnx_error_msg(res == this->_impl->_labels.end(),
4064 "[ERROR] label:%s does not exist in current UniTensor.\n",
4065 labels[i].c_str());
4066 new_loc = std::distance(this->_impl->_labels.begin(), res);
4068 }
4069 return this->at(new_locator);
4070 }
4071
4072 const Scalar::Sproxy at(const std::vector<std::string> &labels,
4073 const std::vector<cytnx_uint64> &locator) const {
4074 // giving label <-> locator one to one corresponding, return the element:
4075 cytnx_error_msg(locator.size() != labels.size(),
4076 "[ERROR][at] length of list should be the same for label and locator.%s",
4077 "\n");
4079 labels.size() != this->rank(),
4080 "[ERROR][at] length of lists must be the same as UniTensor.rank (# of legs)%s", "\n");
4081 std::vector<cytnx_uint64> new_locator(this->rank());
4083 for (int i = 0; i < labels.size(); i++) {
4084 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
4085 cytnx_error_msg(res == this->_impl->_labels.end(),
4086 "[ERROR] label:%s does not exist in current UniTensor.\n",
4087 labels[i].c_str());
4088 new_loc = std::distance(this->_impl->_labels.begin(), res);
4090 }
4091 return this->at(new_locator);
4092 }
4093
4094 // return a copy of the block with the given block index
4103 Tensor get_block(const cytnx_uint64 &idx = 0) const { return this->_impl->get_block(idx); };
4104 //================================
4105 // return a clone of block
4117 Tensor get_block(const std::vector<cytnx_int64> &qidx, const bool &force = false) const {
4118 return this->_impl->get_block(qidx, force);
4119 }
4120
4121 Tensor get_block(const std::vector<std::string> &labels, const std::vector<cytnx_int64> &qidx,
4122 const bool &force = false) const {
4124 labels.size() != qidx.size(),
4125 "[ERROR][get_block] length of lists must be the same for both lables and qnidices%s", "\n");
4126 cytnx_error_msg(labels.size() != this->rank(),
4127 "[ERROR][get_block] length of lists must be the rank (# of legs)%s", "\n");
4128
4129 std::vector<cytnx_int64> loc_id(this->rank());
4130 std::vector<cytnx_int64> new_qidx(this->rank());
4131
4133 std::vector<cytnx_uint64> new_order(this->rank());
4134 for (int i = 0; i < labels.size(); i++) {
4135 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
4136 cytnx_error_msg(res == this->_impl->_labels.end(),
4137 "[ERROR][get_block] label:%s does not exists in current Tensor.\n",
4138 labels[i].c_str());
4139 new_loc = std::distance(this->_impl->_labels.begin(), res);
4140 new_qidx[new_loc] = qidx[i];
4141 new_order[i] = new_loc;
4142 }
4143 auto out = this->_impl->get_block(new_qidx, force);
4144 if (out.dtype() != Type.Void) out.permute_(new_order);
4145 return out;
4146 }
4147
4152 Tensor get_block(const std::initializer_list<cytnx_int64> &qnum,
4153 const bool &force = false) const {
4154 std::vector<cytnx_int64> tmp = qnum;
4155 return get_block(tmp, force);
4156 }
4157
4162 Tensor get_block(const std::vector<cytnx_uint64> &qnum, const bool &force = false) const {
4163 std::vector<cytnx_int64> iqnum(qnum.begin(), qnum.end());
4164 return this->_impl->get_block(iqnum, force);
4165 }
4166
4167 Tensor get_block(const std::vector<std::string> &labels, const std::vector<cytnx_uint64> &qidx,
4168 const bool &force = false) const {
4169 std::vector<cytnx_int64> iqnum(qidx.begin(), qidx.end());
4170 return this->get_block(labels, iqnum, force);
4171 }
4172
4181 const Tensor &get_block_(const cytnx_uint64 &idx = 0) const {
4182 return this->_impl->get_block_(idx);
4183 }
4184
4189 Tensor &get_block_(const cytnx_uint64 &idx = 0) { return this->_impl->get_block_(idx); }
4190
4202 Tensor &get_block_(const std::vector<cytnx_int64> &qidx, const bool &force = false) {
4203 return this->_impl->get_block_(qidx, force);
4204 }
4205
4222 // developer note: Tensor is not the same object (Thus Tensor instead of Tensor& ),
4223 // since we permute! but they have shared data memory.
4224 Tensor get_block_(const std::vector<std::string> &labels, const std::vector<cytnx_int64> &qidx,
4225 const bool &force = false) {
4227 labels.size() != qidx.size(),
4228 "[ERROR][get_block] length of lists must be the same for both lables and qnidices%s", "\n");
4229 cytnx_error_msg(labels.size() != this->rank(),
4230 "[ERROR][get_block] length of lists must be the rank (# of legs)%s", "\n");
4231
4232 std::vector<cytnx_int64> loc_id(this->rank());
4233 std::vector<cytnx_int64> new_qidx(this->rank());
4234
4236 std::vector<cytnx_uint64> new_order(this->rank());
4237 for (int i = 0; i < labels.size(); i++) {
4238 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), labels[i]);
4239 cytnx_error_msg(res == this->_impl->_labels.end(),
4240 "[ERROR][get_block] label:%s does not exists in current Tensor.\n",
4241 labels[i].c_str());
4242 new_loc = std::distance(this->_impl->_labels.begin(), res);
4243 new_qidx[new_loc] = qidx[i];
4244 new_order[i] = new_loc;
4245 }
4246 auto out = this->_impl->get_block_(new_qidx, force);
4247 if (out.dtype() != Type.Void) {
4248 out = out.permute(new_order);
4249 }
4250 return out;
4251 }
4252
4256 Tensor &get_block_(const std::initializer_list<cytnx_int64> &qidx, const bool &force = false) {
4257 std::vector<cytnx_int64> tmp = qidx;
4258 return get_block_(tmp, force);
4259 }
4260
4264 Tensor &get_block_(const std::vector<cytnx_uint64> &qidx, const bool &force = false) {
4265 std::vector<cytnx_int64> iqidx(qidx.begin(), qidx.end());
4266 return get_block_(iqidx, force);
4267 }
4268
4269 Tensor get_block_(const std::vector<std::string> &labels, const std::vector<cytnx_uint64> &qidx,
4270 const bool &force = false) {
4271 std::vector<cytnx_int64> iqidx(qidx.begin(), qidx.end());
4272 return get_block_(labels, iqidx, force);
4273 }
4274 //================================
4275
4276 // this only work for non-symm tensor. return a shared view of block
4280 const Tensor &get_block_(const std::vector<cytnx_int64> &qidx,
4281 const bool &force = false) const {
4282 return this->_impl->get_block_(qidx, force);
4283 }
4284
4288 const Tensor &get_block_(const std::initializer_list<cytnx_int64> &qidx,
4289 const bool &force = false) const {
4290 std::vector<cytnx_int64> tmp = qidx;
4291 return this->_impl->get_block_(tmp, force);
4292 }
4293
4297 const Tensor &get_block_(const std::vector<cytnx_uint64> &qidx,
4298 const bool &force = false) const {
4299 std::vector<cytnx_int64> iqidx(qidx.begin(), qidx.end());
4300 return get_block_(iqidx, force);
4301 }
4302
4303 //================================
4315 //[dev]
4316 std::vector<Tensor> get_blocks() const { return this->_impl->get_blocks(); }
4317
4326 //[dev]
4327 const std::vector<Tensor> &get_blocks_(const bool &silent = false) const {
4328 return this->_impl->get_blocks_(silent);
4329 }
4330
4334 //[dev]
4335 std::vector<Tensor> &get_blocks_(const bool &silent = false) {
4336 return this->_impl->get_blocks_(silent);
4337 }
4338
4349 this->_impl->put_block(in, idx);
4350 return *this;
4351 }
4352
4358 [[deprecated(
4359 "Please use "
4360 "UniTensor &put_block(const Tensor &in, const cytnx_uint64 &idx) "
4361 "instead.")]] UniTensor &
4362 put_block(const Tensor &in, const cytnx_uint64 &idx, const bool &force) {
4363 this->_impl->put_block(in, idx);
4364 return *this;
4365 }
4366
4376 UniTensor &put_block(const Tensor &in_tens, const std::vector<cytnx_int64> &qidx) {
4377 this->_impl->put_block(in_tens, qidx);
4378 return *this;
4379 }
4380
4386 [[deprecated(
4387 "Please use "
4388 "UniTensor &put_block(const Tensor &in_tens, const std::vector<cytnx_int64> &qidx) "
4389 "instead.")]] UniTensor &
4390 put_block(const Tensor &in_tens, const std::vector<cytnx_int64> &qidx, const bool &force) {
4391 this->_impl->put_block(in_tens, qidx);
4392 return *this;
4393 }
4394
4403 UniTensor &put_block(Tensor &in, const std::vector<std::string> &lbls,
4404 const std::vector<cytnx_int64> &qidx) {
4406 lbls.size() != qidx.size(),
4407 "[ERROR][put_block] length of lists must be the same for both lables and qnidices%s", "\n");
4408 cytnx_error_msg(lbls.size() != this->rank(),
4409 "[ERROR][put_block] length of lists must be the rank (# of legs)%s", "\n");
4410
4411 std::vector<cytnx_int64> loc_id(this->rank());
4412 std::vector<cytnx_int64> new_qidx(this->rank());
4413
4415 // std::vector<cytnx_uint64> new_order(this->rank());
4416 std::vector<cytnx_uint64> inv_order(this->rank());
4417 for (int i = 0; i < lbls.size(); i++) {
4418 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), lbls[i]);
4419 cytnx_error_msg(res == this->_impl->_labels.end(),
4420 "[ERROR][put_block] label:%s does not exists in current Tensor.\n",
4421 lbls[i].c_str());
4422 new_loc = std::distance(this->_impl->_labels.begin(), res);
4423 new_qidx[new_loc] = qidx[i];
4424 // new_order[i] = new_loc;
4425 inv_order[new_loc] = i;
4426 }
4427 this->_impl->put_block(in.permute(inv_order), new_qidx);
4428 return *this;
4429 }
4430
4436 [[deprecated(
4437 "Please use "
4438 "UniTensor &put_block(Tensor &in, const std::vector<std::string> &lbls, const "
4439 "std::vector<cytnx_int64> &qidx) "
4440 "instead.")]] UniTensor &
4441 put_block(Tensor &in, const std::vector<std::string> &lbls,
4442 const std::vector<cytnx_int64> &qidx, const bool &force) {
4443 return put_block(in, lbls, qidx);
4444 }
4445
4456 this->_impl->put_block_(in, idx);
4457 return *this;
4458 }
4459
4469 UniTensor &put_block_(Tensor &in, const std::vector<cytnx_int64> &qidx) {
4470 this->_impl->put_block_(in, qidx);
4471 return *this;
4472 }
4473
4479 [[deprecated(
4480 "Please use "
4481 "UniTensor &put_block_(Tensor &in, const std::vector<cytnx_int64> &qidx) "
4482 "instead.")]] UniTensor &
4483 put_block_(Tensor &in, const std::vector<cytnx_int64> &qidx, const bool &force) {
4484 this->_impl->put_block_(in, qidx);
4485 return *this;
4486 }
4487
4496 UniTensor &put_block_(Tensor &in, const std::vector<std::string> &lbls,
4497 const std::vector<cytnx_int64> &qidx) {
4499 lbls.size() != qidx.size(),
4500 "[ERROR][put_block_] length of lists must be the same for both lables and qnidices%s",
4501 "\n");
4502 cytnx_error_msg(lbls.size() != this->rank(),
4503 "[ERROR][put_block_] length of lists must be the rank (# of legs)%s", "\n");
4504
4505 std::vector<cytnx_int64> loc_id(this->rank());
4506 std::vector<cytnx_int64> new_qidx(this->rank());
4507
4509 std::vector<cytnx_uint64> new_order(this->rank());
4510 std::vector<cytnx_uint64> inv_order(this->rank());
4511 for (int i = 0; i < lbls.size(); i++) {
4512 auto res = std::find(this->_impl->_labels.begin(), this->_impl->_labels.end(), lbls[i]);
4513 cytnx_error_msg(res == this->_impl->_labels.end(),
4514 "[ERROR][put_block_] label:%s does not exists in current Tensor.\n",
4515 lbls[i].c_str());
4516 new_loc = std::distance(this->_impl->_labels.begin(), res);
4517 new_qidx[new_loc] = qidx[i];
4518 new_order[i] = new_loc;
4519 inv_order[new_loc] = i;
4520 }
4521 in.permute_(inv_order);
4522 this->_impl->put_block_(in, new_qidx);
4523 in.permute_(new_order);
4524 return *this;
4525 }
4526
4532 [[deprecated(
4533 "Please use "
4534 "UniTensor &put_block_(Tensor &in, const std::vector<std::string> &lbls, const "
4535 "std::vector<cytnx_int64> &qidx) "
4536 "instead.")]] UniTensor &
4537 put_block_(Tensor &in, const std::vector<std::string> &lbls,
4538 const std::vector<cytnx_int64> &qidx, const bool &force) {
4539 return put_block_(in, lbls, qidx);
4540 }
4541
4557 UniTensor get(const std::vector<Accessor> &accessors) const {
4558 UniTensor out;
4559 out._impl = this->_impl->get(accessors);
4560 return out;
4561 }
4562
4567 UniTensor operator[](const std::vector<cytnx::Accessor> &accessors) const {
4568 UniTensor out;
4569 out._impl = this->_impl->get(accessors);
4570 return out;
4571 }
4572 UniTensor operator[](const std::initializer_list<cytnx::Accessor> &accessors) const {
4573 std::vector<cytnx::Accessor> acc_in = accessors;
4574 return this->get(acc_in);
4575 }
4576 UniTensor operator[](const std::vector<cytnx_int64> &accessors) const {
4577 std::vector<cytnx::Accessor> acc_in;
4578 for (cytnx_int64 i = 0; i < accessors.size(); i++) {
4579 acc_in.push_back(cytnx::Accessor(accessors[i]));
4580 }
4581 return this->get(acc_in);
4582 }
4583 UniTensor operator[](const std::initializer_list<cytnx_int64> &accessors) const {
4584 std::vector<cytnx_int64> acc_in = accessors;
4585 return (*this)[acc_in];
4586 }
4587
4604 UniTensor &set(const std::vector<Accessor> &accessors, const Tensor &rhs) {
4605 this->_impl->set(accessors, rhs);
4606 return *this;
4607 }
4608 UniTensor &set(const std::vector<Accessor> &accessors, const UniTensor &rhs) {
4610 rhs.uten_type() != UTenType.Dense,
4611 "[ERROR] Cannot set elements from UniTensor with symmetry. Use at() instead.%s", "\n");
4612 cytnx_error_msg(this->is_diag(), "[ERROR] Cannot set UniTensor with is_diag=True.%s", "\n");
4614 "[ERROR] Cannot set UniTensor. incoming UniTensor is_diag=True.%s", "\n");
4615
4616 this->_impl->set(accessors, rhs.get_block());
4617 return *this;
4618 }
4619
4627 UniTensor reshape(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank = 0) {
4628 UniTensor out;
4629 out._impl = this->_impl->reshape(new_shape, rowrank);
4630 return out;
4631 }
4632
4639 UniTensor &reshape_(const std::vector<cytnx_int64> &new_shape,
4640 const cytnx_uint64 &rowrank = 0) {
4641 this->_impl->reshape_(new_shape, rowrank);
4642 return *this;
4643 }
4644
4656 UniTensor out;
4657 out._impl = this->_impl->to_dense();
4658 return out;
4659 }
4660
4666 this->_impl->to_dense_();
4667 return *this;
4668 }
4669
4675 [[deprecated(
4676 "Please use "
4677 "combineBond(const std::vector<std::string> &indicators, const bool &force) "
4678 "instead.")]] void
4679 combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force,
4680 const bool &by_label) {
4681 this->_impl->combineBonds(indicators, force, by_label);
4682 }
4683
4689 [[deprecated(
4690 "Please use "
4691 "combineBond(const std::vector<std::string> &indicators, const bool &force) "
4692 "instead.")]] void
4693 combineBonds(const std::vector<std::string> &indicators, const bool &force = false) {
4694 this->_impl->combineBonds(indicators, force);
4695 }
4696
4702 [[deprecated(
4703 "Please use "
4704 "combineBond(const std::vector<std::string> &indicators, const bool &force) "
4705 "instead.")]] void
4706 combineBonds(const std::vector<cytnx_int64> &indicators, const bool &force = false) {
4707 this->_impl->combineBonds(indicators, force);
4708 }
4709
4720 UniTensor &combineBond(const std::vector<std::string> &indicators, const bool &force = false) {
4721 this->_impl->combineBond(indicators, force);
4722 return *this;
4723 }
4724
4743 UniTensor contract(const UniTensor &inR, const bool &mv_elem_self = false,
4744 const bool &mv_elem_rhs = false) const {
4745 UniTensor out;
4746 out._impl = this->_impl->contract(inR._impl, mv_elem_self, mv_elem_rhs);
4747 return out;
4748 }
4749
4751
4759 std::vector<Bond> getTotalQnums(const bool physical = false) const {
4760 return this->_impl->getTotalQnums(physical);
4761 }
4762
4766 std::vector<std::vector<cytnx_int64>> get_blocks_qnums() const {
4767 return this->_impl->get_blocks_qnums();
4768 }
4770
4775 bool same_data(const UniTensor &rhs) const {
4776 // check same type:
4777 if (this->_impl->uten_type() != rhs._impl->uten_type()) return false;
4778
4779 return this->_impl->same_data(rhs._impl);
4780 }
4781
4799 this->_impl->Add_(rhs._impl);
4800 return *this;
4801 }
4802
4820 this->_impl->Mul_(rhs._impl);
4821 return *this;
4822 }
4823
4841 this->_impl->Sub_(rhs._impl);
4842 return *this;
4843 }
4844
4862 this->_impl->Div_(rhs._impl);
4863 return *this;
4864 }
4865
4877 this->_impl->Add_(rhs);
4878 return *this;
4879 }
4880
4892 this->_impl->Mul_(rhs);
4893 return *this;
4894 }
4895
4907 this->_impl->Sub_(rhs);
4908 return *this;
4909 }
4910
4922 this->_impl->Div_(rhs);
4923 return *this;
4924 }
4925
4943
4954 UniTensor Add(const Scalar &rhs) const;
4955
4973
4984 UniTensor Mul(const Scalar &rhs) const;
4985
5003
5014 UniTensor Div(const Scalar &rhs) const;
5015
5033
5044 UniTensor Sub(const Scalar &rhs) const;
5045
5054 Tensor Norm() const { return this->_impl->Norm(); };
5055
5072 this->Add_(rhs);
5073 return *this;
5074 }
5075
5092 this->Sub_(rhs);
5093 return *this;
5094 }
5095
5112 this->Div_(rhs);
5113 return *this;
5114 }
5115
5132 this->Mul_(rhs);
5133 return *this;
5134 }
5135
5147 this->Add_(rhs);
5148 return *this;
5149 }
5150
5162 this->Sub_(rhs);
5163 return *this;
5164 }
5165
5177 this->Div_(rhs);
5178 return *this;
5179 }
5180
5192 this->Mul_(rhs);
5193 return *this;
5194 }
5195
5220 UniTensor Inv(double clip = -1.) const;
5221
5246 UniTensor &Inv_(double clip = -1.);
5247
5255 UniTensor Conj() const {
5256 UniTensor out;
5257 out._impl = this->_impl->Conj();
5258 return out;
5259 }
5260
5269 this->_impl->Conj_();
5270 return *this;
5271 }
5272
5287 UniTensor out;
5288 out._impl = this->_impl->Transpose();
5289 return out;
5290 }
5291
5300 this->_impl->Transpose_();
5301 return *this;
5302 }
5303
5311 UniTensor out;
5312 out._impl = this->_impl->normalize();
5313 return out;
5314 }
5315
5323 this->_impl->normalize_();
5324 return *this;
5325 }
5326
5336 UniTensor Trace(const std::string &a, const std::string &b) const {
5337 UniTensor out;
5338 out._impl = this->_impl->Trace(a, b);
5339 return out;
5340 }
5341
5351 UniTensor Trace(const cytnx_int64 &a = 0, const cytnx_int64 &b = 1) const {
5352 UniTensor out;
5353 out._impl = this->_impl->Trace(a, b);
5354 return out;
5355 }
5356
5366 UniTensor &Trace_(const std::string &a, const std::string &b) {
5367 this->_impl->Trace_(a, b);
5368 if (this->uten_type() == UTenType.Block || this->uten_type() == UTenType.BlockFermionic) {
5369 // handle if no leg left case for BlockUniTensor.
5370 if (this->rank() == 0) {
5371 DenseUniTensor *tmp = new DenseUniTensor();
5372 tmp->_block = this->get_blocks_(true)[0];
5373 this->_impl = boost::intrusive_ptr<UniTensor_base>(tmp);
5374 }
5375 }
5376 return *this;
5377 }
5378
5388 UniTensor &Trace_(const cytnx_int64 &a = 0, const cytnx_int64 &b = 1) {
5389 this->_impl->Trace_(a, b);
5390 if (this->uten_type() == UTenType.Block || this->uten_type() == UTenType.BlockFermionic) {
5391 // handle if no leg left case for BlockUniTensor.
5392 if (this->rank() == 0) {
5393 DenseUniTensor *tmp = new DenseUniTensor();
5394 tmp->_block = this->get_blocks_(true)[0];
5395 this->_impl = boost::intrusive_ptr<UniTensor_base>(tmp);
5396 }
5397 }
5398 return *this;
5399 }
5400
5410 UniTensor out;
5411 out._impl = this->_impl->Dagger();
5412 return out;
5413 }
5414
5424 this->_impl->Dagger_();
5425 return *this;
5426 }
5427
5437 this->_impl->tag();
5438 return *this;
5439 }
5440
5456 UniTensor Pow(const double &p) const;
5457
5473 UniTensor &Pow_(const double &p);
5474
5481 bool elem_exists(const std::vector<cytnx_uint64> &locator) const {
5482 return this->_impl->elem_exists(locator);
5483 }
5484
5490 template <class T>
5491 [[deprecated("Use at() instead.")]] T get_elem(const std::vector<cytnx_uint64> &locator) const {
5492 return this->at<T>(locator);
5493 }
5494
5500 template <class T2>
5501 [[deprecated("Use at() instead.")]] UniTensor &set_elem(
5502 const std::vector<cytnx_uint64> &locator, const T2 &rc) {
5503 // cytnx_error_msg(true,"[ERROR] invalid type%s","\n");
5504 this->at(locator) = rc;
5505 return *this;
5506 }
5507
5514 void Save(const std::string &fname) const;
5515
5522 void Save(const char *fname) const;
5523
5532 static UniTensor Load(const std::string &fname);
5533
5542 static UniTensor Load(const char *fname);
5543
5552 UniTensor &truncate_(const std::string &label, const cytnx_uint64 &dim) {
5553 this->_impl->truncate_(label, dim);
5554 return *this;
5555 }
5556
5566 this->_impl->truncate_(bond_idx, dim);
5567 return *this;
5568 }
5569
5579 UniTensor truncate(const std::string &label, const cytnx_uint64 &dim) const {
5580 UniTensor out = this->clone();
5581 out.truncate_(label, dim);
5582 return out;
5583 }
5584
5595 UniTensor out = this->clone();
5596 out.truncate_(bond_idx, dim);
5597 return out;
5598 }
5599
5607 const std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) const {
5608 return this->_impl->get_qindices(bidx);
5609 }
5617 std::vector<cytnx_uint64> &get_qindices(const cytnx_uint64 &bidx) {
5618 return this->_impl->get_qindices(bidx);
5619 }
5620
5627 const vec2d<cytnx_uint64> &get_itoi() const { return this->_impl->get_itoi(); }
5628 vec2d<cytnx_uint64> &get_itoi() { return this->_impl->get_itoi(); }
5629
5631 void _Load(std::fstream &f);
5632 void _Save(std::fstream &f) const;
5634
5650 this->_impl->from_(rhs._impl, force, tol);
5651 return *this;
5652 }
5653
5654 // Generators:
5668 const std::vector<std::string> &in_labels = {},
5669 const unsigned int &dtype = Type.Double, const int &device = Device.cpu,
5670 const std::string &name = "") {
5671 return UniTensor(cytnx::zeros(Nelem, dtype, device), false, -1, in_labels, name);
5672 }
5673
5687 static UniTensor zeros(const std::vector<cytnx_uint64> &shape,
5688 const std::vector<std::string> &in_labels = {},
5689 const unsigned int &dtype = Type.Double, const int &device = Device.cpu,
5690 const std::string &name = "") {
5691 return UniTensor(cytnx::zeros(shape, dtype, device), false, -1, in_labels, name);
5692 }
5693
5705 static UniTensor ones(const cytnx_uint64 &Nelem, const std::vector<std::string> &in_labels = {},
5706 const unsigned int &dtype = Type.Double, const int &device = Device.cpu,
5707 const std::string &name = "") {
5708 return UniTensor(cytnx::ones(Nelem, dtype, device), false, -1, in_labels, name);
5709 }
5710
5725 const std::vector<std::string> &in_labels = {},
5726 const cytnx_bool &is_diag = false,
5727 const unsigned int &dtype = Type.Double,
5728 const int &device = Device.cpu, const std::string &name = "") {
5729 if (is_diag) {
5730 return UniTensor(cytnx::ones(dim, dtype, device), is_diag, -1, in_labels, name);
5731 } else {
5732 return UniTensor(cytnx::identity(dim, dtype, device), is_diag, -1, in_labels, name);
5733 }
5734 }
5735
5751 static UniTensor eye(const cytnx_uint64 &dim, const std::vector<std::string> &in_labels = {},
5752 const cytnx_bool &is_diag = false, const unsigned int &dtype = Type.Double,
5753 const int &device = Device.cpu, const std::string &name = "") {
5754 return identity(dim, in_labels, is_diag, dtype, device, name);
5755 }
5756
5769 static UniTensor ones(const std::vector<cytnx_uint64> &shape,
5770 const std::vector<std::string> &in_labels = {},
5771 const unsigned int &dtype = Type.Double, const int &device = Device.cpu,
5772 const std::string &name = "") {
5773 return UniTensor(cytnx::ones(shape, dtype, device), false, -1, in_labels, name);
5774 }
5775
5791 const std::vector<std::string> &in_labels = {},
5792 const std::string &name = "") {
5793 return UniTensor(cytnx::arange(Nelem), false, -1, in_labels, name);
5794 }
5795
5814 const cytnx_double &step = 1,
5815 const std::vector<std::string> &in_labels = {},
5816 const unsigned int &dtype = Type.Double, const int &device = Device.cpu,
5817 const std::string &name = "") {
5818 return UniTensor(cytnx::arange(start, end, step, dtype, device), false, -1, in_labels, name);
5819 }
5820
5841 const cytnx_uint64 &Nelem, const bool &endpoint = true,
5842 const std::vector<std::string> &in_labels = {},
5843 const unsigned int &dtype = Type.Double,
5844 const int &device = Device.cpu, const std::string &name = "") {
5845 return UniTensor(cytnx::linspace(start, end, Nelem, endpoint, dtype, device), false, -1,
5846 in_labels, name);
5847 }
5848
5849 // Random Generators:
5868 static UniTensor normal(const cytnx_uint64 &Nelem, const double &mean, const double &std,
5869 const std::vector<std::string> &in_labels = {},
5870 const unsigned int &seed = cytnx::random::__static_random_device(),
5871 const unsigned int &dtype = Type.Double, const int &device = Device.cpu,
5872 const std::string &name = "");
5873
5892 static UniTensor normal(const std::vector<cytnx_uint64> &shape, const double &mean,
5893 const double &std, const std::vector<std::string> &in_labels = {},
5894 const unsigned int &seed = cytnx::random::__static_random_device(),
5895 const unsigned int &dtype = Type.Double, const int &device = Device.cpu,
5896 const std::string &name = "");
5897
5916 static UniTensor uniform(const cytnx_uint64 &Nelem, const double &low, const double &high,
5917 const std::vector<std::string> &in_labels = {},
5918 const unsigned int &seed = cytnx::random::__static_random_device(),
5919 const unsigned int &dtype = Type.Double,
5920 const int &device = Device.cpu, const std::string &name = "");
5921
5959 static UniTensor uniform(const std::vector<cytnx_uint64> &shape, const double &low,
5960 const double &high, const std::vector<std::string> &in_labels = {},
5961 const unsigned int &seed = cytnx::random::__static_random_device(),
5962 const unsigned int &dtype = Type.Double,
5963 const int &device = Device.cpu, const std::string &name = "");
5964
5965 // Inplace Random Generators:
5978 UniTensor &normal_(const double &mean, const double &std,
5979 const unsigned int &seed = cytnx::random::__static_random_device());
5980
5993 UniTensor &uniform_(const double &low = 0, const double &high = 1,
5994 const unsigned int &seed = cytnx::random::__static_random_device());
5995
5996 }; // class UniTensor
5997
5999 std::ostream &operator<<(std::ostream &os, const UniTensor &in);
6001
6014 UniTensor Contract(const UniTensor &inL, const UniTensor &inR, const bool &cacheL = false,
6015 const bool &cacheR = false);
6016
6029 UniTensor Contract(const std::vector<UniTensor> &TNs, const std::string &order,
6030 const bool &optimal);
6031
6037 [[deprecated(
6038 "Please use "
6039 "UniTensor Contract(const std::vector<UniTensor> &TNs, const std::string &order, const bool "
6040 "&optimal) "
6041 "instead.")]] UniTensor
6042 Contracts(const std::vector<UniTensor> &TNs, const std::string &order, const bool &optimal);
6043
6045 void _resolve_CT(std::vector<UniTensor> &TNlist);
6046 template <class... T>
6047 void _resolve_CT(std::vector<UniTensor> &TNlist, const UniTensor &in, const T &...args) {
6048 TNlist.push_back(in);
6049 _resolve_CT(TNlist, args...);
6050 }
6052
6064 template <class... T>
6065 UniTensor Contract(const UniTensor &in, const T &...args, const std::string &order,
6066 const bool &optimal) {
6067 std::vector<UniTensor> TNlist;
6068 _resolve_CT(TNlist, in, args...);
6069 return Contract(TNlist, order, optimal);
6070 }
6071
6077 template <class... T>
6078 [[deprecated(
6079 "Please use "
6080 "UniTensor Contract(const UniTensor &in, const T &...args, const std::string &order, const "
6081 "bool &optimal) "
6082 "instead.")]] UniTensor
6083 Contracts(const UniTensor &in, const T &...args, const std::string &order,
6084 const bool &optimal) {
6085 std::vector<UniTensor> TNlist;
6086 _resolve_CT(TNlist, in, args...);
6087 return Contracts(TNlist, order, optimal);
6088 }
6089
6090} // namespace cytnx
6091
6092#endif // BACKEND_TORCH
6093
6094#endif // CYTNX_UNITENSOR_H_
constexpr Type_class Type
data type
Definition Type.hpp:426
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:490
an tensor (multi-dimensional array)
Definition Tensor.hpp:41
T & at(const std::vector< cytnx_uint64 > &locator)
Get an element at specific location.
Definition Tensor.hpp:922
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:2679
UniTensor to(const int &device) const
move the current UniTensor to the assigned device.
Definition UniTensor.hpp:3219
UniTensor & operator*=(const UniTensor &rhs)
The multiplication assignment operator of the UniTensor.
Definition UniTensor.hpp:5131
static UniTensor eye(const cytnx_uint64 &dim, const std::vector< std::string > &in_labels={}, const cytnx_bool &is_diag=false, const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const std::string &name="")
Generate a 2-bond identity UniTensor.
Definition UniTensor.hpp:5751
Tensor & get_block_(const std::initializer_list< cytnx_int64 > &qidx, const bool &force=false)
Definition UniTensor.hpp:4256
std::vector< Tensor > & get_blocks_(const bool &silent=false)
Definition UniTensor.hpp:4335
Tensor & get_block_(const std::vector< cytnx_uint64 > &qidx, const bool &force=false)
Definition UniTensor.hpp:4264
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:3885
UniTensor & operator/=(const UniTensor &rhs)
The division assignment operator of the UniTensor.
Definition UniTensor.hpp:5111
UniTensor & set_elem(const std::vector< cytnx_uint64 > &locator, const T2 &rc)
Definition UniTensor.hpp:5501
T & item()
Definition UniTensor.hpp:3014
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:4469
bool is_contiguous() const
To tell whether the UniTensor is contiguous.
Definition UniTensor.hpp:3105
T get_elem(const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:5491
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.)
Copy data from a UniTensor of different type.
Definition UniTensor.hpp:5649
Tensor get_block(const std::vector< std::string > &labels, const std::vector< cytnx_int64 > &qidx, const bool &force=false) const
Definition UniTensor.hpp:4121
UniTensor & put_block(const Tensor &in, const cytnx_uint64 &idx, const bool &force)
Definition UniTensor.hpp:4362
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:5617
std::vector< bool > signflip() const
Get the sign information of a fermionic UniTensor.
Definition UniTensor.hpp:3180
UniTensor & set_label(const cytnx_int64 &idx, const char *new_label)
Definition UniTensor.hpp:2912
UniTensor & operator+=(const UniTensor &rhs)
The addition assignment operator of the UniTensor.
Definition UniTensor.hpp:5071
UniTensor reshape(const std::vector< cytnx_int64 > &new_shape, const cytnx_uint64 &rowrank=0)
Reshape the UniTensor.
Definition UniTensor.hpp:4627
std::vector< Tensor > get_blocks() const
Get all the blocks of the UniTensor.
Definition UniTensor.hpp:4316
UniTensor permute(const std::initializer_list< char * > &mapper, const cytnx_int64 &rowrank=-1) const
Definition UniTensor.hpp:3626
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:3118
std::string uten_type_str() const
Return the UniTensor type (cytnx::UTenType) of the UniTensor in 'string' form.
Definition UniTensor.hpp:3098
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:3690
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:2768
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:4117
UniTensor & contiguous_()
Make the UniTensor contiguous by coalescing the memory (storage), inplacely.
Definition UniTensor.hpp:3837
UniTensor & tag()
Set the UniTensor as a tagged UniTensor.
Definition UniTensor.hpp:5436
const Bond & bond_(const cytnx_uint64 &idx) const
Definition UniTensor.hpp:3159
void combineBonds(const std::vector< cytnx_int64 > &indicators, const bool &force=false)
Definition UniTensor.hpp:4706
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:3552
const T & at(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:3963
UniTensor & relabels_(const std::initializer_list< char * > &new_labels)
Definition UniTensor.hpp:3347
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:2718
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:4202
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:2741
static UniTensor zeros(const std::vector< cytnx_uint64 > &shape, const std::vector< std::string > &in_labels={}, const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const std::string &name="")
Generate a UniTensor with all elements set to zero.
Definition UniTensor.hpp:5687
UniTensor get(const std::vector< Accessor > &accessors) const
get elements using Accessor (C++ API) / slices (python API)
Definition UniTensor.hpp:4557
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:3724
T & at(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &locator)
Definition UniTensor.hpp:3985
UniTensor Conj() const
Apply complex conjugate on each entry of the UniTensor.
Definition UniTensor.hpp:5255
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.
Definition UniTensor.hpp:2927
UniTensor set_rowrank(const cytnx_uint64 &new_rowrank) const
Definition UniTensor.hpp:3007
UniTensor & set(const std::vector< Accessor > &accessors, const UniTensor &rhs)
Definition UniTensor.hpp:4608
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:5161
cytnx_uint64 rowrank() const
Return the row rank of the UniTensor.
Definition UniTensor.hpp:3049
UniTensor & put_block(const Tensor &in_tens, const std::vector< cytnx_int64 > &qidx)
Put the block into the UniTensor with given quantum number.
Definition UniTensor.hpp:4376
UniTensor & relabels_(const std::vector< std::string > &old_labels, const std::vector< std::string > &new_labels)
Definition UniTensor.hpp:3417
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:5054
UniTensor Mul(const Scalar &rhs) const
The multiplication function for a given scalar.
UniTensor & twist_(const std::string &label)
Inline version.
Definition UniTensor.hpp:3778
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:3755
UniTensor & set_labels(const std::initializer_list< char * > &new_labels)
Definition UniTensor.hpp:2986
UniTensor & relabel_(const std::initializer_list< char * > &new_labels)
Definition UniTensor.hpp:3329
UniTensor & Sub_(const Scalar &rhs)
The subtraction function for a given scalar.
Definition UniTensor.hpp:4906
UniTensor & relabel_(const cytnx_int64 &inx, const std::string &new_label)
rebable the legs in the UniTensor by given index.
Definition UniTensor.hpp:3539
UniTensor & operator/=(const Scalar &rhs)
The division assignment operator for a given scalar.
Definition UniTensor.hpp:5176
const bool & is_braket_form() const
Check whether the UniTensor is in braket form.
Definition UniTensor.hpp:3133
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:4567
static UniTensor linspace(const cytnx_double &start, const cytnx_double &end, const cytnx_uint64 &Nelem, const bool &endpoint=true, const std::vector< std::string > &in_labels={}, const unsigned int &dtype=Type.Double, const 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:5840
std::vector< cytnx_uint64 > shape() const
Get the shape of the UniTensor.
Definition UniTensor.hpp:3172
UniTensor to_dense()
Convert the UniTensor to non-diagonal form.
Definition UniTensor.hpp:4655
UniTensor & permute_(const std::vector< cytnx_int64 > &mapper, const cytnx_int64 &rowrank=-1)
permute the legs of the UniTensor, inplacely.
Definition UniTensor.hpp:3643
Scalar::Sproxy at(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &locator)
Definition UniTensor.hpp:4050
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:4280
UniTensor & set_labels(const std::vector< std::string > &new_labels)
Definition UniTensor.hpp:2972
std::string name() const
Return the name of the UniTensor.
Definition UniTensor.hpp:3077
const Scalar::Sproxy at(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:4072
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:4403
UniTensor & Add_(const Scalar &rhs)
The addition function for a given scalar.
Definition UniTensor.hpp:4876
UniTensor & set(const std::vector< Accessor > &accessors, const Tensor &rhs)
set elements using Accessor (C++ API) / slices (python API)
Definition UniTensor.hpp:4604
UniTensor & Trace_(const std::string &a, const std::string &b)
Take the partial trace of the UniTensor, inplacely.
Definition UniTensor.hpp:5366
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:5565
UniTensor & twist_(const cytnx_int64 &idx)
Inline version.
Definition UniTensor.hpp:3787
Scalar::Sproxy at(const std::vector< cytnx_uint64 > &locator)
Get an element at a specific location.
Definition UniTensor.hpp:4035
UniTensor Trace(const std::string &a, const std::string &b) const
Take the partial trace of the UniTensor.
Definition UniTensor.hpp:5336
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:2815
bool same_data(const UniTensor &rhs) const
Check whether the Blocks address are the same.
Definition UniTensor.hpp:4775
UniTensor astype(const unsigned int &dtype) const
Return a new UniTensor whose elements are casted to a different data type.
Definition UniTensor.hpp:3583
static UniTensor ones(const std::vector< cytnx_uint64 > &shape, const std::vector< std::string > &in_labels={}, const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const std::string &name="")
Generate a UniTensor with all elements set to one.
Definition UniTensor.hpp:5769
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:5579
UniTensor Transpose() const
Take the transpose of the UniTensor.
Definition UniTensor.hpp:5286
static UniTensor arange(const cytnx_double &start, const cytnx_double &end, const cytnx_double &step=1, const std::vector< std::string > &in_labels={}, const unsigned int &dtype=Type.Double, const 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:5813
UniTensor operator[](const std::initializer_list< cytnx_int64 > &accessors) const
Definition UniTensor.hpp:4583
UniTensor & set_label(const char *old_label, const std::string &new_label)
Definition UniTensor.hpp:2935
static UniTensor Load(const char *fname)
load a UniTensor from file
UniTensor & Dagger_()
Take the conjugate transpose to the UniTensor, inplacely.
Definition UniTensor.hpp:5423
std::vector< Bond > & bonds()
Definition UniTensor.hpp:3157
T & at(const std::vector< cytnx_uint64 > &locator)
Get an element at a specific location.
Definition UniTensor.hpp:3915
UniTensor & set_rowrank_(const cytnx_uint64 &new_rowrank)
Set the rowrank of the UniTensor.
Definition UniTensor.hpp:3002
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:4572
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:4496
UniTensor & set_label(const cytnx_int64 &idx, const std::string &new_label)
Set a new label for bond at the assigned index.
Definition UniTensor.hpp:2904
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:3672
UniTensor & fermion_twists_()
Inline version.
Definition UniTensor.hpp:3816
UniTensor & to_dense_()
Convert the UniTensor to non-diagonal form, inplacely.
Definition UniTensor.hpp:4665
UniTensor contiguous() const
Make the UniTensor contiguous by coalescing the memory (storage).
Definition UniTensor.hpp:3827
UniTensor & put_block_(Tensor &in, const cytnx_uint64 &idx=0)
Put the block into the UniTensor with given index, inplacely.
Definition UniTensor.hpp:4455
UniTensor & apply_()
Apply fermionic signflips to the UniTensor, inplacely. Subsequently, all elements returned by signfli...
Definition UniTensor.hpp:3861
Tensor get_block(const cytnx_uint64 &idx=0) const
Get the block of the UniTensor for a given block index.
Definition UniTensor.hpp:4103
const T & at(const std::vector< cytnx_uint64 > &locator) const
Get an element at a specific location.
Definition UniTensor.hpp:3943
UniTensor & operator*=(const Scalar &rhs)
The multiplication assignment operator for a given scalar.
Definition UniTensor.hpp:5191
UniTensor relabels(const std::vector< std::string > &old_labels, const std::vector< std::string > &new_labels) const
Definition UniTensor.hpp:3380
UniTensor normalize() const
normalize the current UniTensor instance with 2-norm.
Definition UniTensor.hpp:5310
static UniTensor ones(const cytnx_uint64 &Nelem, const std::vector< std::string > &in_labels={}, const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const std::string &name="")
Generate a one-bond UniTensor with all elements set to one.
Definition UniTensor.hpp:5705
UniTensor & relabel_(const std::vector< std::string > &new_labels)
Set new labels for all the bonds.
Definition UniTensor.hpp:3244
std::vector< Symmetry > syms() const
Return the symmetry type of the UniTensor.
Definition UniTensor.hpp:3125
UniTensor relabel(const std::vector< std::string > &new_labels) const
relabel all of the labels in UniTensor.
Definition UniTensor.hpp:3273
UniTensor & Mul_(const UniTensor &rhs)
The multiplcation function of the UniTensor.
Definition UniTensor.hpp:4819
static UniTensor zeros(const cytnx_uint64 &Nelem, const std::vector< std::string > &in_labels={}, const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const std::string &name="")
Generate a one-bond UniTensor with all elements set to zero.
Definition UniTensor.hpp:5667
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:3741
void combineBonds(const std::vector< std::string > &indicators, const bool &force=false)
Definition UniTensor.hpp:4693
UniTensor & combineBond(const std::vector< std::string > &indicators, const bool &force=false)
Combine the sevral bonds of the UniTensor.
Definition UniTensor.hpp:4720
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:3571
UniTensor & group_basis_()
Group the same quantum number basis together.
Definition UniTensor.hpp:3895
UniTensor & normalize_()
normalize the UniTensor, inplacely.
Definition UniTensor.hpp:5322
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:3111
int device() const
Return the device of the UniTensor.
Definition UniTensor.hpp:3071
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:4297
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:4224
std::string dtype_str() const
Return the data type of the UniTensor in 'string' form.
Definition UniTensor.hpp:3084
UniTensor & operator+=(const Scalar &rhs)
The addition assignment operator for a given scalar.
Definition UniTensor.hpp:5146
UniTensor & Div_(const UniTensor &rhs)
The division function of the UniTensor.
Definition UniTensor.hpp:4861
UniTensor & Div_(const Scalar &rhs)
The division function for a given scalar.
Definition UniTensor.hpp:4921
UniTensor & put_block_(Tensor &in, const std::vector< cytnx_int64 > &qidx, const bool &force)
Definition UniTensor.hpp:4483
Bond & bond_(const std::string &label)
Definition UniTensor.hpp:3163
cytnx_uint64 rank() const
Return the rank of the UniTensor.
Definition UniTensor.hpp:3043
Bond bond(const std::string &label) const
Definition UniTensor.hpp:3166
std::vector< bool > & signflip_()
Get reference to the sign information of a fermionic UniTensor.
Definition UniTensor.hpp:3190
UniTensor fermion_twists() const
Apply twists to all right bonds (>= rowrank) with bond type BD_KET.
Definition UniTensor.hpp:3806
UniTensor permute_nosignflip(const std::initializer_list< char * > &mapper, const cytnx_int64 &rowrank=-1) const
Definition UniTensor.hpp:3702
UniTensor & Trace_(const cytnx_int64 &a=0, const cytnx_int64 &b=1)
Take the partial trace of the UniTensor, inplacely.
Definition UniTensor.hpp:5388
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:3364
UniTensor & put_block(const Tensor &in, const cytnx_uint64 &idx=0)
Put the block into the UniTensor with given index.
Definition UniTensor.hpp:4348
UniTensor & put_block(const Tensor &in_tens, const std::vector< cytnx_int64 > &qidx, const bool &force)
Definition UniTensor.hpp:4390
UniTensor & set_name(const std::string &in)
Set the name of a UniTensor.
Definition UniTensor.hpp:2889
UniTensor Trace(const cytnx_int64 &a=0, const cytnx_int64 &b=1) const
Take the partial trace of the UniTensor.
Definition UniTensor.hpp:5351
UniTensor & Add_(const UniTensor &rhs)
The addition function of the UniTensor.
Definition UniTensor.hpp:4798
UniTensor permute(const std::vector< cytnx_int64 > &mapper, const cytnx_int64 &rowrank=-1) const
permute the legs of the UniTensor
Definition UniTensor.hpp:3601
UniTensor & set_label(const std::string &old_label, const char *new_label)
Definition UniTensor.hpp:2943
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:3614
unsigned int dtype() const
Return the data type of the UniTensor.
Definition UniTensor.hpp:3056
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:4891
UniTensor & operator-=(const UniTensor &rhs)
The subtraction assignment operator of the UniTensor.
Definition UniTensor.hpp:5091
Tensor get_block_(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &qidx, const bool &force=false)
Definition UniTensor.hpp:4269
void combineBonds(const std::vector< cytnx_int64 > &indicators, const bool &force, const bool &by_label)
Definition UniTensor.hpp:4679
UniTensor & set_label(const char *old_label, const char *new_label)
Definition UniTensor.hpp:2951
static UniTensor arange(const 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:5790
bool is_blockform() const
Check whether the UniTensor is in block form.
Definition UniTensor.hpp:3197
UniTensor group_basis() const
Definition UniTensor.hpp:3900
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:3768
UniTensor apply() const
Apply fermionic signflips to the UniTensor, such that all elements calling signflip() on the output t...
Definition UniTensor.hpp:3850
UniTensor Dagger() const
Take the conjugate transpose to the UniTensor.
Definition UniTensor.hpp:5409
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:4327
UniTensor & relabels_(const std::initializer_list< char * > &old_labels, const std::initializer_list< char * > &new_labels)
Definition UniTensor.hpp:3496
const Tensor & get_block_(const std::initializer_list< cytnx_int64 > &qidx, const bool &force=false) const
Definition UniTensor.hpp:4288
bool elem_exists(const std::vector< cytnx_uint64 > &locator) const
Given the locator, check if the element exists.
Definition UniTensor.hpp:5481
UniTensor & Sub_(const UniTensor &rhs)
The subtraction function of the UniTensor.
Definition UniTensor.hpp:4840
UniTensor relabels(const std::initializer_list< char * > &new_labels) const
Definition UniTensor.hpp:3316
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:4743
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:4181
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:3402
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:3654
const Bond & bond_(const std::string &label) const
Definition UniTensor.hpp:3162
static UniTensor identity(const cytnx_uint64 &dim, const std::vector< std::string > &in_labels={}, const cytnx_bool &is_diag=false, const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const std::string &name="")
Generate an identity UniTensor with two bonds.
Definition UniTensor.hpp:5724
Bond & bond_(const cytnx_uint64 &idx)
Definition UniTensor.hpp:3160
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:3526
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:4639
void print_diagram(const bool &bond_info=false) const
Plot the diagram of the UniTensor.
Definition UniTensor.hpp:3870
UniTensor relabels(const std::initializer_list< char * > &old_labels, const std::initializer_list< char * > &new_labels) const
Definition UniTensor.hpp:3452
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:5607
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:3139
UniTensor & relabel_(const std::initializer_list< char * > &old_labels, const std::initializer_list< char * > &new_labels)
Definition UniTensor.hpp:3471
cytnx_int64 get_index(std::string label) const
Get the index of an desired label string.
Definition UniTensor.hpp:3146
UniTensor & to_(const int &device)
move the current UniTensor to the assigned device (inplace).
Definition UniTensor.hpp:3205
const std::vector< Bond > & bonds() const
Get the bonds of the UniTensor.
Definition UniTensor.hpp:3152
Tensor get_block(const std::vector< std::string > &labels, const std::vector< cytnx_uint64 > &qidx, const bool &force=false) const
Definition UniTensor.hpp:4167
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:5594
UniTensor & Transpose_()
Take the transpose of the UniTensor, inplacely.
Definition UniTensor.hpp:5299
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:4441
UniTensor clone() const
Clone (deep copy) the UniTensor.
Definition UniTensor.hpp:3229
vec2d< cytnx_uint64 > & get_itoi()
Definition UniTensor.hpp:5628
void print_blocks(const bool &full_info=true) const
Print all blocks of the UniTensor.
Definition UniTensor.hpp:3878
Scalar::Sproxy item() const
Definition UniTensor.hpp:3024
const vec2d< cytnx_uint64 > & get_itoi() const
get the q-indices on each leg for all the blocks
Definition UniTensor.hpp:5627
std::string device_str() const
Return the device of the UniTensor in 'string' form.
Definition UniTensor.hpp:3091
UniTensor & put_block_(Tensor &in, const std::vector< std::string > &lbls, const std::vector< cytnx_int64 > &qidx, const bool &force)
Definition UniTensor.hpp:4537
UniTensor relabels(const std::vector< std::string > &new_labels) const
Definition UniTensor.hpp:3287
UniTensor relabel(const std::initializer_list< char * > &old_labels, const std::initializer_list< char * > &new_labels) const
Definition UniTensor.hpp:3427
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:5268
UniTensor operator[](const std::vector< cytnx_int64 > &accessors) const
Definition UniTensor.hpp:4576
UniTensor relabel(const std::initializer_list< char * > &new_labels) const
relables all of the labels in UniTensor.
Definition UniTensor.hpp:3297
cytnx_uint64 Nblocks() const
Return the number of blocks in the UniTensor.
Definition UniTensor.hpp:3037
Tensor get_block(const std::vector< cytnx_uint64 > &qnum, const bool &force=false) const
Definition UniTensor.hpp:4162
void Save(const char *fname) const
save a UniTensor to file
Bond bond(const cytnx_uint64 &idx) const
Definition UniTensor.hpp:3165
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:5552
Tensor get_block(const std::initializer_list< cytnx_int64 > &qnum, const bool &force=false) const
Definition UniTensor.hpp:4152
UniTensor & relabels_(const std::vector< std::string > &new_labels)
Definition UniTensor.hpp:3257
const Scalar::Sproxy at(const std::vector< cytnx_uint64 > &locator) const
Get an element at a specific location.
Definition UniTensor.hpp:4013
int uten_type() const
Return the UniTensor type (cytnx::UTenType) of the UniTensor.
Definition UniTensor.hpp:3064
Tensor & get_block_(const cytnx_uint64 &idx=0)
Definition UniTensor.hpp:4189
#define cytnx_warning_msg(is_true, format,...)
Definition cytnx_error.hpp:65
#define cytnx_error_msg(is_true, format,...)
Definition cytnx_error.hpp:27
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:29
Definition Accessor.hpp:12
Device_class Device
data on which devices.
Tensor linspace(const cytnx_double &start, const cytnx_double &end, const cytnx_uint64 &Nelem, const bool &endpoint=true, const unsigned int &dtype=Type.Double, const int &device=Device.cpu)
UniTensorType_class UTenType
UniTensor type.
@ Void
Definition Symmetry.hpp:32
Tensor arange(const cytnx_int64 &Nelem)
Create a rank-1 Tensor with incremental unsigned integer elements in the range [0,...
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 ones(const cytnx_uint64 &Nelem, const unsigned int &dtype=Type.Double, const int &device=Device.cpu)
Create a rank-1 Tensor with all elements initialized to one.
UniTensor Contracts(const std::vector< UniTensor > &TNs, const std::string &order, const bool &optimal)
Tensor zeros(const cytnx_uint64 &Nelem, const unsigned int &dtype=Type.Double, const int &device=Device.cpu)
Create a rank-1 Tensor with all elements initialized to zero.
Tensor identity(const cytnx_uint64 &Dim, const unsigned int &dtype=Type.Double, const int &device=Device.cpu)
Create a square rank-2 Tensor with the diagonal initialized to one and all other elements set to zero...