Cytnx v0.7.6
Loading...
Searching...
No Matches
UniTensor.hpp
Go to the documentation of this file.
1#ifndef _H_UniTensor_
2#define _H_UniTensor_
3
4#include "Type.hpp"
5#include "cytnx_error.hpp"
6#include "Storage.hpp"
7#include "Device.hpp"
8#include "Tensor.hpp"
9#include "Scalar.hpp"
10#include "utils/utils.hpp"
12#include <iostream>
13#include <vector>
14#include <map>
15#include <utility>
16#include <initializer_list>
17#include <fstream>
18#include <algorithm>
19#include "Symmetry.hpp"
20#include "Bond.hpp"
21//#include "linalg.hpp"
22
23//namespace cytnx{
24namespace cytnx{
25 using namespace cytnx;
27 class UniTensorType_class{
28 public:
29 enum : int{
30 Void=-99,
31 Dense=0,
32 Sparse=1,
33 };
34 std::string getname(const int &ut_type);
35 };
36 extern UniTensorType_class UTenType;
38
40 //class DenseUniTensor;
41 //class SparseUniTensor;
42 class UniTensor_base: public intrusive_ptr_base<UniTensor_base>{
43
44 public:
45 int uten_type_id; //the unitensor type id.
46 bool _is_braket_form;
47 bool _is_tag;
48 bool _is_diag;
49 cytnx_int64 _rowrank;
50 std::string _name;
51 std::vector<cytnx_int64> _labels;
52 std::vector< Bond > _bonds;
53
54
55
56 bool _update_braket(){
57 if(_bonds.size()==0) return false;
58
59 if(this->_bonds[0].type()!= bondType::BD_REG){
60 //check:
61 for(unsigned int i=0;i<this->_bonds.size();i++){
62 if(i<this->_rowrank){
63 if(this->_bonds[i].type()!=bondType::BD_KET) return false;
64 }else{
65 if(this->_bonds[i].type()!=bondType::BD_BRA) return false;
66 }
67 }
68 return true;
69 }else{
70 return false;
71 }
72 }
73
74 friend class UniTensor; // allow wrapper to access the private elems
75 friend class DenseUniTensor;
76 friend class SparseUniTensor;
77
78 UniTensor_base(): _is_tag(false), _name(std::string("")), _is_braket_form(false), _rowrank(-1), _is_diag(false), uten_type_id(UTenType.Void){};
79
80 //copy&assignment constr., use intrusive_ptr's !!
81 UniTensor_base(const UniTensor_base &rhs);
82 UniTensor_base& operator=(UniTensor_base &rhs);
83
84 cytnx_uint64 rowrank() const{return this->_rowrank;}
85 bool is_diag() const{ return this->_is_diag; }
86 const bool& is_braket_form() const{
87 return this->_is_braket_form;
88 }
89 const bool& is_tag() const{
90 return this->_is_tag;
91 }
92 const std::vector<cytnx_int64>& labels() const{ return this->_labels;}
93 const std::vector<Bond> &bonds() const {return this->_bonds;}
94 std::vector<Bond> &bonds(){return this->_bonds;}
95 const std::string& name() const { return this->_name;}
96 cytnx_uint64 rank() const {return this->_labels.size();}
97 void set_name(const std::string &in){ this->_name = in;}
98 void set_label(const cytnx_int64 &inx, const cytnx_int64 &new_label, const bool &by_label=false){
99 cytnx_int64 idx;
100 if(by_label){
101 auto res = std::find(this->_labels.begin(),this->_labels.end(),inx);
102 cytnx_error_msg(res==this->_labels.end(),"[ERROR] label %d not exists.\n",inx);
103 idx = std::distance(this->_labels.begin(), res);
104 }else{
105 idx = inx;
106 }
107
108 cytnx_error_msg(idx>=this->_labels.size(),"[ERROR] index exceed the rank of UniTensor%s","\n");
109 //check in:
110 bool is_dup =false;
111 for(cytnx_uint64 i=0;i<this->_labels.size();i++){
112 if(i==idx) continue;
113 if(new_label == this->_labels[i]){is_dup = true; break;}
114 }
115 cytnx_error_msg(is_dup,"[ERROR] alreay has a label that is the same as the input label%s","\n");
116 this->_labels[idx] = new_label;
117
118 }
119 void set_labels(const std::vector<cytnx_int64> &new_labels);
120
121
122
123
124
125 /*
126 template<class T>
127 T get_elem(const std::vector<cytnx_uint64> &locator) const{
128 if(this->is_blockform()){
129 if(this->elem_exists(locator)){
130 T aux; // [workaround] use aux to dispatch.
131 return this->at_for_sparse(locator,aux);
132 }else{
133 return 0;
134 }
135 }else{
136 return this->at<T>(locator);
137 }
138 }
139 template<class T>
140 void set_elem(const std::vector<cytnx_uint64> &locator, const T &input){
141 if(this->uten_type()==UTenType.Sparse){
142 if(this->elem_exists(locator)){
143 T aux;
144 this->at_for_sparse(locator,aux) = input;
145 }else{
146 cytnx_error_msg(true,"[ERROR][SparseUniTensor] invalid location. break qnum block.%s","\n");
147 }
148 }else{
149 this->at<T>(locator) = input;
150 }
151 }
152 */
153
154 int uten_type(){
155 return this->uten_type_id;
156 }
157 std::string uten_type_str(){
158 return UTenType.getname(this->uten_type_id);
159 }
160
161
162
163
164 virtual void Init(const std::vector<Bond> &bonds, const std::vector<cytnx_int64> &in_labels={}, const cytnx_int64 &rowrank=-1,const unsigned int &dtype=Type.Double,const int &device = Device.cpu,const bool &is_diag=false, const bool &no_alloc=false);
165 virtual void Init_by_Tensor(const Tensor& in, const cytnx_uint64 &rowrank, const bool &is_diag=false);
166 virtual std::vector<cytnx_uint64> shape() const;
167 virtual bool is_blockform() const ;
168 virtual bool is_contiguous() const;
169 virtual void to_(const int &device);
170 virtual boost::intrusive_ptr<UniTensor_base> to(const int &device);
171 virtual boost::intrusive_ptr<UniTensor_base> clone() const;
172 virtual unsigned int dtype() const;
173 virtual int device() const;
174 virtual std::string dtype_str() const;
175 virtual std::string device_str() const;
176 virtual void set_rowrank(const cytnx_uint64 &new_rowrank);
177 virtual boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,const cytnx_int64 &rowrank=-1, const bool &by_label=false);
178 virtual void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank=-1, const bool &by_label=false);
179 virtual boost::intrusive_ptr<UniTensor_base> contiguous_();
180 virtual boost::intrusive_ptr<UniTensor_base> contiguous();
181 virtual void print_diagram(const bool &bond_info=false);
182
183 virtual boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const;
184
185 virtual cytnx_uint64 Nblocks() const{return 0;};
186 virtual Tensor get_block(const cytnx_uint64 &idx=0) const; // return a copy of block
187 virtual Tensor get_block(const std::vector<cytnx_int64> &qnum, const bool &force) const; //return a copy of block
188
189 virtual const Tensor& get_block_(const cytnx_uint64 &idx=0) const; // return a share view of block, this only work for non-symm tensor.
190 virtual const Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force) const; //return a copy of block
191 virtual Tensor& get_block_(const cytnx_uint64 &idx=0); // return a share view of block, this only work for non-symm tensor.
192 virtual Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force); //return a copy of block
193 virtual bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const;
194
195 virtual std::vector<Tensor> get_blocks() const;
196 virtual const std::vector<Tensor>& get_blocks_(const bool &) const;
197 virtual std::vector<Tensor>& get_blocks_(const bool &);
198
199 virtual void put_block(const Tensor &in, const cytnx_uint64 &idx=0);
200 virtual void put_block_(Tensor &in, const cytnx_uint64 &idx=0);
201 virtual void put_block(const Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force);
202 virtual void put_block_(Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force);
203
204 // this will only work on non-symm tensor (DenseUniTensor)
205 virtual boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors);
206
207 // this will only work on non-symm tensor (DenseUniTensor)
208 virtual void set(const std::vector<Accessor> &accessors, const Tensor &rhs);
209
210 virtual void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0);
211 virtual boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0);
212 virtual boost::intrusive_ptr<UniTensor_base> to_dense();
213 virtual void to_dense_();
214 virtual void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &permute_back=false, const bool &by_label=true);
215 virtual boost::intrusive_ptr<UniTensor_base> contract(const boost::intrusive_ptr<UniTensor_base> &rhs, const bool &mv_elem_self=false, const bool &mv_elem_rhs=false);
216 virtual std::vector<Bond> getTotalQnums(const bool &physical=false);
217 virtual std::vector<std::vector<cytnx_int64> > get_blocks_qnums() const;
218 virtual void Trace_(const cytnx_int64 &a, const cytnx_int64 &b, const bool &by_label=false);
219 virtual boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b, const bool &by_label=false);
220 virtual boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<cytnx_int64> &new_labels);
221 virtual boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx, const cytnx_int64 &new_label, const bool &by_label=false);
222
223
224 virtual std::vector<Symmetry> syms() const;
225
226 // arithmetic
227 virtual void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
228 virtual void Add_(const Scalar &rhs);
229
230 virtual void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
231 virtual void Mul_(const Scalar &rhs);
232
233 virtual void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
234 virtual void Sub_(const Scalar &rhs);
235 virtual void lSub_(const Scalar &lhs);
236
237 virtual void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
238 virtual void Div_(const Scalar &rhs);
239 virtual void lDiv_(const Scalar &lhs);
240
241
242 virtual Tensor Norm() const;
243
244
245
246 virtual boost::intrusive_ptr<UniTensor_base> Conj();
247 virtual void Conj_();
248
249 virtual boost::intrusive_ptr<UniTensor_base> Transpose();
250 virtual void Transpose_();
251
252 virtual boost::intrusive_ptr<UniTensor_base> Dagger();
253 virtual void Dagger_();
254
255 virtual void tag();
256
257 virtual void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim, const bool &by_label=false);
258
259 virtual bool elem_exists(const std::vector<cytnx_uint64> &locator) const;
260
261 // this a workaround, as virtual function cannot template.
262 virtual Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator);
263 virtual const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const;
264
265 virtual cytnx_complex128& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex128 &aux);
266 virtual cytnx_complex64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex64 &aux);
267 virtual cytnx_double& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux);
268 virtual cytnx_float& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux);
269 virtual cytnx_uint64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux);
270 virtual cytnx_int64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux);
271 virtual cytnx_uint32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux);
272 virtual cytnx_int32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux);
273 virtual cytnx_uint16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux);
274 virtual cytnx_int16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux);
275
276 virtual const cytnx_complex128& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex128 &aux)const ;
277 virtual const cytnx_complex64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex64 &aux)const;
278 virtual const cytnx_double& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux)const;
279 virtual const cytnx_float& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux)const;
280 virtual const cytnx_uint64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux) const;
281 virtual const cytnx_int64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux) const;
282 virtual const cytnx_uint32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux) const;
283 virtual const cytnx_int32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux) const;
284 virtual const cytnx_uint16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux) const;
285 virtual const cytnx_int16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux) const;
286
287 virtual void _save_dispatch(std::fstream &f) const;
288 virtual void _load_dispatch(std::fstream &f);
289
290 virtual ~UniTensor_base(){};
291 };
293
294 //======================================================================
296 class DenseUniTensor: public UniTensor_base{
297 protected:
298 public:
299 Tensor _block;
300 std::vector<Tensor> _interface_block; // this is serves as interface for get_blocks_();
301 DenseUniTensor* clone_meta() const{
302 DenseUniTensor* tmp = new DenseUniTensor();
303 tmp->_bonds = vec_clone(this->_bonds);
304 tmp->_labels = this->_labels;
305 tmp->_is_braket_form = this->_is_braket_form;
306 tmp->_rowrank = this->_rowrank;
307 tmp->_is_diag = this->_is_diag;
308 tmp->_name = this->_name;
309 tmp->_is_tag = this->_is_tag;
310 return tmp;
311 }
312 //------------------------------------------
313
314 DenseUniTensor(){this->uten_type_id = UTenType.Dense;};
315 friend class UniTensor; // allow wrapper to access the private elems
316 // virtual functions
317 void Init(const std::vector<Bond> &bonds, const std::vector<cytnx_int64> &in_labels={}, const cytnx_int64 &rowrank=-1, const unsigned int &dtype=Type.Double,const int &device = Device.cpu, const bool &is_diag=false, const bool &no_alloc=false);
318 // this only work for non-symm tensor
319 void Init_by_Tensor(const Tensor& in_tensor, const cytnx_uint64 &rowrank, const bool &is_diag=false);
320 std::vector<cytnx_uint64> shape() const{
321 if(this->_is_diag){
322 std::vector<cytnx_uint64> shape = this->_block.shape();
323 shape.push_back(shape[0]);
324 return shape;
325 }else{
326 return this->_block.shape();
327 }
328 }
329 bool is_blockform() const{ return false;}
330 void to_(const int &device){
331 this->_block.to_(device);
332 }
333 boost::intrusive_ptr<UniTensor_base> to(const int &device){
334 if(this->device() == device){
335 return this;
336 }else{
337 boost::intrusive_ptr<UniTensor_base> out = this->clone();
338 out->to_(device);
339 return out;
340 }
341 }
342 void set_rowrank(const cytnx_uint64 &new_rowrank){
343 cytnx_error_msg(new_rowrank > this->_labels.size(),"[ERROR] rowrank cannot exceed the rank of UniTensor.%s","\n");
344 this->_rowrank = new_rowrank;
345 }
346
347 boost::intrusive_ptr<UniTensor_base> clone() const{
348 DenseUniTensor* tmp = this->clone_meta();
349 tmp->_block = this->_block.clone();
350 boost::intrusive_ptr<UniTensor_base> out(tmp);
351 return out;
352 };
353 bool is_contiguous() const{return this->_block.is_contiguous();}
354 unsigned int dtype() const{return this->_block.dtype();}
355 int device() const{return this->_block.device();}
356 std::string dtype_str() const{ return Type.getname(this->_block.dtype());}
357 std::string device_str() const{ return Device.getname(this->_block.device());}
358 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,const cytnx_int64 &rowrank=-1,const bool &by_label=false);
359 void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank=-1, const bool &by_label=false);
360 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<cytnx_int64> &new_labels);
361 boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx, const cytnx_int64 &new_label, const bool &by_label=false);
362
363 boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const{
364 DenseUniTensor* tmp = this->clone_meta();
365 tmp->_block = this->_block.astype(dtype);
366 boost::intrusive_ptr<UniTensor_base> out(tmp);
367 return tmp;
368 }
369
370 std::vector<Symmetry> syms() const{
371 cytnx_error_msg(true,"[ERROR][DenseUniTensor] dense unitensor does not have symmetry.%s","\n");
372 return std::vector<Symmetry>();
373 }
374
375 boost::intrusive_ptr<UniTensor_base> contiguous_(){this->_block.contiguous_(); return boost::intrusive_ptr<UniTensor_base>(this);}
376 boost::intrusive_ptr<UniTensor_base> contiguous(){
377 // if contiguous then return self!
378 if(this->is_contiguous()){
379 boost::intrusive_ptr<UniTensor_base> out(this);
380 return out;
381 }else{
382 DenseUniTensor* tmp = this->clone_meta();
383 tmp->_block = this->_block.contiguous();
384 boost::intrusive_ptr<UniTensor_base> out(tmp);
385 return out;
386 }
387 }
388 void print_diagram(const bool &bond_info=false);
389 Tensor get_block(const cytnx_uint64 &idx=0) const{ return this->_block.clone(); }
390
391 Tensor get_block(const std::vector<cytnx_int64> &qnum, const bool &force) const{cytnx_error_msg(true,"[ERROR][DenseUniTensor] try to get_block() using qnum on a non-symmetry UniTensor%s","\n"); return Tensor();}
392 // return a share view of block, this only work for non-symm tensor.
393 const Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force) const{cytnx_error_msg(true,"[ERROR][DenseUniTensor] try to get_block_() using qnum on a non-symmetry UniTensor%s","\n"); return this->_block;}
394 Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force){cytnx_error_msg(true,"[ERROR][DenseUniTensor] try to get_block_() using qnum on a non-symmetry UniTensor%s","\n"); return this->_block;}
395
396 // return a share view of block, this only work for non-symm tensor.
397 Tensor& get_block_(const cytnx_uint64 &idx=0){
398 return this->_block;
399 }
400 // return a share view of block, this only work for non-symm tensor.
401 const Tensor& get_block_(const cytnx_uint64 &idx=0) const{
402 return this->_block;
403 }
404
405 cytnx_uint64 Nblocks() const{return 1;};
406 std::vector<Tensor> get_blocks() const {
407 std::vector<Tensor> out;
408 cytnx_error_msg(true,"[ERROR][DenseUniTensor] cannot use get_blocks(), use get_block() instead!%s","\n");
409 return out; // this will not share memory!!
410 }
411 const std::vector<Tensor>& get_blocks_(const bool &silent=false) const {
412 cytnx_error_msg(true,"[ERROR][DenseUniTensor] cannot use get_blocks_(), use get_block_() instead!%s","\n");
413 return this->_interface_block; // this will not share memory!!
414 }
415 std::vector<Tensor>& get_blocks_(const bool &silent=false){
416 cytnx_error_msg(true,"[ERROR][DenseUniTensor] cannot use get_blocks_(), use get_block_() instead!%s","\n");
417 return this->_interface_block; // this will not share memory!!
418 }
419
420 void put_block(const Tensor &in, const cytnx_uint64 &idx=0){
421 if(this->is_diag()){
422 cytnx_error_msg(in.shape() != this->_block.shape(),"[ERROR][DenseUniTensor] put_block, the input tensor shape does not match.%s","\n");
423 this->_block = in.clone();
424 }else{
425 cytnx_error_msg(in.shape() != this->shape(),"[ERROR][DenseUniTensor] put_block, the input tensor shape does not match.%s","\n");
426 this->_block = in.clone();
427 }
428 }
429 // share view of the block
430 void put_block_(Tensor &in, const cytnx_uint64 &idx=0){
431 if(this->is_diag()){
432 cytnx_error_msg(in.shape() != this->_block.shape(),"[ERROR][DenseUniTensor] put_block, the input tensor shape does not match.%s","\n");
433 this->_block = in;
434 }else{
435 cytnx_error_msg(in.shape() != this->shape(),"[ERROR][DenseUniTensor] put_block, the input tensor shape does not match.%s","\n");
436 this->_block = in;
437 }
438 }
439
440 void put_block(const Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force){
441 cytnx_error_msg(true,"[ERROR][DenseUniTensor] try to put_block using qnum on a non-symmetry UniTensor%s","\n");
442 }
443 void put_block_(Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force){
444 cytnx_error_msg(true,"[ERROR][DenseUniTensor] try to put_block using qnum on a non-symmetry UniTensor%s","\n");
445 }
446 // this will only work on non-symm tensor (DenseUniTensor)
447 boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors){
448 boost::intrusive_ptr<UniTensor_base> out(new DenseUniTensor());
449 out->Init_by_Tensor(this->_block.get(accessors),0); //wrapping around.
450 return out;
451 }
452 // this will only work on non-symm tensor (DenseUniTensor)
453 void set(const std::vector<Accessor> &accessors, const Tensor &rhs){
454 this->_block.set(accessors,rhs);
455 }
456
457 void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0);
458 boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0);
459 boost::intrusive_ptr<UniTensor_base> to_dense();
460 void to_dense_();
461
462 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &permute_back=true, const bool &by_label=true);
463 boost::intrusive_ptr<UniTensor_base> contract(const boost::intrusive_ptr<UniTensor_base> &rhs, const bool &mv_elem_self=false, const bool &mv_elem_rhs=false);
464 std::vector<Bond> getTotalQnums(const bool &physical=false){
465 cytnx_error_msg(true,"[ERROR][DenseUniTensor] %s","getTotalQnums can only operate on UniTensor with symmetry.\n");
466 return std::vector<Bond>();
467 }
468
469
470 std::vector<std::vector<cytnx_int64> > get_blocks_qnums() const{
471 cytnx_error_msg(true,"[ERROR][DenseUniTensor] %s","get_blocks_qnums can only operate on UniTensor with symmetry.\n");
472 return std::vector<std::vector<cytnx_int64> >();
473 }
474
475 bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const{
476 if(rhs->uten_type()!=UTenType.Dense) return false;
477
478 return this->get_block_().same_data(rhs->get_block_());
479
480 }
481
482
483 ~DenseUniTensor(){};
484
485
486 // arithmetic
487 void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
488 void Add_(const Scalar &rhs);
489
490 void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
491 void Mul_(const Scalar &rhs);
492
493 void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
494 void Sub_(const Scalar &rhs);
495 void lSub_(const Scalar &lhs);
496
497 void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
498 void Div_(const Scalar &rhs);
499 void lDiv_(const Scalar &lhs);
500
501
502 void Conj_(){
503 this->_block.Conj_();
504 };
505
506 boost::intrusive_ptr<UniTensor_base> Conj(){
507 boost::intrusive_ptr<UniTensor_base> out = this->clone();
508 out->Conj_();
509 return out;
510 }
511
512 boost::intrusive_ptr<UniTensor_base> Transpose(){
513 boost::intrusive_ptr<UniTensor_base> out = this->clone();
514 out->Transpose_();
515 return out;
516 }
517 void Transpose_();
518
519 boost::intrusive_ptr<UniTensor_base> Dagger(){
520 boost::intrusive_ptr<UniTensor_base> out = this->Conj();
521 out->Transpose_();
522 return out;
523 }
524 void Dagger_(){
525 this->Conj_();
526 this->Transpose_();
527 }
528
529
530 void Trace_(const cytnx_int64 &a, const cytnx_int64 &b, const bool &by_label=false);
531 boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b, const bool &by_label=false){
532 boost::intrusive_ptr<UniTensor_base> out = this->clone();
533 out->Trace_(a,b,by_label);
534 return out;
535 }
536
537 Tensor Norm() const;
538
539 const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const {
540 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
541 //return cytnx_complex128(0,0);
542 }
543 const cytnx_complex128& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex128 &aux) const {
544 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
545 //return cytnx_complex128(0,0);
546 }
547 const cytnx_complex64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex64 &aux) const{
548 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
549 //return cytnx_complex64(0,0);
550 }
551 const cytnx_double& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux) const{
552 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
553 //return 0;
554 }
555 const cytnx_float& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux) const{
556 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
557 //return 0;
558 }
559 const cytnx_uint64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux) const{
560 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
561 //return 0;
562 }
563 const cytnx_int64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux) const{
564 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
565 //return 0;
566 }
567 const cytnx_uint32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux)const {
568 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
569 //return 0;
570
571 }
572 const cytnx_int32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux) const {
573 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
574 //return 0;
575 }
576 const cytnx_uint16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux)const {
577 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
578 //return 0;
579
580 }
581 const cytnx_int16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux) const {
582 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
583 //return 0;
584 }
585
586 Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator){
587 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
588 //return cytnx_complex128(0,0);
589 }
590 cytnx_complex128& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex128 &aux){
591 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
592 //return cytnx_complex128(0,0);
593 }
594 cytnx_complex64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex64 &aux){
595 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
596 //return cytnx_complex64(0,0);
597 }
598 cytnx_double& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux){
599 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
600 //return 0;
601 }
602 cytnx_float& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux){
603 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
604 //return 0;
605 }
606 cytnx_uint64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux){
607 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
608 //return 0;
609 }
610 cytnx_int64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux){
611 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
612 //return 0;
613 }
614 cytnx_uint32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux){
615 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
616 //return 0;
617
618 }
619 cytnx_int32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux){
620 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
621 //return 0;
622 }
623 cytnx_uint16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux){
624 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
625 //return 0;
626
627 }
628 cytnx_int16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux){
629 cytnx_error_msg(true,"[ERROR][Internal] This shouldn't be called by DenseUniTensor, something wrong.%s","\n");
630 //return 0;
631 }
632
633
634 bool elem_exists(const std::vector<cytnx_uint64> &locator) const{
635 cytnx_error_msg(true,"[ERROR][DenseUniTensor] elem_exists can only be used on UniTensor with Symmetry.%s","\n");
636 }
637 void tag(){
638 if(!this->is_tag()){
639 for(int i=0;i<this->_rowrank;i++){
640 this->_bonds[i].set_type(BD_KET);
641 }
642 for(int i=this->_rowrank;i<this->_bonds.size();i++){
643 this->_bonds[i].set_type(BD_BRA);
644 }
645 this->_is_tag = true;
646 this->_is_braket_form = this->_update_braket();
647 }
648 }
649 void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim, const bool &by_label=false);
650
651 void _save_dispatch(std::fstream &f) const;
652 void _load_dispatch(std::fstream &f);
653 // end virtual function
654
655
656
657 };
659
660
661 //======================================================================
663 class SparseUniTensor: public UniTensor_base{
664 protected:
665
666 public:
667
668 cytnx_uint64 _inner_rowrank;
669 std::vector<std::vector<cytnx_int64> > _blockqnums;
670 std::vector<cytnx_uint64> _mapper;
671 std::vector<cytnx_uint64> _inv_mapper;
672 std::vector<std::vector<cytnx_uint64> > _inner2outer_row;
673 std::vector<std::vector<cytnx_uint64> > _inner2outer_col;
674 std::map<cytnx_uint64,std::pair<cytnx_uint64,cytnx_uint64> > _outer2inner_row;
675 std::map<cytnx_uint64, std::pair<cytnx_uint64,cytnx_uint64> > _outer2inner_col;
676
677 std::vector<Tensor> _blocks;
678
679 bool _contiguous;
680 void set_meta(SparseUniTensor *tmp, const bool &inner, const bool &outer)const{
681 //outer meta
682 if(outer){
683 tmp->_bonds = vec_clone(this->_bonds);
684 tmp->_labels = this->_labels;
685 tmp->_is_braket_form = this->_is_braket_form;
686 tmp->_rowrank = this->_rowrank;
687 tmp->_name = this->_name;
688 }
689 //comm meta
690 tmp->_mapper = this->_mapper;
691 tmp->_inv_mapper = this->_inv_mapper;
692 tmp->_contiguous = this->_contiguous;
693 tmp->_is_diag = this->_is_diag;
694
695 //inner meta
696 if(inner){
697 tmp->_inner_rowrank = this->_inner_rowrank;
698 tmp->_inner2outer_row = this->_inner2outer_row;
699 tmp->_inner2outer_col = this->_inner2outer_col;
700 tmp->_outer2inner_row = this->_outer2inner_row;
701 tmp->_outer2inner_col = this->_outer2inner_col;
702 tmp->_blockqnums = this->_blockqnums;
703 }
704
705 }
706 SparseUniTensor* clone_meta(const bool &inner, const bool &outer) const{
707 SparseUniTensor* tmp = new SparseUniTensor();
708 this->set_meta(tmp,inner,outer);
709 return tmp;
710 };
711
712
713
714
715 //===================================
716 friend class UniTensor; // allow wrapper to access the private elems
717 SparseUniTensor(){
718 this->uten_type_id = UTenType.Sparse;
719 this->_is_tag = true;
720 };
721
722 // virtual functions
723 void Init(const std::vector<Bond> &bonds, const std::vector<cytnx_int64> &in_labels={}, const cytnx_int64 &rowrank=-1, const unsigned int &dtype=Type.Double,const int &device = Device.cpu, const bool &is_diag=false, const bool &no_alloc=false);
724 void Init_by_Tensor(const Tensor& in_tensor, const cytnx_uint64 &rowrank, const bool &is_diag=false){
725 cytnx_error_msg(true,"[ERROR][SparseUniTensor] cannot use Init_by_tensor() on a SparseUniTensor.%s","\n");
726 }
727 std::vector<cytnx_uint64> shape() const{
728 std::vector<cytnx_uint64> out(this->_bonds.size());
729 for(cytnx_uint64 i=0;i<out.size();i++){
730 out[i] = this->_bonds[i].dim();
731 }
732 return out;
733 }
734 bool is_blockform() const{return true;}
735 void to_(const int &device){
736 for(cytnx_uint64 i=0;i<this->_blocks.size();i++){
737 this->_blocks[i].to_(device);
738 }
739 };
740 boost::intrusive_ptr<UniTensor_base> to(const int &device){
741 if(this->device() == device){
742 return this;
743 }else{
744 boost::intrusive_ptr<UniTensor_base> out = this->clone();
745 out->to_(device);
746 return out;
747 }
748 };
749 boost::intrusive_ptr<UniTensor_base> clone() const{
750 SparseUniTensor* tmp = this->clone_meta(true,true);
751 tmp->_blocks = vec_clone(this->_blocks);
752 boost::intrusive_ptr<UniTensor_base> out(tmp);
753 return out;
754 };
755
756 bool is_contiguous() const{
757 return this->_contiguous;
758 };
759 void set_rowrank(const cytnx_uint64 &new_rowrank){
760 cytnx_error_msg((new_rowrank < 1) || (new_rowrank>= this->rank()),"[ERROR][SparseUniTensor] rowrank should be [>=1] and [<UniTensor.rank].%s","\n");
761 cytnx_error_msg(new_rowrank >= this->_labels.size(),"[ERROR] rowrank cannot exceed the rank of UniTensor.%s","\n");
762 if(this->_inner_rowrank!= new_rowrank)
763 this->_contiguous = false;
764
765 this->_rowrank = new_rowrank;
766 this->_is_braket_form = this->_update_braket();
767 }
768 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<cytnx_int64> &new_labels);
769 boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx, const cytnx_int64 &new_label, const bool &by_label=false);
770
771 unsigned int dtype() const{
772 #ifdef UNI_DEBUG
773 cytnx_error_msg(this->_blocks.size()==0,"[ERROR][internal] empty blocks for blockform.%s","\n");
774 #endif
775 return this->_blocks[0].dtype();
776 };
777 int device() const{
778 #ifdef UNI_DEBUG
779 cytnx_error_msg(this->_blocks.size()==0,"[ERROR][internal] empty blocks for blockform.%s","\n");
780 #endif
781 return this->_blocks[0].device();
782 };
783 std::string dtype_str() const{
784 #ifdef UNI_DEBUG
785 cytnx_error_msg(this->_blocks.size()==0,"[ERROR][internal] empty blocks for blockform.%s","\n");
786 #endif
787 return this->_blocks[0].dtype_str();
788 };
789 std::string device_str() const{
790 #ifdef UNI_DEBUG
791 cytnx_error_msg(this->_blocks.size()==0,"[ERROR][internal] empty blocks for blockform.%s","\n");
792 #endif
793 return this->_blocks[0].device_str();
794 };
795
796 boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const{
797 SparseUniTensor* tmp = this->clone_meta(true,true);
798 tmp->_blocks.resize(this->_blocks.size());
799 for(cytnx_int64 blk=0;blk<this->_blocks.size();blk++){
800 tmp->_blocks[blk] = this->_blocks[blk].astype(dtype);
801 }
802 boost::intrusive_ptr<UniTensor_base> out(tmp);
803 return out;
804 };
805
806 void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank=-1,const bool &by_label=false);
807 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,const cytnx_int64 &rowrank=-1, const bool &by_label=false);
808 boost::intrusive_ptr<UniTensor_base> contiguous();
809 boost::intrusive_ptr<UniTensor_base> contiguous_(){
810 if(!this->_contiguous){
811 boost::intrusive_ptr<UniTensor_base> titr = this->contiguous();
812 SparseUniTensor *tmp = (SparseUniTensor*)titr.get();
813 tmp->set_meta(this,true,true);
814 this->_blocks = tmp->_blocks;
815
816 }
817 return boost::intrusive_ptr<UniTensor_base>(this);
818
819 }
820 void print_diagram(const bool &bond_info=false);
821
822
823 std::vector<Symmetry> syms() const;
824
825 Tensor get_block(const cytnx_uint64 &idx=0) const{
826 cytnx_error_msg(idx>=this->_blocks.size(),"[ERROR][SparseUniTensor] index out of range%s","\n");
827 if(this->_contiguous){
828 return this->_blocks[idx].clone();
829 }else{
830 cytnx_error_msg(true,"[Developing] get block from a non-contiguous SparseUniTensor is currently not support. Call contiguous()/contiguous_() first.%s","\n");
831 return Tensor();
832 }
833 };
834 cytnx_uint64 Nblocks() const{ return this->_blocks.size();};
835 Tensor get_block(const std::vector<cytnx_int64> &qnum, const bool &force) const{
836 if(!force)
837 cytnx_error_msg(!this->is_braket_form(),"[ERROR][Un-physical] cannot get the block by qnums when bra-ket/in-out bonds mismatch the row/col space.\n permute to the correct physical space first, then get block.%s","\n");
838 //std::cout << "get_block" <<std::endl;
839 if(this->_contiguous){
840 //std::cout << "contiguous" << std::endl;
841 //get dtype from qnum:
842 cytnx_int64 idx=-1;
843 for(int i=0;i<this->_blockqnums.size();i++){
844 //for(int j=0;j<this->_blockqnums[i].size();j++)
845 // std::cout << this->_blockqnums[i][j]<< " ";
846 //std::cout << std::endl;
847 if(qnum==this->_blockqnums[i]){idx=i; break;}
848 }
849 cytnx_error_msg(idx<0,"[ERROR][SparseUniTensor] no block with [qnum] exists in the current UniTensor.%s","\n");
850 return this->get_block(idx);
851 }else{
852 cytnx_error_msg(true,"[Developing] get block from a non-contiguous SparseUniTensor is currently not support. Call contiguous()/contiguous_() first.%s","\n");
853 return Tensor();
854 }
855 return Tensor();
856 };
857
858 // return a share view of block, this only work for symm tensor in contiguous form.
859 Tensor& get_block_(const cytnx_uint64 &idx=0){
860 cytnx_error_msg(this->is_contiguous()==false,"[ERROR][SparseUniTensor] cannot use get_block_() on non-contiguous UniTensor with symmetry.\n suggest options: \n 1) Call contiguous_()/contiguous() first, then call get_block_()\n 2) Try get_block()/get_blocks()%s","\n");
861
862 cytnx_error_msg(idx >= this->_blocks.size(),"[ERROR][SparseUniTensor] index exceed the number of blocks.%s","\n");
863
864 return this->_blocks[idx];
865 }
866 const Tensor& get_block_(const cytnx_uint64 &idx=0) const{
867 cytnx_error_msg(this->is_contiguous()==false,"[ERROR][SparseUniTensor] cannot use get_block_() on non-contiguous UniTensor with symmetry.\n suggest options: \n 1) Call contiguous_()/contiguous() first, then call get_block_()\n 2) Try get_block()/get_blocks()%s","\n");
868
869 cytnx_error_msg(idx >= this->_blocks.size(),"[ERROR][SparseUniTensor] index exceed the number of blocks.%s","\n");
870
871 return this->_blocks[idx];
872 }
873
874 Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force){
875 if(!force)
876 cytnx_error_msg(!this->is_braket_form(),"[ERROR][Un-physical] cannot get the block by qnums when bra-ket/in-out bonds mismatch the row/col space.\n permute to the correct physical space first, then get block.%s","\n");
877
878 cytnx_error_msg(this->is_contiguous()==false,"[ERROR][SparseUniTensor] cannot use get_block_() on non-contiguous UniTensor with symmetry.\n suggest options: \n 1) Call contiguous_()/contiguous() first, then call get_blocks_()\n 2) Try get_block()/get_blocks()%s","\n");
879
880 //get dtype from qnum:
881 cytnx_int64 idx=-1;
882 for(int i=0;i<this->_blockqnums.size();i++){
883 if(qnum==this->_blockqnums[i]){idx=i; break;}
884 }
885 cytnx_error_msg(idx<0,"[ERROR][SparseUniTensor] no block with [qnum] exists in the current UniTensor.%s","\n");
886 return this->get_block_(idx);
887 //cytnx_error_msg(true,"[Developing]%s","\n");
888 }
889 const Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force) const{
890 if(!force)
891 cytnx_error_msg(!this->is_braket_form(),"[ERROR][Un-physical] cannot get the block by qnums when bra-ket/in-out bonds mismatch the row/col space.\n permute to the correct physical space first, then get block.%s","\n");
892
893 cytnx_error_msg(this->is_contiguous()==false,"[ERROR][SparseUniTensor] cannot use get_block_() on non-contiguous UniTensor with symmetry.\n suggest options: \n 1) Call contiguous_()/contiguous() first, then call get_blocks_()\n 2) Try get_block()/get_blocks()%s","\n");
894
895 //get dtype from qnum:
896 cytnx_int64 idx=-1;
897 for(int i=0;i<this->_blockqnums.size();i++){
898 if(qnum==this->_blockqnums[i]){idx=i; break;}
899 }
900 cytnx_error_msg(idx<0,"[ERROR][SparseUniTensor] no block with [qnum] exists in the current UniTensor.%s","\n");
901 return this->get_block_(idx);
902 }
903
904 std::vector<Tensor> get_blocks() const {
905 if(this->_contiguous){
906 return vec_clone(this->_blocks);
907 }else{
908 //cytnx_error_msg(true,"[Developing]%s","\n");
909 boost::intrusive_ptr<UniTensor_base> tmp = this->clone();
910 tmp->contiguous_();
911 SparseUniTensor *ttmp = (SparseUniTensor*)tmp.get();
912 return ttmp->_blocks;
913 }
914 };
915
916 const std::vector<Tensor>& get_blocks_(const bool &silent=false) const {
917 //cout << "[call this]" << endl;
918 if(this->_contiguous){
919 return this->_blocks;
920 }else{
921 //cytnx_error_msg(true,"[Developing]%s","\n");
922 if(!silent)
923 cytnx_warning_msg(true,"[WARNING][SparseUniTensor] call get_blocks_() with a non-contiguous UniTensor should be used with caution. \ntry: \n1) get_blocks()\n2) call contiguous/contiguous_() first, then get_blocks_() to get concise results%s","\n");
924
925 return this->_blocks;
926 }
927 };
928 std::vector<Tensor>& get_blocks_(const bool &silent=false){
929 //cout << "[call this]" << endl;
930 if(this->_contiguous){
931 return this->_blocks;
932 }else{
933 if(!silent)
934 cytnx_warning_msg(true,"[WARNING][SparseUniTensor] call get_blocks_() with a non-contiguous UniTensor should be used with caution. \ntry: \n1) get_blocks()\n2) call contiguous/contiguous_() first, then get_blocks_() to get concise results%s","\n");
935
936 return this->_blocks;
937 }
938 };
939
940 bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const{
941 if(rhs->uten_type()!=UTenType.Sparse) return false;
942 if(rhs->get_blocks_(1).size() != this->get_blocks_(1).size()) return false;
943
944 for(int i=0;i<rhs->get_blocks_(1).size();i++)
945 if(this->get_blocks_(1)[i].same_data(rhs->get_blocks_(1)[i])==false) return false;
946
947 return true;
948
949 }
950
951
952
953 void put_block_(Tensor &in,const cytnx_uint64 &idx=0){
954 cytnx_error_msg(this->is_contiguous()==false,"[ERROR][SparseUniTensor] cannot use put_block_() on non-contiguous UniTensor with symmetry.\n suggest options: \n 1) Call contiguous_()/contiguous() first, then call put_blocks_()\n 2) Try put_block()/put_blocks()%s","\n");
955
956 cytnx_error_msg(idx>=this->_blocks.size(),"[ERROR][SparseUniTensor] index out of range%s","\n");
957 cytnx_error_msg(in.shape()!=this->_blocks[idx].shape(),"[ERROR][SparseUniTensor] the shape of input tensor does not match the shape of block @ idx=%d\n",idx);
958 this->_blocks[idx] = in;
959 };
960 void put_block(const Tensor &in,const cytnx_uint64 &idx=0){
961 cytnx_error_msg(idx>=this->_blocks.size(),"[ERROR][SparseUniTensor] index out of range%s","\n");
962 if(this->_contiguous){
963 cytnx_error_msg(in.shape()!=this->_blocks[idx].shape(),"[ERROR][SparseUniTensor] the shape of input tensor does not match the shape of block @ idx=%d\n",idx);
964 this->_blocks[idx] = in.clone();
965 }else{
966 cytnx_error_msg(true,"[Developing] put block to a non-contiguous SparseUniTensor is currently not support. Call contiguous()/contiguous_() first.%s","\n");
967 }
968 };
969 void put_block(const Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force){
970 if(!force)
971 cytnx_error_msg(!this->is_braket_form(),"[ERROR][Un-physical] cannot get the block by qnums when bra-ket/in-out bonds mismatch the row/col space.\n permute to the correct physical space first, then get block.%s","\n");
972
973 //get dtype from qnum:
974 cytnx_int64 idx=-1;
975 for(int i=0;i<this->_blockqnums.size();i++){
976 if(qnum==this->_blockqnums[i]){idx=i; break;}
977 }
978 cytnx_error_msg(idx<0,"[ERROR][SparseUniTensor] no block with [qnum] exists in the current UniTensor.%s","\n");
979 this->put_block(in,idx);
980
981 };
982 void put_block_(Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force){
983 if(!force)
984 cytnx_error_msg(!this->is_braket_form(),"[ERROR][Un-physical] cannot get the block by qnums when bra-ket/in-out bonds mismatch the row/col space.\n permute to the correct physical space first, then get block.%s","\n");
985
986 //get dtype from qnum:
987 cytnx_int64 idx=-1;
988 for(int i=0;i<this->_blockqnums.size();i++){
989 if(qnum==this->_blockqnums[i]){idx=i; break;}
990 }
991 cytnx_error_msg(idx<0,"[ERROR][SparseUniTensor] no block with [qnum] exists in the current UniTensor.%s","\n");
992 this->put_block_(in,idx);
993 };
994
995 // this will only work on non-symm tensor (DenseUniTensor)
996 boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors){
997 cytnx_error_msg(true,"[ERROR][SparseUniTensor][get] cannot use get on a UniTensor with Symmetry.\n suggestion: try get_block()/get_blocks() first.%s","\n");
998 return nullptr;
999 }
1000 // this will only work on non-symm tensor (DenseUniTensor)
1001 void set(const std::vector<Accessor> &accessors, const Tensor &rhs){
1002 cytnx_error_msg(true,"[ERROR][SparseUniTensor][set] cannot use set on a UniTensor with Symmetry.\n suggestion: try get_block()/get_blocks() first.%s","\n");
1003 }
1004 void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0){
1005 cytnx_error_msg(true,"[ERROR] cannot reshape a UniTensor with symmetry.%s","\n");
1006 }
1007 boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0){
1008 cytnx_error_msg(true,"[ERROR] cannot reshape a UniTensor with symmetry.%s","\n");
1009 return nullptr;
1010 }
1011 boost::intrusive_ptr<UniTensor_base> to_dense(){
1012 cytnx_error_msg(true,"[ERROR] cannot to_dense a UniTensor with symmetry.%s","\n");
1013 return nullptr;
1014 }
1015 void to_dense_(){
1016 cytnx_error_msg(true,"[ERROR] cannot to_dense_ a UniTensor with symmetry.%s","\n");
1017 }
1018 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &permute_back=true, const bool &by_label=true){
1019 cytnx_error_msg(true,"[Developing]%s","\n");
1020 };
1021 boost::intrusive_ptr<UniTensor_base> contract(const boost::intrusive_ptr<UniTensor_base> &rhs, const bool &mv_elem_self=false, const bool &mv_elem_rhs=false);
1022 std::vector<Bond> getTotalQnums(const bool &physical=false);
1023 std::vector<std::vector<cytnx_int64> > get_blocks_qnums() const{
1024 return this->_blockqnums;
1025 }
1026 ~SparseUniTensor(){};
1027
1028
1029 // arithmetic
1030 void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1031 void Add_(const Scalar &rhs);
1032
1033 void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1034 void Mul_(const Scalar &rhs);
1035
1036 void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1037 void Sub_(const Scalar &rhs);
1038 void lSub_(const Scalar &lhs);
1039
1040 void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1041 void Div_(const Scalar &rhs);
1042 void lDiv_(const Scalar &lhs);
1043
1044
1045 boost::intrusive_ptr<UniTensor_base> Conj(){
1046 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1047 out->Conj_();
1048 return out;
1049 }
1050
1051 void Conj_(){
1052 for(int i=0;i<this->_blocks.size();i++){
1053 this->_blocks[i].Conj_();
1054 }
1055 };
1056 boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b, const bool &by_label=false);
1057 void Trace_(const cytnx_int64 &a, const cytnx_int64 &b, const bool &by_label=false){
1058 cytnx_error_msg(true,"[ERROR] Currently SparseUniTensor does not support inplace Trace!, call Trace() instead!%s","\n");
1059 }
1060
1061 void Transpose_();
1062 boost::intrusive_ptr<UniTensor_base> Transpose(){
1063 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1064 out->Transpose_();
1065 return out;
1066 }
1067
1068 boost::intrusive_ptr<UniTensor_base> Dagger(){
1069 boost::intrusive_ptr<UniTensor_base> out = this->Conj();
1070 out->Transpose_();
1071 return out;
1072 }
1073 void Dagger_(){
1074 this->Conj_();
1075 this->Transpose_();
1076 }
1077
1078 Tensor Norm() const;
1079
1080 void tag(){
1081 // no-use!
1082 }
1083
1084 void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim, const bool &by_label=false);
1085 const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const;
1086 const cytnx_complex128& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex128 &aux) const;
1087 const cytnx_complex64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex64 &aux) const;
1088 const cytnx_double& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux) const;
1089 const cytnx_float& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux) const;
1090 const cytnx_uint64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux) const;
1091 const cytnx_int64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux) const;
1092 const cytnx_uint32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux) const;
1093 const cytnx_int32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux) const;
1094 const cytnx_uint16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux) const;
1095 const cytnx_int16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux) const;
1096
1097
1098 Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator);
1099 cytnx_complex128& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex128 &aux);
1100 cytnx_complex64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex64 &aux);
1101 cytnx_double& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux);
1102 cytnx_float& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux);
1103 cytnx_uint64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux);
1104 cytnx_int64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux);
1105 cytnx_uint32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux);
1106 cytnx_int32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux);
1107 cytnx_uint16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux);
1108 cytnx_int16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux);
1109
1110 bool elem_exists(const std::vector<cytnx_uint64> &locator) const;
1111 void _save_dispatch(std::fstream &f) const;
1112 void _load_dispatch(std::fstream &f);
1113 // end virtual func
1114
1115
1116 };
1118
1119 //======================================================================
1120
1123
1124 public:
1125
1127 boost::intrusive_ptr<UniTensor_base> _impl;
1128 UniTensor(): _impl(new UniTensor_base()){};
1129 UniTensor(const UniTensor &rhs){
1130 this->_impl = rhs._impl;
1131 }
1132 UniTensor& operator=(const UniTensor &rhs){
1133 this->_impl = rhs._impl;
1134 return *this;
1135 }
1137
1139
1160 UniTensor(const Tensor &in_tensor, const cytnx_uint64 &rowrank, const bool &is_diag=false): _impl(new UniTensor_base()){
1161 this->Init(in_tensor,rowrank,is_diag);
1162 }
1163 void Init(const Tensor &in_tensor, const cytnx_uint64 &rowrank, const bool &is_diag=false){
1164 boost::intrusive_ptr<UniTensor_base> out(new DenseUniTensor());
1165 out->Init_by_Tensor(in_tensor, rowrank,is_diag);
1166 this->_impl = out;
1167 }
1169
1170
1172
1187 UniTensor(const std::vector<Bond> &bonds, const std::vector<cytnx_int64> &in_labels={}, const cytnx_int64 &rowrank=-1, const unsigned int &dtype=Type.Double, const int &device = Device.cpu, const bool &is_diag=false): _impl(new UniTensor_base()){
1188 #ifdef UNI_DEBUG
1189 cytnx_warning_msg(true,"[DEBUG] message: entry for UniTensor(const std::vector<Bond> &bonds, const std::vector<cytnx_int64> &in_labels={}, const cytnx_int64 &rowrank=-1, const unsigned int &dtype=Type.Double, const int &device = Device.cpu, const bool &is_diag=false)%s","\n");
1190 #endif
1191 this->Init(bonds,in_labels,rowrank,dtype,device,is_diag);
1192 }
1193 void Init(const std::vector<Bond> &bonds, const std::vector<cytnx_int64> &in_labels={}, const cytnx_int64 &rowrank=-1, const unsigned int &dtype=Type.Double, const int &device = Device.cpu, const bool &is_diag=false){
1194
1195 // checking type:
1196 bool is_sym = false;
1197 for(cytnx_uint64 i=0;i<bonds.size();i++){
1198 //check
1199 if(bonds[i].syms().size() != 0) is_sym = true;
1200 else cytnx_error_msg(is_sym,"[ERROR] cannot have bonds with mixing of symmetry and non-symmetry.%s","\n");
1201 }
1202
1203 // dynamical dispatch:
1204 if(is_sym){
1205 #ifdef UNI_DEBUG
1206 cytnx_warning_msg(true,"[DEBUG] message: entry dispatch: UniTensor: symmetric%s","\n");
1207 #endif
1208 //cytnx_warning_msg(true,"[warning, still developing, some functions will display \"[Developing]\"][SparseUniTensor]%s","\n");
1209 boost::intrusive_ptr<UniTensor_base> out(new SparseUniTensor());
1210 this->_impl = out;
1211 }else{
1212 boost::intrusive_ptr<UniTensor_base> out(new DenseUniTensor());
1213 this->_impl = out;
1214 }
1215 this->_impl->Init(bonds, in_labels, rowrank, dtype, device, is_diag, false);
1216 }
1218
1224 UniTensor& set_name(const std::string &in){
1225 this->_impl->set_name(in);
1226 return *this;
1227 }
1238 UniTensor& set_label(const cytnx_int64 &idx, const cytnx_int64 &new_label, const bool &by_label=false){
1239 this->_impl->set_label(idx,new_label,by_label);
1240 return *this;
1241 }
1242
1253 /*
1254 UniTensor& change_label(const cytnx_int64 &old_lbl, const cytnx_int64 &new_label){
1255 this->_impl->change_label(old_lbl,new_label);
1256 return *this;
1257 }
1258 */
1259
1260
1269 UniTensor& set_labels(const std::vector<cytnx_int64> &new_labels){
1270 this->_impl->set_labels(new_labels);
1271 return *this;
1272 }
1273 UniTensor& set_rowrank(const cytnx_uint64 &new_rowrank){
1274 this->_impl->set_rowrank(new_rowrank);
1275 return *this;
1276 }
1277
1278 template<class T>
1279 T& item(){
1280
1281 cytnx_error_msg(this->is_blockform(),"[ERROR] cannot use item on UniTensor with Symmetry.\n suggestion: use get_block()/get_blocks() first.%s","\n");
1282
1283 DenseUniTensor* tmp = static_cast<DenseUniTensor*>(this->_impl.get());
1284 return tmp->_block.item<T>();
1285
1286 }
1287
1288 Scalar::Sproxy item() const{
1289 cytnx_error_msg(this->is_blockform(),"[ERROR] cannot use item on UniTensor with Symmetry.\n suggestion: use get_block()/get_blocks() first.%s","\n");
1290
1291 DenseUniTensor* tmp = static_cast<DenseUniTensor*>(this->_impl.get());
1292 return tmp->_block.item();
1293
1294 }
1295
1296 cytnx_uint64 Nblocks() const{return this->_impl->Nblocks();}
1297 cytnx_uint64 rank() const {return this->_impl->rank();}
1298 cytnx_uint64 rowrank() const{return this->_impl->rowrank();}
1299 unsigned int dtype() const{ return this->_impl->dtype(); }
1300 int uten_type() const{ return this->_impl->uten_type();}
1301 int device() const{ return this->_impl->device(); }
1302 std::string name() const { return this->_impl->name();}
1303 std::string dtype_str() const{ return this->_impl->dtype_str();}
1304 std::string device_str() const{ return this->_impl->device_str();}
1305 std::string uten_type_str() const {return this->_impl->uten_type_str();}
1306 bool is_contiguous() const{ return this->_impl->is_contiguous();}
1307 bool is_diag() const{ return this->_impl->is_diag(); }
1308 bool is_tag() const { return this->_impl->is_tag();}
1309 std::vector<Symmetry> syms() const{
1310 return this->_impl->syms();
1311 }
1312 const bool& is_braket_form() const{
1313 return this->_impl->is_braket_form();
1314 }
1315 const std::vector<cytnx_int64>& labels() const{ return this->_impl->labels();}
1316 const std::vector<Bond> &bonds() const {return this->_impl->bonds();}
1317 std::vector<Bond> &bonds() {return this->_impl->bonds();}
1318 std::vector<cytnx_uint64> shape() const{return this->_impl->shape();}
1319 bool is_blockform() const{ return this->_impl->is_blockform();}
1320
1321 void to_(const int &device){this->_impl->to_(device);}
1322 UniTensor to(const int &device) const{
1323 UniTensor out;
1324 out._impl = this->_impl->to(device);
1325 return out;
1326 }
1328 UniTensor out;
1329 out._impl = this->_impl->clone();
1330 return out;
1331 }
1332 UniTensor relabels(const std::vector<cytnx_int64> &new_labels) const{
1333 UniTensor out;
1334 out._impl = this->_impl->relabels(new_labels);
1335 return out;
1336 }
1337 UniTensor relabel(const cytnx_int64 &inx, const cytnx_int64 &new_label, const bool &by_label=false) const{
1338 UniTensor out;
1339 out._impl = this->_impl->relabel(inx,new_label,by_label);
1340 return out;
1341 }
1342
1343 UniTensor astype(const unsigned int &dtype) const{
1344 UniTensor out;
1345 if(this->dtype()==dtype){
1346 out._impl = this->_impl;
1347 }else{
1348 out._impl = this->_impl->astype(dtype);
1349 }
1350 return out;
1351 }
1352
1353 UniTensor permute(const std::vector<cytnx_int64> &mapper,const cytnx_int64 &rowrank=-1,const bool &by_label=false){UniTensor out; out._impl = this->_impl->permute(mapper,rowrank,by_label); return out;}
1354 void permute_(const std::vector<cytnx_int64> &mapper,const cytnx_int64 &rowrank=-1,const bool &by_label=false){
1355 this->_impl->permute_(mapper,rowrank,by_label);
1356 }
1358 UniTensor out;
1359 out._impl = this->_impl->contiguous();
1360 return out;
1361 }
1363 this->_impl = this->_impl->contiguous_();
1364 }
1365 void print_diagram(const bool &bond_info=false){
1366 this->_impl->print_diagram(bond_info);
1367 }
1368
1369 template<class T>
1370 T& at(const std::vector<cytnx_uint64> &locator){
1371 //std::cout << "at " << this->is_blockform() << std::endl;
1372 if(this->uten_type()==UTenType.Sparse){
1373 if(this->_impl->elem_exists(locator)){
1374 T aux;
1375 return this->_impl->at_for_sparse(locator,aux);
1376 }else{
1377 cytnx_error_msg(true,"[ERROR][SparseUniTensor] invalid location. break qnum block.%s","\n");
1378 }
1379 }else{
1380 return this->get_block_().at<T>(locator);
1381 }
1382
1383 }
1384
1385 template<class T>
1386 const T& at(const std::vector<cytnx_uint64> &locator) const{
1387 //std::cout << "at " << this->is_blockform() << std::endl;
1388 if(this->uten_type()==UTenType.Sparse){
1389 if(this->_impl->elem_exists(locator)){
1390 T aux; // [workaround] use aux to dispatch.
1391 return this->_impl->at_for_sparse(locator,aux);
1392 }else{
1393 cytnx_error_msg(true,"[ERROR][SparseUniTensor] invalid location. break qnum block.%s","\n");
1394 }
1395 }else{
1396 return this->get_block_().at<T>(locator);
1397 }
1398
1399 }
1400
1401 const Scalar::Sproxy at(const std::vector<cytnx_uint64> &locator) const{
1402 if(this->uten_type()==UTenType.Sparse){
1403 if(this->_impl->elem_exists(locator)){
1404 return this->_impl->at_for_sparse(locator);
1405 }else{
1406 cytnx_error_msg(true,"[ERROR][SparseUniTensor] invalid location. break qnum block.%s","\n");
1407 }
1408 }else{
1409 return this->get_block_().at(locator);
1410 }
1411 }
1412
1413 Scalar::Sproxy at(const std::vector<cytnx_uint64> &locator){
1414 if(this->uten_type()==UTenType.Sparse){
1415 if(this->_impl->elem_exists(locator)){
1416 return this->_impl->at_for_sparse(locator);
1417 }else{
1418 cytnx_error_msg(true,"[ERROR][SparseUniTensor] invalid location. break qnum block.%s","\n");
1419 }
1420 }else{
1421 return this->get_block_().at(locator);
1422 }
1423 }
1424
1425
1426
1427
1428 // return a clone of block
1429 Tensor get_block(const cytnx_uint64 &idx=0) const{
1430 return this->_impl->get_block(idx);
1431 };
1432 //================================
1433 // return a clone of block
1434 Tensor get_block(const std::vector<cytnx_int64> &qnum, const bool &force=false) const{
1435 return this->_impl->get_block(qnum,force);
1436 }
1437 Tensor get_block(const std::initializer_list<cytnx_int64> &qnum, const bool &force=false) const{
1438 std::vector<cytnx_int64> tmp = qnum;
1439 return get_block(tmp,force);
1440 }
1441 //================================
1442 // this only work for non-symm tensor. return a shared view of block
1443 const Tensor& get_block_(const cytnx_uint64 &idx=0) const{
1444 return this->_impl->get_block_(idx);
1445 }
1446 //================================
1447 // this only work for non-symm tensor. return a shared view of block
1449 return this->_impl->get_block_(idx);
1450 }
1451 //================================
1452 // this only work for non-symm tensor. return a shared view of block
1453 Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force=false){
1454 return this->_impl->get_block_(qnum,force);
1455 }
1456 Tensor& get_block_(const std::initializer_list<cytnx_int64> &qnum,const bool &force=false){
1457 std::vector<cytnx_int64> tmp = qnum;
1458 return get_block_(tmp,force);
1459 }
1460 //================================
1461
1462 // this only work for non-symm tensor. return a shared view of block
1463 const Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force=false) const{
1464 return this->_impl->get_block_(qnum,force);
1465 }
1466 const Tensor& get_block_(const std::initializer_list<cytnx_int64> &qnum, const bool &force=false) const{
1467 std::vector<cytnx_int64> tmp = qnum;
1468 return this->_impl->get_block_(tmp,force);
1469 }
1470 //================================
1471 // this return a shared view of blocks for non-symm tensor.
1472 // for symmetry tensor, it call contiguous first and return a shared view of blocks. [dev]
1473 std::vector<Tensor> get_blocks() const {
1474 return this->_impl->get_blocks();
1475 }
1476 // this return a shared view of blocks for non-symm tensor.
1477 // for symmetry tensor, it call contiguous first and return a shared view of blocks. [dev]
1478 const std::vector<Tensor>& get_blocks_(const bool &silent=false) const {
1479 return this->_impl->get_blocks_(silent);
1480 }
1481 // for symmetry tensor, it call contiguous first and return a shared view of blocks. [dev]
1482 std::vector<Tensor>& get_blocks_(const bool &silent=false){
1483 return this->_impl->get_blocks_(silent);
1484 }
1485
1486 // the put block will have shared view with the internal block, i.e. non-clone.
1487 void put_block(const Tensor &in,const cytnx_uint64 &idx=0){
1488 this->_impl->put_block(in,idx);
1489 }
1490 // the put block will have shared view with the internal block, i.e. non-clone.
1491 void put_block(const Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force){
1492 this->_impl->put_block(in,qnum, force);
1493 }
1494 // the put block will have shared view with the internal block, i.e. non-clone.
1495 void put_block_(Tensor &in,const cytnx_uint64 &idx=0){
1496 this->_impl->put_block_(in,idx);
1497 }
1498 // the put block will have shared view with the internal block, i.e. non-clone.
1499 void put_block_(Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force){
1500 this->_impl->put_block_(in,qnum,force);
1501 }
1502 UniTensor get(const std::vector<Accessor> &accessors) const{
1503 UniTensor out;
1504 out._impl = this->_impl->get(accessors);
1505 return out;
1506 }
1507 void set(const std::vector<Accessor> &accessors, const Tensor &rhs){
1508 this->_impl->set(accessors, rhs);
1509 }
1510 UniTensor reshape(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0){
1511 UniTensor out;
1512 out._impl = this->_impl->reshape(new_shape,rowrank);
1513 return out;
1514 }
1515 void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0){
1516 this->_impl->reshape_(new_shape,rowrank);
1517 }
1519 UniTensor out;
1520 out._impl = this->_impl->to_dense();
1521 return out;
1522 }
1524 this->_impl->to_dense_();
1525 }
1526 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &permute_back=true, const bool &by_label=true){
1527 this->_impl->combineBonds(indicators,permute_back,by_label);
1528 }
1529 UniTensor contract(const UniTensor &inR, const bool &mv_elem_self=false, const bool &mv_elem_rhs=false) const{
1530 UniTensor out;
1531 out._impl = this->_impl->contract(inR._impl,mv_elem_self,mv_elem_rhs);
1532 return out;
1533 }
1534 std::vector<Bond> getTotalQnums(const bool physical=false) const{
1535 return this->_impl->getTotalQnums(physical);
1536 }
1537 std::vector<std::vector<cytnx_int64> > get_blocks_qnums() const{
1538 return this->_impl->get_blocks_qnums();
1539 }
1540
1541 bool same_data(const UniTensor &rhs) const{
1542
1543 // check same type:
1544 if(this->_impl->uten_type() != rhs._impl->uten_type())
1545 return false;
1546
1547
1548
1549 return this->_impl->same_data(rhs._impl);
1550 }
1551
1553 this->_impl->Add_(rhs._impl);
1554 return *this;
1555 }
1556
1558 this->_impl->Mul_(rhs._impl);
1559 return *this;
1560 }
1561
1563 this->_impl->Sub_(rhs._impl);
1564 return *this;
1565 }
1566
1568 this->_impl->Div_(rhs._impl);
1569 return *this;
1570 }
1571
1572 UniTensor& Add_(const Scalar &rhs){
1573 this->_impl->Add_(rhs);
1574 return *this;
1575 }
1576
1577 UniTensor& Mul_(const Scalar &rhs){
1578 this->_impl->Mul_(rhs);
1579 return *this;
1580 }
1581
1582 UniTensor& Sub_(const Scalar &rhs){
1583 this->_impl->Sub_(rhs);
1584 return *this;
1585 }
1586
1587 UniTensor& Div_(const Scalar &rhs){
1588 this->_impl->Div_(rhs);
1589 return *this;
1590 }
1591
1592 UniTensor Add(const UniTensor &rhs) const;
1593 UniTensor Add(const Scalar &rhs) const;
1594 UniTensor Mul(const UniTensor &rhs) const;
1595 UniTensor Mul(const Scalar &rhs) const;
1596 UniTensor Div(const UniTensor &rhs) const;
1597 UniTensor Div(const Scalar &rhs) const;
1598 UniTensor Sub(const UniTensor &rhs) const;
1599 UniTensor Sub(const Scalar &rhs) const;
1600
1601 Tensor Norm() const{
1602 return this->_impl->Norm();
1603 };
1604
1606 this->Add_(rhs);
1607 return *this;
1608 }
1610 this->Sub_(rhs);
1611 return *this;
1612 }
1614 this->Div_(rhs);
1615 return *this;
1616 }
1618 this->Mul_(rhs);
1619 return *this;
1620 }
1622 this->Add_(rhs);
1623 return *this;
1624 }
1626 this->Sub_(rhs);
1627 return *this;
1628 }
1630 this->Div_(rhs);
1631 return *this;
1632 }
1634 this->Mul_(rhs);
1635 return *this;
1636 }
1637
1638
1639
1641 UniTensor out;
1642 out._impl = this->_impl->Conj();
1643 return out;
1644 }
1645
1647 this->_impl->Conj_();
1648 return *this;
1649 }
1650
1651
1653 UniTensor out;
1654 out._impl = this->_impl->Transpose();
1655 return out;
1656 }
1658 this->_impl->Transpose_();
1659 return *this;
1660 }
1661
1662 UniTensor Trace(const cytnx_int64 &a=0, const cytnx_int64 &b=1, const bool &by_label=false) const{
1663 UniTensor out;
1664 out._impl = this->_impl->Trace(a,b,by_label);
1665 return out;
1666 }
1667
1668 UniTensor& Trace_(const cytnx_int64 &a=0, const cytnx_int64 &b=1, const bool &by_label=false){
1669 this->_impl->Trace_(a,b,by_label);
1670 return *this;
1671 }
1672
1674 UniTensor out;
1675 out._impl = this->_impl->Dagger();
1676 return out;
1677 }
1678
1680 this->_impl->Dagger_();
1681 return *this;
1682 }
1683
1685 this->_impl->tag();
1686 return *this;
1687 }
1688
1689 UniTensor Pow(const double &p) const;
1690 UniTensor& Pow_(const double &p);
1691
1692
1693
1694
1695
1696 bool elem_exists( const std::vector<cytnx_uint64> &locator) const{
1697 return this->_impl->elem_exists(locator);
1698 }
1699
1700 // [C++: Deprecated soon, use at]
1701 template<class T>
1702 T get_elem(const std::vector<cytnx_uint64> &locator) const{
1703 return this->at<T>(locator);
1704 }
1705
1706 // [C++: Deprecated soon, use at]
1707 template<class T2>
1708 void set_elem(const std::vector<cytnx_uint64> &locator, const T2&rc){
1709 //cytnx_error_msg(true,"[ERROR] invalid type%s","\n");
1710 this->at(locator) = rc;
1711 }
1712
1713
1714
1715 void Save(const std::string &fname) const;
1716 void Save(const char* fname) const;
1717 static UniTensor Load(const std::string &fname);
1718 static UniTensor Load(const char* fname);
1719
1720 UniTensor& truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim, const bool &by_label=false){
1721 this->_impl->truncate_(bond_idx,dim,by_label);
1722 return *this;
1723 }
1724 UniTensor truncate(const cytnx_int64 &bond_idx, const cytnx_uint64& dim, const bool &by_label=false) const{
1725 UniTensor out = this->clone();
1726 out.truncate_(bond_idx,dim,by_label);
1727 return out;
1728 }
1729
1730
1732 void _Load(std::fstream &f);
1733 void _Save(std::fstream &f) const;
1735
1736 };//class UniTensor
1737
1738
1739
1740
1742 std::ostream& operator<<(std::ostream& os, const UniTensor &in);
1744
1757 UniTensor Contract(const UniTensor &inL, const UniTensor &inR, const bool &cacheL=false, const bool &cacheR=false);
1758
1759
1769 UniTensor Contracts(const std::vector<UniTensor> &TNs);
1770
1771
1772
1774 void _resolve_CT(std::vector<UniTensor> &TNlist);
1775 template<class ... T>
1776 void _resolve_CT(std::vector<UniTensor> &TNlist, const UniTensor &in, const T&... args){
1777 TNlist.push_back(in);
1778 _resolve_CT(TNlist,args...);
1779 }
1781
1792 template<class ... T>
1793 UniTensor Contracts(const UniTensor& in, const T&... args){
1794 std::vector<UniTensor> TNlist;
1795 _resolve_CT(TNlist,in,args...);
1796 return Contracts(TNlist);
1797 }
1798
1799
1800
1801
1802}
1803#endif
Definition Scalar.hpp:1751
an tensor (multi-dimensional array)
Definition Tensor.hpp:344
void to_(const int &device)
move the current Tensor to the device.
Definition Tensor.hpp:836
Tensor contiguous_()
Make the Tensor contiguous by coalescing the memory (storage), inplacely.
Definition Tensor.hpp:923
unsigned int dtype() const
the dtype-id of the Tensor
Definition Tensor.hpp:729
Tensor contiguous() const
Make the Tensor contiguous by coalescing the memory (storage).
Definition Tensor.hpp:902
T & at(const std::vector< cytnx_uint64 > &locator)
[C++ only] get an element at specific location.
Definition Tensor.hpp:1057
Tensor clone() const
return a clone of the current Tensor.
Definition Tensor.hpp:787
void set(const std::vector< cytnx::Accessor > &accessors, const Tensor &rhs)
set elements with the input Tensor using Accessor (C++ API) / slices (python API)
Definition Tensor.hpp:1185
Tensor Norm() const
Definition Tensor.cpp:1195
Tensor astype(const int &new_type) const
return a new Tensor that cast to different dtype.
Definition Tensor.hpp:1025
const bool & is_contiguous() const
Definition Tensor.hpp:840
Tensor & Conj_()
Definition Tensor.cpp:1180
int device() const
the device-id of the Tensor
Definition Tensor.hpp:736
Tensor get(const std::vector< cytnx::Accessor > &accessors) const
get elements using Accessor (C++ API) / slices (python API)
Definition Tensor.hpp:1152
const std::vector< cytnx_uint64 > & shape() const
the shape of the Tensor
Definition Tensor.hpp:757
An Enhanced tensor specifically designed for physical Tensor network simulation.
Definition UniTensor.hpp:1122
UniTensor to(const int &device) const
Definition UniTensor.hpp:1322
UniTensor & operator*=(const UniTensor &rhs)
Definition UniTensor.hpp:1617
UniTensor relabels(const std::vector< cytnx_int64 > &new_labels) const
Definition UniTensor.hpp:1332
std::vector< Tensor > & get_blocks_(const bool &silent=false)
Definition UniTensor.hpp:1482
UniTensor & operator/=(const UniTensor &rhs)
Definition UniTensor.hpp:1613
T & item()
Definition UniTensor.hpp:1279
void combineBonds(const std::vector< cytnx_int64 > &indicators, const bool &permute_back=true, const bool &by_label=true)
Definition UniTensor.hpp:1526
bool is_contiguous() const
Definition UniTensor.hpp:1306
T get_elem(const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:1702
UniTensor Div(const UniTensor &rhs) const
Definition UniTensor.cpp:32
const Tensor & get_block_(const std::initializer_list< cytnx_int64 > &qnum, const bool &force=false) const
Definition UniTensor.hpp:1466
const std::vector< cytnx_int64 > & labels() const
Definition UniTensor.hpp:1315
Tensor & get_block_(const std::vector< cytnx_int64 > &qnum, const bool &force=false)
Definition UniTensor.hpp:1453
UniTensor & operator+=(const UniTensor &rhs)
Definition UniTensor.hpp:1605
void to_dense_()
Definition UniTensor.hpp:1523
UniTensor reshape(const std::vector< cytnx_int64 > &new_shape, const cytnx_uint64 &rowrank=0)
Definition UniTensor.hpp:1510
std::vector< Tensor > get_blocks() const
Definition UniTensor.hpp:1473
bool is_tag() const
Definition UniTensor.hpp:1308
std::string uten_type_str() const
Definition UniTensor.hpp:1305
UniTensor permute(const std::vector< cytnx_int64 > &mapper, const cytnx_int64 &rowrank=-1, const bool &by_label=false)
Definition UniTensor.hpp:1353
void put_block(const Tensor &in, const std::vector< cytnx_int64 > &qnum, const bool &force)
Definition UniTensor.hpp:1491
static UniTensor Load(const std::string &fname)
Definition UniTensor.cpp:158
UniTensor & tag()
Definition UniTensor.hpp:1684
UniTensor get(const std::vector< Accessor > &accessors) const
Definition UniTensor.hpp:1502
void Save(const std::string &fname) const
Definition UniTensor.cpp:137
UniTensor & operator-=(const Scalar &rhs)
Definition UniTensor.hpp:1625
cytnx_uint64 rowrank() const
Definition UniTensor.hpp:1298
Tensor Norm() const
Definition UniTensor.hpp:1601
void Init(const std::vector< Bond > &bonds, const std::vector< cytnx_int64 > &in_labels={}, const cytnx_int64 &rowrank=-1, const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const bool &is_diag=false)
Definition UniTensor.hpp:1193
UniTensor & Sub_(const Scalar &rhs)
Definition UniTensor.hpp:1582
UniTensor & operator/=(const Scalar &rhs)
Definition UniTensor.hpp:1629
const bool & is_braket_form() const
Definition UniTensor.hpp:1312
void set_elem(const std::vector< cytnx_uint64 > &locator, const T2 &rc)
Definition UniTensor.hpp:1708
UniTensor relabel(const cytnx_int64 &inx, const cytnx_int64 &new_label, const bool &by_label=false) const
Definition UniTensor.hpp:1337
UniTensor(const std::vector< Bond > &bonds, const std::vector< cytnx_int64 > &in_labels={}, const cytnx_int64 &rowrank=-1, const unsigned int &dtype=Type.Double, const int &device=Device.cpu, const bool &is_diag=false)
Initialize a UniTensor.
Definition UniTensor.hpp:1187
std::vector< cytnx_uint64 > shape() const
Definition UniTensor.hpp:1318
UniTensor to_dense()
Definition UniTensor.hpp:1518
void reshape_(const std::vector< cytnx_int64 > &new_shape, const cytnx_uint64 &rowrank=0)
Definition UniTensor.hpp:1515
const Tensor & get_block_(const std::vector< cytnx_int64 > &qnum, const bool &force=false) const
Definition UniTensor.hpp:1463
std::string name() const
Definition UniTensor.hpp:1302
UniTensor & Add_(const Scalar &rhs)
Definition UniTensor.hpp:1572
std::vector< Bond > getTotalQnums(const bool physical=false) const
Definition UniTensor.hpp:1534
Scalar::Sproxy at(const std::vector< cytnx_uint64 > &locator)
Definition UniTensor.hpp:1413
bool same_data(const UniTensor &rhs) const
Definition UniTensor.hpp:1541
UniTensor astype(const unsigned int &dtype) const
Definition UniTensor.hpp:1343
UniTensor Transpose() const
Definition UniTensor.hpp:1652
UniTensor & Dagger_()
Definition UniTensor.hpp:1679
void print_diagram(const bool &bond_info=false)
Definition UniTensor.hpp:1365
std::vector< Bond > & bonds()
Definition UniTensor.hpp:1317
T & at(const std::vector< cytnx_uint64 > &locator)
Definition UniTensor.hpp:1370
UniTensor & truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim, const bool &by_label=false)
Definition UniTensor.hpp:1720
UniTensor & set_label(const cytnx_int64 &idx, const cytnx_int64 &new_label, const bool &by_label=false)
set a new label for bond at the assigned index.
Definition UniTensor.hpp:1238
std::vector< std::vector< cytnx_int64 > > get_blocks_qnums() const
Definition UniTensor.hpp:1537
UniTensor Trace(const cytnx_int64 &a=0, const cytnx_int64 &b=1, const bool &by_label=false) const
Definition UniTensor.hpp:1662
UniTensor contiguous() const
Definition UniTensor.hpp:1357
Tensor get_block(const cytnx_uint64 &idx=0) const
Definition UniTensor.hpp:1429
const T & at(const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:1386
UniTensor & operator*=(const Scalar &rhs)
Definition UniTensor.hpp:1633
void contiguous_()
Definition UniTensor.hpp:1362
UniTensor & set_labels(const std::vector< cytnx_int64 > &new_labels)
change a new label for bond with original label.
Definition UniTensor.hpp:1269
std::vector< Symmetry > syms() const
Definition UniTensor.hpp:1309
UniTensor & Mul_(const UniTensor &rhs)
Definition UniTensor.hpp:1557
void put_block_(Tensor &in, const cytnx_uint64 &idx=0)
Definition UniTensor.hpp:1495
void put_block_(Tensor &in, const std::vector< cytnx_int64 > &qnum, const bool &force)
Definition UniTensor.hpp:1499
bool is_diag() const
Definition UniTensor.hpp:1307
int device() const
Definition UniTensor.hpp:1301
UniTensor & Pow_(const double &p)
Definition UniTensor.cpp:14
void set(const std::vector< Accessor > &accessors, const Tensor &rhs)
Definition UniTensor.hpp:1507
std::string dtype_str() const
Definition UniTensor.hpp:1303
UniTensor & operator+=(const Scalar &rhs)
Definition UniTensor.hpp:1621
UniTensor & Div_(const UniTensor &rhs)
Definition UniTensor.hpp:1567
UniTensor & Div_(const Scalar &rhs)
Definition UniTensor.hpp:1587
cytnx_uint64 rank() const
Definition UniTensor.hpp:1297
void to_(const int &device)
Definition UniTensor.hpp:1321
UniTensor & set_name(const std::string &in)
set the name of the UniTensor
Definition UniTensor.hpp:1224
UniTensor & Add_(const UniTensor &rhs)
Definition UniTensor.hpp:1552
Tensor & get_block_(const std::initializer_list< cytnx_int64 > &qnum, const bool &force=false)
Definition UniTensor.hpp:1456
unsigned int dtype() const
Definition UniTensor.hpp:1299
UniTensor Pow(const double &p) const
Definition UniTensor.cpp:11
UniTensor & Mul_(const Scalar &rhs)
Definition UniTensor.hpp:1577
UniTensor & operator-=(const UniTensor &rhs)
Definition UniTensor.hpp:1609
bool is_blockform() const
Definition UniTensor.hpp:1319
UniTensor Dagger() const
Definition UniTensor.hpp:1673
const std::vector< Tensor > & get_blocks_(const bool &silent=false) const
Definition UniTensor.hpp:1478
bool elem_exists(const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:1696
UniTensor & Sub_(const UniTensor &rhs)
Definition UniTensor.hpp:1562
UniTensor contract(const UniTensor &inR, const bool &mv_elem_self=false, const bool &mv_elem_rhs=false) const
Definition UniTensor.hpp:1529
void put_block(const Tensor &in, const cytnx_uint64 &idx=0)
Definition UniTensor.hpp:1487
const Tensor & get_block_(const cytnx_uint64 &idx=0) const
Definition UniTensor.hpp:1443
UniTensor Mul(const UniTensor &rhs) const
Definition UniTensor.cpp:39
UniTensor & Trace_(const cytnx_int64 &a=0, const cytnx_int64 &b=1, const bool &by_label=false)
Definition UniTensor.hpp:1668
Tensor get_block(const std::vector< cytnx_int64 > &qnum, const bool &force=false) const
Definition UniTensor.hpp:1434
const std::vector< Bond > & bonds() const
Definition UniTensor.hpp:1316
UniTensor & Transpose_()
Definition UniTensor.hpp:1657
UniTensor clone() const
Definition UniTensor.hpp:1327
Scalar::Sproxy item() const
Definition UniTensor.hpp:1288
UniTensor truncate(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim, const bool &by_label=false) const
Definition UniTensor.hpp:1724
void Init(const Tensor &in_tensor, const cytnx_uint64 &rowrank, const bool &is_diag=false)
Definition UniTensor.hpp:1163
std::string device_str() const
Definition UniTensor.hpp:1304
UniTensor Sub(const UniTensor &rhs) const
Definition UniTensor.cpp:25
UniTensor & Conj_()
Definition UniTensor.hpp:1646
cytnx_uint64 Nblocks() const
Definition UniTensor.hpp:1296
UniTensor Conj()
Definition UniTensor.hpp:1640
UniTensor Add(const UniTensor &rhs) const
Definition UniTensor.cpp:18
UniTensor & set_rowrank(const cytnx_uint64 &new_rowrank)
Definition UniTensor.hpp:1273
void permute_(const std::vector< cytnx_int64 > &mapper, const cytnx_int64 &rowrank=-1, const bool &by_label=false)
Definition UniTensor.hpp:1354
UniTensor(const Tensor &in_tensor, const cytnx_uint64 &rowrank, const bool &is_diag=false)
Initialize a UniTensor with cytnx::Tensor.
Definition UniTensor.hpp:1160
Tensor get_block(const std::initializer_list< cytnx_int64 > &qnum, const bool &force=false) const
Definition UniTensor.hpp:1437
const Scalar::Sproxy at(const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:1401
int uten_type() const
Definition UniTensor.hpp:1300
Tensor & get_block_(const cytnx_uint64 &idx=0)
Definition UniTensor.hpp:1448
#define cytnx_warning_msg(is_true, format,...)
Definition cytnx_error.hpp:37
#define cytnx_error_msg(is_true, format,...)
Definition cytnx_error.hpp:18
Tensor Conj(const Tensor &Tin)
Conjugate all the element in Tensor.
Tensor Norm(const Tensor &Tl)
calculate the norm of a tensor.
cytnx::UniTensor Trace(const cytnx::UniTensor &Tin, const cytnx_int64 &a=0, const cytnx_int64 &b=1, const bool &by_label=false)
void Conj_(Tensor &Tin)
inplace perform Conjugate on all the element in Tensor.
Definition Accessor.hpp:12
Device_class Device
Definition Device.cpp:105
double cytnx_double
Definition Type.hpp:20
UniTensorType_class UTenType
Definition UniTensor_base.cpp:21
uint32_t cytnx_uint32
Definition Type.hpp:23
std::complex< double > cytnx_complex128
Definition Type.hpp:30
float cytnx_float
Definition Type.hpp:21
std::ostream & operator<<(std::ostream &os, const Scalar &in)
Definition Scalar.cpp:14
int16_t cytnx_int16
Definition Type.hpp:27
std::complex< float > cytnx_complex64
Definition Type.hpp:29
int32_t cytnx_int32
Definition Type.hpp:26
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.
Definition UniTensor_base.cpp:379
uint16_t cytnx_uint16
Definition Type.hpp:24
void _resolve_CT(std::vector< UniTensor > &TNlist)
Definition UniTensor_base.cpp:383
uint64_t cytnx_uint64
Definition Type.hpp:22
int64_t cytnx_int64
Definition Type.hpp:25
Type_class Type
Definition Type.cpp:143
UniTensor Contracts(const std::vector< UniTensor > &TNs)
Contract multiple UniTensor by tracing the ranks with common labels with pairwise operation.
Definition UniTensor_base.cpp:384