Cytnx v0.7.4
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 //===================================
717 friend class UniTensor; // allow wrapper to access the private elems
718 SparseUniTensor(){
719 this->uten_type_id = UTenType.Sparse;
720 this->_is_tag = true;
721 };
722
723 // virtual functions
724 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);
725 void Init_by_Tensor(const Tensor& in_tensor, const cytnx_uint64 &rowrank, const bool &is_diag=false){
726 cytnx_error_msg(true,"[ERROR][SparseUniTensor] cannot use Init_by_tensor() on a SparseUniTensor.%s","\n");
727 }
728 std::vector<cytnx_uint64> shape() const{
729 std::vector<cytnx_uint64> out(this->_bonds.size());
730 for(cytnx_uint64 i=0;i<out.size();i++){
731 out[i] = this->_bonds[i].dim();
732 }
733 return out;
734 }
735 bool is_blockform() const{return true;}
736 void to_(const int &device){
737 for(cytnx_uint64 i=0;i<this->_blocks.size();i++){
738 this->_blocks[i].to_(device);
739 }
740 };
741 boost::intrusive_ptr<UniTensor_base> to(const int &device){
742 if(this->device() == device){
743 return this;
744 }else{
745 boost::intrusive_ptr<UniTensor_base> out = this->clone();
746 out->to_(device);
747 return out;
748 }
749 };
750 boost::intrusive_ptr<UniTensor_base> clone() const{
751 SparseUniTensor* tmp = this->clone_meta(true,true);
752 tmp->_blocks = vec_clone(this->_blocks);
753 boost::intrusive_ptr<UniTensor_base> out(tmp);
754 return out;
755 };
756
757 bool is_contiguous() const{
758 return this->_contiguous;
759 };
760 void set_rowrank(const cytnx_uint64 &new_rowrank){
761 cytnx_error_msg((new_rowrank < 1) || (new_rowrank>= this->rank()),"[ERROR][SparseUniTensor] rowrank should be [>=1] and [<UniTensor.rank].%s","\n");
762 cytnx_error_msg(new_rowrank >= this->_labels.size(),"[ERROR] rowrank cannot exceed the rank of UniTensor.%s","\n");
763 if(this->_inner_rowrank!= new_rowrank)
764 this->_contiguous = false;
765
766 this->_rowrank = new_rowrank;
767 this->_is_braket_form = this->_update_braket();
768 }
769 boost::intrusive_ptr<UniTensor_base> relabels(const std::vector<cytnx_int64> &new_labels);
770 boost::intrusive_ptr<UniTensor_base> relabel(const cytnx_int64 &inx, const cytnx_int64 &new_label, const bool &by_label=false);
771
772 unsigned int dtype() const{
773 #ifdef UNI_DEBUG
774 cytnx_error_msg(this->_blocks.size()==0,"[ERROR][internal] empty blocks for blockform.%s","\n");
775 #endif
776 return this->_blocks[0].dtype();
777 };
778 int device() const{
779 #ifdef UNI_DEBUG
780 cytnx_error_msg(this->_blocks.size()==0,"[ERROR][internal] empty blocks for blockform.%s","\n");
781 #endif
782 return this->_blocks[0].device();
783 };
784 std::string dtype_str() const{
785 #ifdef UNI_DEBUG
786 cytnx_error_msg(this->_blocks.size()==0,"[ERROR][internal] empty blocks for blockform.%s","\n");
787 #endif
788 return this->_blocks[0].dtype_str();
789 };
790 std::string device_str() const{
791 #ifdef UNI_DEBUG
792 cytnx_error_msg(this->_blocks.size()==0,"[ERROR][internal] empty blocks for blockform.%s","\n");
793 #endif
794 return this->_blocks[0].device_str();
795 };
796
797 boost::intrusive_ptr<UniTensor_base> astype(const unsigned int &dtype) const{
798 SparseUniTensor* tmp = this->clone_meta(true,true);
799 tmp->_blocks.resize(this->_blocks.size());
800 for(cytnx_int64 blk=0;blk<this->_blocks.size();blk++){
801 tmp->_blocks[blk] = this->_blocks[blk].astype(dtype);
802 }
803 boost::intrusive_ptr<UniTensor_base> out(tmp);
804 return out;
805 };
806
807 void permute_(const std::vector<cytnx_int64> &mapper, const cytnx_int64 &rowrank=-1,const bool &by_label=false);
808 boost::intrusive_ptr<UniTensor_base> permute(const std::vector<cytnx_int64> &mapper,const cytnx_int64 &rowrank=-1, const bool &by_label=false);
809 boost::intrusive_ptr<UniTensor_base> contiguous();
810 boost::intrusive_ptr<UniTensor_base> contiguous_(){
811 if(!this->_contiguous){
812 boost::intrusive_ptr<UniTensor_base> titr = this->contiguous();
813 SparseUniTensor *tmp = (SparseUniTensor*)titr.get();
814 tmp->set_meta(this,true,true);
815 this->_blocks = tmp->_blocks;
816
817 }
818 return boost::intrusive_ptr<UniTensor_base>(this);
819
820 }
821 void print_diagram(const bool &bond_info=false);
822
823
824 std::vector<Symmetry> syms() const;
825
826 Tensor get_block(const cytnx_uint64 &idx=0) const{
827 cytnx_error_msg(idx>=this->_blocks.size(),"[ERROR][SparseUniTensor] index out of range%s","\n");
828 if(this->_contiguous){
829 return this->_blocks[idx].clone();
830 }else{
831 cytnx_error_msg(true,"[Developing] get block from a non-contiguous SparseUniTensor is currently not support. Call contiguous()/contiguous_() first.%s","\n");
832 return Tensor();
833 }
834 };
835 cytnx_uint64 Nblocks() const{ return this->_blocks.size();};
836 Tensor get_block(const std::vector<cytnx_int64> &qnum, const bool &force) const{
837 if(!force)
838 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");
839 //std::cout << "get_block" <<std::endl;
840 if(this->_contiguous){
841 //std::cout << "contiguous" << std::endl;
842 //get dtype from qnum:
843 cytnx_int64 idx=-1;
844 for(int i=0;i<this->_blockqnums.size();i++){
845 //for(int j=0;j<this->_blockqnums[i].size();j++)
846 // std::cout << this->_blockqnums[i][j]<< " ";
847 //std::cout << std::endl;
848 if(qnum==this->_blockqnums[i]){idx=i; break;}
849 }
850 cytnx_error_msg(idx<0,"[ERROR][SparseUniTensor] no block with [qnum] exists in the current UniTensor.%s","\n");
851 return this->get_block(idx);
852 }else{
853 cytnx_error_msg(true,"[Developing] get block from a non-contiguous SparseUniTensor is currently not support. Call contiguous()/contiguous_() first.%s","\n");
854 return Tensor();
855 }
856 return Tensor();
857 };
858
859 // return a share view of block, this only work for symm tensor in contiguous form.
860 Tensor& get_block_(const cytnx_uint64 &idx=0){
861 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");
862
863 cytnx_error_msg(idx >= this->_blocks.size(),"[ERROR][SparseUniTensor] index exceed the number of blocks.%s","\n");
864
865 return this->_blocks[idx];
866 }
867 const Tensor& get_block_(const cytnx_uint64 &idx=0) const{
868 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");
869
870 cytnx_error_msg(idx >= this->_blocks.size(),"[ERROR][SparseUniTensor] index exceed the number of blocks.%s","\n");
871
872 return this->_blocks[idx];
873 }
874
875 Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force){
876 if(!force)
877 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");
878
879 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");
880
881 //get dtype from qnum:
882 cytnx_int64 idx=-1;
883 for(int i=0;i<this->_blockqnums.size();i++){
884 if(qnum==this->_blockqnums[i]){idx=i; break;}
885 }
886 cytnx_error_msg(idx<0,"[ERROR][SparseUniTensor] no block with [qnum] exists in the current UniTensor.%s","\n");
887 return this->get_block_(idx);
888 //cytnx_error_msg(true,"[Developing]%s","\n");
889 }
890 const Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force) const{
891 if(!force)
892 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");
893
894 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");
895
896 //get dtype from qnum:
897 cytnx_int64 idx=-1;
898 for(int i=0;i<this->_blockqnums.size();i++){
899 if(qnum==this->_blockqnums[i]){idx=i; break;}
900 }
901 cytnx_error_msg(idx<0,"[ERROR][SparseUniTensor] no block with [qnum] exists in the current UniTensor.%s","\n");
902 return this->get_block_(idx);
903 }
904
905 std::vector<Tensor> get_blocks() const {
906 if(this->_contiguous){
907 return vec_clone(this->_blocks);
908 }else{
909 //cytnx_error_msg(true,"[Developing]%s","\n");
910 boost::intrusive_ptr<UniTensor_base> tmp = this->clone();
911 tmp->contiguous_();
912 SparseUniTensor *ttmp = (SparseUniTensor*)tmp.get();
913 return ttmp->_blocks;
914 }
915 };
916
917 const std::vector<Tensor>& get_blocks_(const bool &silent=false) const {
918 //cout << "[call this]" << endl;
919 if(this->_contiguous){
920 return this->_blocks;
921 }else{
922 //cytnx_error_msg(true,"[Developing]%s","\n");
923 if(!silent)
924 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");
925
926 return this->_blocks;
927 }
928 };
929 std::vector<Tensor>& get_blocks_(const bool &silent=false){
930 //cout << "[call this]" << endl;
931 if(this->_contiguous){
932 return this->_blocks;
933 }else{
934 if(!silent)
935 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");
936
937 return this->_blocks;
938 }
939 };
940
941 bool same_data(const boost::intrusive_ptr<UniTensor_base> &rhs) const{
942 if(rhs->uten_type()!=UTenType.Sparse) return false;
943 if(rhs->get_blocks_(1).size() != this->get_blocks_(1).size()) return false;
944
945 for(int i=0;i<rhs->get_blocks_(1).size();i++)
946 if(this->get_blocks_(1)[i].same_data(rhs->get_blocks_(1)[i])==false) return false;
947
948 return true;
949
950 }
951
952
953
954 void put_block_(Tensor &in,const cytnx_uint64 &idx=0){
955 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");
956
957 cytnx_error_msg(idx>=this->_blocks.size(),"[ERROR][SparseUniTensor] index out of range%s","\n");
958 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);
959 this->_blocks[idx] = in;
960 };
961 void put_block(const Tensor &in,const cytnx_uint64 &idx=0){
962 cytnx_error_msg(idx>=this->_blocks.size(),"[ERROR][SparseUniTensor] index out of range%s","\n");
963 if(this->_contiguous){
964 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);
965 this->_blocks[idx] = in.clone();
966 }else{
967 cytnx_error_msg(true,"[Developing] put block to a non-contiguous SparseUniTensor is currently not support. Call contiguous()/contiguous_() first.%s","\n");
968 }
969 };
970 void put_block(const Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force){
971 if(!force)
972 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");
973
974 //get dtype from qnum:
975 cytnx_int64 idx=-1;
976 for(int i=0;i<this->_blockqnums.size();i++){
977 if(qnum==this->_blockqnums[i]){idx=i; break;}
978 }
979 cytnx_error_msg(idx<0,"[ERROR][SparseUniTensor] no block with [qnum] exists in the current UniTensor.%s","\n");
980 this->put_block(in,idx);
981
982 };
983 void put_block_(Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force){
984 if(!force)
985 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");
986
987 //get dtype from qnum:
988 cytnx_int64 idx=-1;
989 for(int i=0;i<this->_blockqnums.size();i++){
990 if(qnum==this->_blockqnums[i]){idx=i; break;}
991 }
992 cytnx_error_msg(idx<0,"[ERROR][SparseUniTensor] no block with [qnum] exists in the current UniTensor.%s","\n");
993 this->put_block_(in,idx);
994 };
995
996 // this will only work on non-symm tensor (DenseUniTensor)
997 boost::intrusive_ptr<UniTensor_base> get(const std::vector<Accessor> &accessors){
998 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");
999 return nullptr;
1000 }
1001 // this will only work on non-symm tensor (DenseUniTensor)
1002 void set(const std::vector<Accessor> &accessors, const Tensor &rhs){
1003 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");
1004 }
1005 void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0){
1006 cytnx_error_msg(true,"[ERROR] cannot reshape a UniTensor with symmetry.%s","\n");
1007 }
1008 boost::intrusive_ptr<UniTensor_base> reshape(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0){
1009 cytnx_error_msg(true,"[ERROR] cannot reshape a UniTensor with symmetry.%s","\n");
1010 return nullptr;
1011 }
1012 boost::intrusive_ptr<UniTensor_base> to_dense(){
1013 cytnx_error_msg(true,"[ERROR] cannot to_dense a UniTensor with symmetry.%s","\n");
1014 return nullptr;
1015 }
1016 void to_dense_(){
1017 cytnx_error_msg(true,"[ERROR] cannot to_dense_ a UniTensor with symmetry.%s","\n");
1018 }
1019 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &permute_back=true, const bool &by_label=true){
1020 cytnx_error_msg(true,"[Developing]%s","\n");
1021 };
1022 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);
1023 std::vector<Bond> getTotalQnums(const bool &physical=false);
1024 std::vector<std::vector<cytnx_int64> > get_blocks_qnums() const{
1025 return this->_blockqnums;
1026 }
1027 ~SparseUniTensor(){};
1028
1029
1030 // arithmetic
1031 void Add_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1032 void Add_(const Scalar &rhs);
1033
1034 void Mul_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1035 void Mul_(const Scalar &rhs);
1036
1037 void Sub_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1038 void Sub_(const Scalar &rhs);
1039 void lSub_(const Scalar &lhs);
1040
1041 void Div_(const boost::intrusive_ptr<UniTensor_base> &rhs);
1042 void Div_(const Scalar &rhs);
1043 void lDiv_(const Scalar &lhs);
1044
1045
1046 boost::intrusive_ptr<UniTensor_base> Conj(){
1047 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1048 out->Conj_();
1049 return out;
1050 }
1051
1052 void Conj_(){
1053 for(int i=0;i<this->_blocks.size();i++){
1054 this->_blocks[i].Conj_();
1055 }
1056 };
1057 boost::intrusive_ptr<UniTensor_base> Trace(const cytnx_int64 &a, const cytnx_int64 &b, const bool &by_label=false);
1058 void Trace_(const cytnx_int64 &a, const cytnx_int64 &b, const bool &by_label=false){
1059 cytnx_error_msg(true,"[ERROR] Currently SparseUniTensor does not support inplace Trace!, call Trace() instead!%s","\n");
1060 }
1061
1062 void Transpose_();
1063 boost::intrusive_ptr<UniTensor_base> Transpose(){
1064 boost::intrusive_ptr<UniTensor_base> out = this->clone();
1065 out->Transpose_();
1066 return out;
1067 }
1068
1069 boost::intrusive_ptr<UniTensor_base> Dagger(){
1070 boost::intrusive_ptr<UniTensor_base> out = this->Conj();
1071 out->Transpose_();
1072 return out;
1073 }
1074 void Dagger_(){
1075 this->Conj_();
1076 this->Transpose_();
1077 }
1078
1079 Tensor Norm() const;
1080
1081 void tag(){
1082 // no-use!
1083 }
1084
1085 void truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim, const bool &by_label=false);
1086 const Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator) const;
1087 const cytnx_complex128& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex128 &aux) const;
1088 const cytnx_complex64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex64 &aux) const;
1089 const cytnx_double& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux) const;
1090 const cytnx_float& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux) const;
1091 const cytnx_uint64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux) const;
1092 const cytnx_int64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux) const;
1093 const cytnx_uint32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux) const;
1094 const cytnx_int32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux) const;
1095 const cytnx_uint16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux) const;
1096 const cytnx_int16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux) const;
1097
1098
1099 Scalar::Sproxy at_for_sparse(const std::vector<cytnx_uint64> &locator);
1100 cytnx_complex128& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex128 &aux);
1101 cytnx_complex64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_complex64 &aux);
1102 cytnx_double& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_double &aux);
1103 cytnx_float& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_float &aux);
1104 cytnx_uint64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint64 &aux);
1105 cytnx_int64& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int64 &aux);
1106 cytnx_uint32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint32 &aux);
1107 cytnx_int32& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int32 &aux);
1108 cytnx_uint16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_uint16 &aux);
1109 cytnx_int16& at_for_sparse(const std::vector<cytnx_uint64> &locator, const cytnx_int16 &aux);
1110
1111 bool elem_exists(const std::vector<cytnx_uint64> &locator) const;
1112 void _save_dispatch(std::fstream &f) const;
1113 void _load_dispatch(std::fstream &f);
1114 // end virtual func
1115
1116
1117 };
1119
1120 //======================================================================
1121
1124
1125 public:
1126
1128 boost::intrusive_ptr<UniTensor_base> _impl;
1129 UniTensor(): _impl(new UniTensor_base()){};
1130 UniTensor(const UniTensor &rhs){
1131 this->_impl = rhs._impl;
1132 }
1133 UniTensor& operator=(const UniTensor &rhs){
1134 this->_impl = rhs._impl;
1135 return *this;
1136 }
1138
1140
1161 UniTensor(const Tensor &in_tensor, const cytnx_uint64 &rowrank, const bool &is_diag=false): _impl(new UniTensor_base()){
1162 this->Init(in_tensor,rowrank,is_diag);
1163 }
1164 void Init(const Tensor &in_tensor, const cytnx_uint64 &rowrank, const bool &is_diag=false){
1165 boost::intrusive_ptr<UniTensor_base> out(new DenseUniTensor());
1166 out->Init_by_Tensor(in_tensor, rowrank,is_diag);
1167 this->_impl = out;
1168 }
1170
1171
1173
1188 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()){
1189 #ifdef UNI_DEBUG
1190 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");
1191 #endif
1193 }
1194 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){
1195
1196 // checking type:
1197 bool is_sym = false;
1198 for(cytnx_uint64 i=0;i<bonds.size();i++){
1199 //check
1200 if(bonds[i].syms().size() != 0) is_sym = true;
1201 else cytnx_error_msg(is_sym,"[ERROR] cannot have bonds with mixing of symmetry and non-symmetry.%s","\n");
1202 }
1203
1204 // dynamical dispatch:
1205 if(is_sym){
1206 #ifdef UNI_DEBUG
1207 cytnx_warning_msg(true,"[DEBUG] message: entry dispatch: UniTensor: symmetric%s","\n");
1208 #endif
1209 //cytnx_warning_msg(true,"[warning, still developing, some functions will display \"[Developing]\"][SparseUniTensor]%s","\n");
1210 boost::intrusive_ptr<UniTensor_base> out(new SparseUniTensor());
1211 this->_impl = out;
1212 }else{
1213 boost::intrusive_ptr<UniTensor_base> out(new DenseUniTensor());
1214 this->_impl = out;
1215 }
1216 this->_impl->Init(bonds, in_labels, rowrank, dtype, device, is_diag, false);
1217 }
1219
1225 UniTensor& set_name(const std::string &in){
1226 this->_impl->set_name(in);
1227 return *this;
1228 }
1239 UniTensor& set_label(const cytnx_int64 &idx, const cytnx_int64 &new_label, const bool &by_label=false){
1240 this->_impl->set_label(idx,new_label,by_label);
1241 return *this;
1242 }
1243
1254 /*
1255 UniTensor& change_label(const cytnx_int64 &old_lbl, const cytnx_int64 &new_label){
1256 this->_impl->change_label(old_lbl,new_label);
1257 return *this;
1258 }
1259 */
1260
1261
1270 UniTensor& set_labels(const std::vector<cytnx_int64> &new_labels){
1271 this->_impl->set_labels(new_labels);
1272 return *this;
1273 }
1275 this->_impl->set_rowrank(new_rowrank);
1276 return *this;
1277 }
1278
1279 template<class T>
1281
1282 cytnx_error_msg(this->is_blockform(),"[ERROR] cannot use item on UniTensor with Symmetry.\n suggestion: use get_block()/get_blocks() first.%s","\n");
1283
1284 DenseUniTensor* tmp = static_cast<DenseUniTensor*>(this->_impl.get());
1285 return tmp->_block.item<T>();
1286
1287 }
1288
1289 Scalar::Sproxy item() const{
1290 cytnx_error_msg(this->is_blockform(),"[ERROR] cannot use item on UniTensor with Symmetry.\n suggestion: use get_block()/get_blocks() first.%s","\n");
1291
1292 DenseUniTensor* tmp = static_cast<DenseUniTensor*>(this->_impl.get());
1293 return tmp->_block.item();
1294
1295 }
1296
1297 cytnx_uint64 Nblocks() const{return this->_impl->Nblocks();}
1298 cytnx_uint64 rank() const {return this->_impl->rank();}
1299 cytnx_uint64 rowrank() const{return this->_impl->rowrank();}
1300 unsigned int dtype() const{ return this->_impl->dtype(); }
1301 int uten_type() const{ return this->_impl->uten_type();}
1302 int device() const{ return this->_impl->device(); }
1303 std::string name() const { return this->_impl->name();}
1304 std::string dtype_str() const{ return this->_impl->dtype_str();}
1305 std::string device_str() const{ return this->_impl->device_str();}
1306 std::string uten_type_str() const {return this->_impl->uten_type_str();}
1307 bool is_contiguous() const{ return this->_impl->is_contiguous();}
1308 bool is_diag() const{ return this->_impl->is_diag(); }
1309 bool is_tag() const { return this->_impl->is_tag();}
1310 std::vector<Symmetry> syms() const{
1311 return this->_impl->syms();
1312 }
1313 const bool& is_braket_form() const{
1314 return this->_impl->is_braket_form();
1315 }
1316 const std::vector<cytnx_int64>& labels() const{ return this->_impl->labels();}
1317 const std::vector<Bond> &bonds() const {return this->_impl->bonds();}
1318 std::vector<Bond> &bonds() {return this->_impl->bonds();}
1319 std::vector<cytnx_uint64> shape() const{return this->_impl->shape();}
1320 bool is_blockform() const{ return this->_impl->is_blockform();}
1321
1322 void to_(const int &device){this->_impl->to_(device);}
1323 UniTensor to(const int &device) const{
1324 UniTensor out;
1325 out._impl = this->_impl->to(device);
1326 return out;
1327 }
1329 UniTensor out;
1330 out._impl = this->_impl->clone();
1331 return out;
1332 }
1333 UniTensor relabels(const std::vector<cytnx_int64> &new_labels) const{
1334 UniTensor out;
1335 out._impl = this->_impl->relabels(new_labels);
1336 return out;
1337 }
1338 UniTensor relabel(const cytnx_int64 &inx, const cytnx_int64 &new_label, const bool &by_label=false) const{
1339 UniTensor out;
1340 out._impl = this->_impl->relabel(inx,new_label,by_label);
1341 return out;
1342 }
1343
1344 UniTensor astype(const unsigned int &dtype) const{
1345 UniTensor out;
1346 if(this->dtype()==dtype){
1347 out._impl = this->_impl;
1348 }else{
1349 out._impl = this->_impl->astype(dtype);
1350 }
1351 return out;
1352 }
1353
1354 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;}
1355 void permute_(const std::vector<cytnx_int64> &mapper,const cytnx_int64 &rowrank=-1,const bool &by_label=false){
1356 this->_impl->permute_(mapper,rowrank,by_label);
1357 }
1359 UniTensor out;
1360 out._impl = this->_impl->contiguous();
1361 return out;
1362 }
1364 this->_impl = this->_impl->contiguous_();
1365 }
1366 void print_diagram(const bool &bond_info=false){
1367 this->_impl->print_diagram(bond_info);
1368 }
1369
1370 template<class T>
1371 T& at(const std::vector<cytnx_uint64> &locator){
1372 //std::cout << "at " << this->is_blockform() << std::endl;
1373 if(this->uten_type()==UTenType.Sparse){
1374 if(this->_impl->elem_exists(locator)){
1375 T aux;
1376 return this->_impl->at_for_sparse(locator,aux);
1377 }else{
1378 cytnx_error_msg(true,"[ERROR][SparseUniTensor] invalid location. break qnum block.%s","\n");
1379 }
1380 }else{
1381 return this->get_block_().at<T>(locator);
1382 }
1383
1384 }
1385
1386 template<class T>
1387 const T& at(const std::vector<cytnx_uint64> &locator) const{
1388 //std::cout << "at " << this->is_blockform() << std::endl;
1389 if(this->uten_type()==UTenType.Sparse){
1390 if(this->_impl->elem_exists(locator)){
1391 T aux; // [workaround] use aux to dispatch.
1392 return this->_impl->at_for_sparse(locator,aux);
1393 }else{
1394 cytnx_error_msg(true,"[ERROR][SparseUniTensor] invalid location. break qnum block.%s","\n");
1395 }
1396 }else{
1397 return this->get_block_().at<T>(locator);
1398 }
1399
1400 }
1401
1402 const Scalar::Sproxy at(const std::vector<cytnx_uint64> &locator) const{
1403 if(this->uten_type()==UTenType.Sparse){
1404 if(this->_impl->elem_exists(locator)){
1405 return this->_impl->at_for_sparse(locator);
1406 }else{
1407 cytnx_error_msg(true,"[ERROR][SparseUniTensor] invalid location. break qnum block.%s","\n");
1408 }
1409 }else{
1410 return this->get_block_().at(locator);
1411 }
1412 }
1413
1414 Scalar::Sproxy at(const std::vector<cytnx_uint64> &locator){
1415 if(this->uten_type()==UTenType.Sparse){
1416 if(this->_impl->elem_exists(locator)){
1417 return this->_impl->at_for_sparse(locator);
1418 }else{
1419 cytnx_error_msg(true,"[ERROR][SparseUniTensor] invalid location. break qnum block.%s","\n");
1420 }
1421 }else{
1422 return this->get_block_().at(locator);
1423 }
1424 }
1425
1426
1427
1428
1429 // return a clone of block
1431 return this->_impl->get_block(idx);
1432 };
1433 //================================
1434 // return a clone of block
1435 Tensor get_block(const std::vector<cytnx_int64> &qnum, const bool &force=false) const{
1436 return this->_impl->get_block(qnum,force);
1437 }
1438 Tensor get_block(const std::initializer_list<cytnx_int64> &qnum, const bool &force=false) const{
1439 std::vector<cytnx_int64> tmp = qnum;
1440 return get_block(tmp,force);
1441 }
1442 //================================
1443 // this only work for non-symm tensor. return a shared view of block
1444 const Tensor& get_block_(const cytnx_uint64 &idx=0) const{
1445 return this->_impl->get_block_(idx);
1446 }
1447 //================================
1448 // this only work for non-symm tensor. return a shared view of block
1450 return this->_impl->get_block_(idx);
1451 }
1452 //================================
1453 // this only work for non-symm tensor. return a shared view of block
1454 Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force=false){
1455 return this->_impl->get_block_(qnum,force);
1456 }
1457 Tensor& get_block_(const std::initializer_list<cytnx_int64> &qnum,const bool &force=false){
1458 std::vector<cytnx_int64> tmp = qnum;
1459 return get_block_(tmp,force);
1460 }
1461 //================================
1462
1463 // this only work for non-symm tensor. return a shared view of block
1464 const Tensor& get_block_(const std::vector<cytnx_int64> &qnum, const bool &force=false) const{
1465 return this->_impl->get_block_(qnum,force);
1466 }
1467 const Tensor& get_block_(const std::initializer_list<cytnx_int64> &qnum, const bool &force=false) const{
1468 std::vector<cytnx_int64> tmp = qnum;
1469 return this->_impl->get_block_(tmp,force);
1470 }
1471 //================================
1472 // this return a shared view of blocks for non-symm tensor.
1473 // for symmetry tensor, it call contiguous first and return a shared view of blocks. [dev]
1474 std::vector<Tensor> get_blocks() const {
1475 return this->_impl->get_blocks();
1476 }
1477 // this return a shared view of blocks for non-symm tensor.
1478 // for symmetry tensor, it call contiguous first and return a shared view of blocks. [dev]
1479 const std::vector<Tensor>& get_blocks_(const bool &silent=false) const {
1480 return this->_impl->get_blocks_(silent);
1481 }
1482 // for symmetry tensor, it call contiguous first and return a shared view of blocks. [dev]
1483 std::vector<Tensor>& get_blocks_(const bool &silent=false){
1484 return this->_impl->get_blocks_(silent);
1485 }
1486
1487 // the put block will have shared view with the internal block, i.e. non-clone.
1488 void put_block(const Tensor &in,const cytnx_uint64 &idx=0){
1489 this->_impl->put_block(in,idx);
1490 }
1491 // the put block will have shared view with the internal block, i.e. non-clone.
1492 void put_block(const Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force){
1493 this->_impl->put_block(in,qnum, force);
1494 }
1495 // the put block will have shared view with the internal block, i.e. non-clone.
1497 this->_impl->put_block_(in,idx);
1498 }
1499 // the put block will have shared view with the internal block, i.e. non-clone.
1500 void put_block_(Tensor &in, const std::vector<cytnx_int64> &qnum, const bool &force){
1501 this->_impl->put_block_(in,qnum,force);
1502 }
1503 UniTensor get(const std::vector<Accessor> &accessors) const{
1504 UniTensor out;
1505 out._impl = this->_impl->get(accessors);
1506 return out;
1507 }
1508 void set(const std::vector<Accessor> &accessors, const Tensor &rhs){
1509 this->_impl->set(accessors, rhs);
1510 }
1511 UniTensor reshape(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0){
1512 UniTensor out;
1513 out._impl = this->_impl->reshape(new_shape,rowrank);
1514 return out;
1515 }
1516 void reshape_(const std::vector<cytnx_int64> &new_shape, const cytnx_uint64 &rowrank=0){
1517 this->_impl->reshape_(new_shape,rowrank);
1518 }
1520 UniTensor out;
1521 out._impl = this->_impl->to_dense();
1522 return out;
1523 }
1525 this->_impl->to_dense_();
1526 }
1527 void combineBonds(const std::vector<cytnx_int64> &indicators, const bool &permute_back=true, const bool &by_label=true){
1528 this->_impl->combineBonds(indicators,permute_back,by_label);
1529 }
1530 UniTensor contract(const UniTensor &inR, const bool &mv_elem_self=false, const bool &mv_elem_rhs=false) const{
1531 UniTensor out;
1532 out._impl = this->_impl->contract(inR._impl,mv_elem_self,mv_elem_rhs);
1533 return out;
1534 }
1535 std::vector<Bond> getTotalQnums(const bool physical=false) const{
1536 return this->_impl->getTotalQnums(physical);
1537 }
1538 std::vector<std::vector<cytnx_int64> > get_blocks_qnums() const{
1539 return this->_impl->get_blocks_qnums();
1540 }
1541
1542 bool same_data(const UniTensor &rhs) const{
1543
1544 // check same type:
1545 if(this->_impl->uten_type() != rhs._impl->uten_type())
1546 return false;
1547
1548
1549
1550 return this->_impl->same_data(rhs._impl);
1551 }
1552
1554 this->_impl->Add_(rhs._impl);
1555 return *this;
1556 }
1557
1559 this->_impl->Mul_(rhs._impl);
1560 return *this;
1561 }
1562
1564 this->_impl->Sub_(rhs._impl);
1565 return *this;
1566 }
1567
1569 this->_impl->Div_(rhs._impl);
1570 return *this;
1571 }
1572
1574 this->_impl->Add_(rhs);
1575 return *this;
1576 }
1577
1579 this->_impl->Mul_(rhs);
1580 return *this;
1581 }
1582
1584 this->_impl->Sub_(rhs);
1585 return *this;
1586 }
1587
1589 this->_impl->Div_(rhs);
1590 return *this;
1591 }
1592
1593 UniTensor Add(const UniTensor &rhs) const;
1594 UniTensor Add(const Scalar &rhs) const;
1595 UniTensor Mul(const UniTensor &rhs) const;
1596 UniTensor Mul(const Scalar &rhs) const;
1597 UniTensor Div(const UniTensor &rhs) const;
1598 UniTensor Div(const Scalar &rhs) const;
1599 UniTensor Sub(const UniTensor &rhs) const;
1600 UniTensor Sub(const Scalar &rhs) const;
1601
1602 Tensor Norm() const{
1603 return this->_impl->Norm();
1604 };
1605
1607 this->Add_(rhs);
1608 return *this;
1609 }
1611 this->Sub_(rhs);
1612 return *this;
1613 }
1615 this->Div_(rhs);
1616 return *this;
1617 }
1619 this->Mul_(rhs);
1620 return *this;
1621 }
1623 this->Add_(rhs);
1624 return *this;
1625 }
1627 this->Sub_(rhs);
1628 return *this;
1629 }
1631 this->Div_(rhs);
1632 return *this;
1633 }
1635 this->Mul_(rhs);
1636 return *this;
1637 }
1638
1639
1640
1642 UniTensor out;
1643 out._impl = this->_impl->Conj();
1644 return out;
1645 }
1646
1648 this->_impl->Conj_();
1649 return *this;
1650 }
1651
1652
1654 UniTensor out;
1655 out._impl = this->_impl->Transpose();
1656 return out;
1657 }
1659 this->_impl->Transpose_();
1660 return *this;
1661 }
1662
1663 UniTensor Trace(const cytnx_int64 &a=0, const cytnx_int64 &b=1, const bool &by_label=false) const{
1664 UniTensor out;
1665 out._impl = this->_impl->Trace(a,b,by_label);
1666 return out;
1667 }
1668
1669 UniTensor& Trace_(const cytnx_int64 &a=0, const cytnx_int64 &b=1, const bool &by_label=false){
1670 this->_impl->Trace_(a,b,by_label);
1671 return *this;
1672 }
1673
1675 UniTensor out;
1676 out._impl = this->_impl->Dagger();
1677 return out;
1678 }
1679
1681 this->_impl->Dagger_();
1682 return *this;
1683 }
1684
1686 this->_impl->tag();
1687 return *this;
1688 }
1689
1690 UniTensor Pow(const double &p) const;
1691 UniTensor& Pow_(const double &p);
1692
1693
1694
1695
1696
1697 bool elem_exists( const std::vector<cytnx_uint64> &locator) const{
1698 return this->_impl->elem_exists(locator);
1699 }
1700
1701 // [C++: Deprecated soon, use at]
1702 template<class T>
1703 T get_elem(const std::vector<cytnx_uint64> &locator) const{
1704 return this->at<T>(locator);
1705 }
1706
1707 // [C++: Deprecated soon, use at]
1708 template<class T2>
1709 void set_elem(const std::vector<cytnx_uint64> &locator, const T2&rc){
1710 //cytnx_error_msg(true,"[ERROR] invalid type%s","\n");
1711 this->at(locator) = rc;
1712 }
1713
1714
1715
1716 void Save(const std::string &fname) const;
1717 void Save(const char* fname) const;
1718 static UniTensor Load(const std::string &fname);
1719 static UniTensor Load(const char* fname);
1720
1721 UniTensor& truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim, const bool &by_label=false){
1722 this->_impl->truncate_(bond_idx,dim,by_label);
1723 return *this;
1724 }
1725 UniTensor truncate(const cytnx_int64 &bond_idx, const cytnx_uint64& dim, const bool &by_label=false) const{
1726 UniTensor out = this->clone();
1727 out.truncate_(bond_idx,dim,by_label);
1728 return out;
1729 }
1730
1731
1733 void _Load(std::fstream &f);
1734 void _Save(std::fstream &f) const;
1736
1737 };//class UniTensor
1738
1739
1740
1741
1743 std::ostream& operator<<(std::ostream& os, const UniTensor &in);
1745
1756 UniTensor Contract(const UniTensor &inL, const UniTensor &inR, const bool &cacheL=false, const bool &cacheR=false);
1757
1758
1759}
1760#endif
Definition Scalar.hpp:1751
an tensor (multi-dimensional array)
Definition Tensor.hpp:333
void to_(const int &device)
move the current Tensor to the device.
Definition Tensor.hpp:819
Tensor contiguous_()
Make the Tensor contiguous by coalescing the memory (storage), inplacely.
Definition Tensor.hpp:906
unsigned int dtype() const
the dtype-id of the Tensor
Definition Tensor.hpp:712
Tensor contiguous() const
Make the Tensor contiguous by coalescing the memory (storage).
Definition Tensor.hpp:885
T & at(const std::vector< cytnx_uint64 > &locator)
[C++ only] get an element at specific location.
Definition Tensor.hpp:1027
Tensor clone() const
return a clone of the current Tensor.
Definition Tensor.hpp:770
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:1155
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:995
const bool & is_contiguous() const
Definition Tensor.hpp:823
Tensor & Conj_()
Definition Tensor.cpp:1180
int device() const
the device-id of the Tensor
Definition Tensor.hpp:719
Tensor get(const std::vector< cytnx::Accessor > &accessors) const
get elements using Accessor (C++ API) / slices (python API)
Definition Tensor.hpp:1122
const std::vector< cytnx_uint64 > & shape() const
the shape of the Tensor
Definition Tensor.hpp:740
An Enhanced tensor specifically designed for physical Tensor network simulation.
Definition UniTensor.hpp:1123
UniTensor to(const int &device) const
Definition UniTensor.hpp:1323
UniTensor & operator*=(const UniTensor &rhs)
Definition UniTensor.hpp:1618
UniTensor relabels(const std::vector< cytnx_int64 > &new_labels) const
Definition UniTensor.hpp:1333
std::vector< Tensor > & get_blocks_(const bool &silent=false)
Definition UniTensor.hpp:1483
UniTensor & operator/=(const UniTensor &rhs)
Definition UniTensor.hpp:1614
T & item()
Definition UniTensor.hpp:1280
void combineBonds(const std::vector< cytnx_int64 > &indicators, const bool &permute_back=true, const bool &by_label=true)
Definition UniTensor.hpp:1527
bool is_contiguous() const
Definition UniTensor.hpp:1307
T get_elem(const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:1703
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:1467
const std::vector< cytnx_int64 > & labels() const
Definition UniTensor.hpp:1316
Tensor & get_block_(const std::vector< cytnx_int64 > &qnum, const bool &force=false)
Definition UniTensor.hpp:1454
UniTensor & operator+=(const UniTensor &rhs)
Definition UniTensor.hpp:1606
void to_dense_()
Definition UniTensor.hpp:1524
UniTensor reshape(const std::vector< cytnx_int64 > &new_shape, const cytnx_uint64 &rowrank=0)
Definition UniTensor.hpp:1511
std::vector< Tensor > get_blocks() const
Definition UniTensor.hpp:1474
bool is_tag() const
Definition UniTensor.hpp:1309
std::string uten_type_str() const
Definition UniTensor.hpp:1306
UniTensor permute(const std::vector< cytnx_int64 > &mapper, const cytnx_int64 &rowrank=-1, const bool &by_label=false)
Definition UniTensor.hpp:1354
void put_block(const Tensor &in, const std::vector< cytnx_int64 > &qnum, const bool &force)
Definition UniTensor.hpp:1492
static UniTensor Load(const std::string &fname)
Definition UniTensor.cpp:152
UniTensor & tag()
Definition UniTensor.hpp:1685
UniTensor get(const std::vector< Accessor > &accessors) const
Definition UniTensor.hpp:1503
void Save(const std::string &fname) const
Definition UniTensor.cpp:131
UniTensor & operator-=(const Scalar &rhs)
Definition UniTensor.hpp:1626
cytnx_uint64 rowrank() const
Definition UniTensor.hpp:1299
Tensor Norm() const
Definition UniTensor.hpp:1602
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:1194
UniTensor & Sub_(const Scalar &rhs)
Definition UniTensor.hpp:1583
UniTensor & operator/=(const Scalar &rhs)
Definition UniTensor.hpp:1630
const bool & is_braket_form() const
Definition UniTensor.hpp:1313
void set_elem(const std::vector< cytnx_uint64 > &locator, const T2 &rc)
Definition UniTensor.hpp:1709
UniTensor relabel(const cytnx_int64 &inx, const cytnx_int64 &new_label, const bool &by_label=false) const
Definition UniTensor.hpp:1338
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:1188
std::vector< cytnx_uint64 > shape() const
Definition UniTensor.hpp:1319
UniTensor to_dense()
Definition UniTensor.hpp:1519
void reshape_(const std::vector< cytnx_int64 > &new_shape, const cytnx_uint64 &rowrank=0)
Definition UniTensor.hpp:1516
const Tensor & get_block_(const std::vector< cytnx_int64 > &qnum, const bool &force=false) const
Definition UniTensor.hpp:1464
std::string name() const
Definition UniTensor.hpp:1303
UniTensor & Add_(const Scalar &rhs)
Definition UniTensor.hpp:1573
std::vector< Bond > getTotalQnums(const bool physical=false) const
Definition UniTensor.hpp:1535
Scalar::Sproxy at(const std::vector< cytnx_uint64 > &locator)
Definition UniTensor.hpp:1414
bool same_data(const UniTensor &rhs) const
Definition UniTensor.hpp:1542
UniTensor astype(const unsigned int &dtype) const
Definition UniTensor.hpp:1344
UniTensor Transpose() const
Definition UniTensor.hpp:1653
UniTensor & Dagger_()
Definition UniTensor.hpp:1680
void print_diagram(const bool &bond_info=false)
Definition UniTensor.hpp:1366
std::vector< Bond > & bonds()
Definition UniTensor.hpp:1318
T & at(const std::vector< cytnx_uint64 > &locator)
Definition UniTensor.hpp:1371
UniTensor & truncate_(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim, const bool &by_label=false)
Definition UniTensor.hpp:1721
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:1239
std::vector< std::vector< cytnx_int64 > > get_blocks_qnums() const
Definition UniTensor.hpp:1538
UniTensor Trace(const cytnx_int64 &a=0, const cytnx_int64 &b=1, const bool &by_label=false) const
Definition UniTensor.hpp:1663
UniTensor contiguous() const
Definition UniTensor.hpp:1358
Tensor get_block(const cytnx_uint64 &idx=0) const
Definition UniTensor.hpp:1430
const T & at(const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:1387
UniTensor & operator*=(const Scalar &rhs)
Definition UniTensor.hpp:1634
void contiguous_()
Definition UniTensor.hpp:1363
UniTensor & set_labels(const std::vector< cytnx_int64 > &new_labels)
change a new label for bond with original label.
Definition UniTensor.hpp:1270
std::vector< Symmetry > syms() const
Definition UniTensor.hpp:1310
UniTensor & Mul_(const UniTensor &rhs)
Definition UniTensor.hpp:1558
void put_block_(Tensor &in, const cytnx_uint64 &idx=0)
Definition UniTensor.hpp:1496
void put_block_(Tensor &in, const std::vector< cytnx_int64 > &qnum, const bool &force)
Definition UniTensor.hpp:1500
bool is_diag() const
Definition UniTensor.hpp:1308
int device() const
Definition UniTensor.hpp:1302
UniTensor & Pow_(const double &p)
Definition UniTensor.cpp:14
void set(const std::vector< Accessor > &accessors, const Tensor &rhs)
Definition UniTensor.hpp:1508
std::string dtype_str() const
Definition UniTensor.hpp:1304
UniTensor & operator+=(const Scalar &rhs)
Definition UniTensor.hpp:1622
UniTensor & Div_(const UniTensor &rhs)
Definition UniTensor.hpp:1568
UniTensor & Div_(const Scalar &rhs)
Definition UniTensor.hpp:1588
cytnx_uint64 rank() const
Definition UniTensor.hpp:1298
void to_(const int &device)
Definition UniTensor.hpp:1322
UniTensor & set_name(const std::string &in)
set the name of the UniTensor
Definition UniTensor.hpp:1225
UniTensor & Add_(const UniTensor &rhs)
Definition UniTensor.hpp:1553
Tensor & get_block_(const std::initializer_list< cytnx_int64 > &qnum, const bool &force=false)
Definition UniTensor.hpp:1457
unsigned int dtype() const
Definition UniTensor.hpp:1300
UniTensor Pow(const double &p) const
Definition UniTensor.cpp:11
UniTensor & Mul_(const Scalar &rhs)
Definition UniTensor.hpp:1578
UniTensor & operator-=(const UniTensor &rhs)
Definition UniTensor.hpp:1610
bool is_blockform() const
Definition UniTensor.hpp:1320
UniTensor Dagger() const
Definition UniTensor.hpp:1674
const std::vector< Tensor > & get_blocks_(const bool &silent=false) const
Definition UniTensor.hpp:1479
bool elem_exists(const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:1697
UniTensor & Sub_(const UniTensor &rhs)
Definition UniTensor.hpp:1563
UniTensor contract(const UniTensor &inR, const bool &mv_elem_self=false, const bool &mv_elem_rhs=false) const
Definition UniTensor.hpp:1530
void put_block(const Tensor &in, const cytnx_uint64 &idx=0)
Definition UniTensor.hpp:1488
const Tensor & get_block_(const cytnx_uint64 &idx=0) const
Definition UniTensor.hpp:1444
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:1669
Tensor get_block(const std::vector< cytnx_int64 > &qnum, const bool &force=false) const
Definition UniTensor.hpp:1435
const std::vector< Bond > & bonds() const
Definition UniTensor.hpp:1317
UniTensor & Transpose_()
Definition UniTensor.hpp:1658
UniTensor clone() const
Definition UniTensor.hpp:1328
Scalar::Sproxy item() const
Definition UniTensor.hpp:1289
UniTensor truncate(const cytnx_int64 &bond_idx, const cytnx_uint64 &dim, const bool &by_label=false) const
Definition UniTensor.hpp:1725
void Init(const Tensor &in_tensor, const cytnx_uint64 &rowrank, const bool &is_diag=false)
Definition UniTensor.hpp:1164
std::string device_str() const
Definition UniTensor.hpp:1305
UniTensor Sub(const UniTensor &rhs) const
Definition UniTensor.cpp:25
UniTensor & Conj_()
Definition UniTensor.hpp:1647
cytnx_uint64 Nblocks() const
Definition UniTensor.hpp:1297
UniTensor Conj()
Definition UniTensor.hpp:1641
UniTensor Add(const UniTensor &rhs) const
Definition UniTensor.cpp:18
UniTensor & set_rowrank(const cytnx_uint64 &new_rowrank)
Definition UniTensor.hpp:1274
void permute_(const std::vector< cytnx_int64 > &mapper, const cytnx_int64 &rowrank=-1, const bool &by_label=false)
Definition UniTensor.hpp:1355
UniTensor(const Tensor &in_tensor, const cytnx_uint64 &rowrank, const bool &is_diag=false)
Initialize a UniTensor with cytnx::Tensor.
Definition UniTensor.hpp:1161
Tensor get_block(const std::initializer_list< cytnx_int64 > &qnum, const bool &force=false) const
Definition UniTensor.hpp:1438
const Scalar::Sproxy at(const std::vector< cytnx_uint64 > &locator) const
Definition UniTensor.hpp:1402
int uten_type() const
Definition UniTensor.hpp:1301
Tensor & get_block_(const cytnx_uint64 &idx=0)
Definition UniTensor.hpp:1449
#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
uint64_t cytnx_uint64
Definition Type.hpp:22
int64_t cytnx_int64
Definition Type.hpp:25
Type_class Type
Definition Type.cpp:137