51 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++)
53 const int linsize =
_index->getNORB(irrep);
54 const int size = linsize * linsize;
58 unitary[irrep].reset(
new double[size]);
60 memset(
unitary[irrep].
get(), 0,
sizeof(
double)*size);
61 for (
int cnt=0; cnt<linsize; cnt++)
62 unitary[irrep][cnt*(1+linsize)] = 1.0;
73 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++)
75 const int linsize =
_index->getNORB(irrep);
76 const int size = linsize * linsize;
77 unitary[irrep].reset(
new double[size]);
78 std::memcpy(
unitary[irrep].
get(), unit.
unitary[irrep].get(), size*
sizeof(double));
84 _index = std::move(unit._index);
85 unitary = std::move(unit.unitary);
95 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++)
97 const int linsize =
_index->getNORB(irrep);
98 const int size = linsize * linsize;
99 unitary[irrep].reset(
new double[size]);
100 std::memcpy(
unitary[irrep].
get(), unit.
unitary[irrep].get(), size*
sizeof(double));
108 _index = std::move(unit._index);
109 unitary = std::move(unit.unitary);
117 i -=
_index->getNstart(irrep);
118 j -=
_index->getNstart(irrep);
119 const int linsize =
_index->getNORB(irrep);
121 const double cos = std::cos(angle);
122 const double sin = std::sin(angle);
124 for(
int l=0;l<linsize;l++)
126 const double tmpi =
unitary[irrep][i+l*linsize];
127 const double tmpj =
unitary[irrep][j+l*linsize];
129 unitary[irrep][i+l*linsize] = cos*tmpi-sin*tmpj;
130 unitary[irrep][j+l*linsize] = cos*tmpj+sin*tmpi;
136 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++)
138 const int linsize =
_index->getNORB(irrep);
139 const int size = linsize * linsize;
140 memset(
unitary[irrep].
get(), 0,
sizeof(
double)*size);
141 for (
int cnt=0; cnt<linsize; cnt++)
142 unitary[irrep][cnt*(1+linsize)] = 1.0;
160 for (
int irrep=0;irrep<
_index->getNirreps();irrep++)
162 auto linsize =
_index->getNORB(irrep);
163 const auto size = linsize * linsize;
169 unitary[irrep][0] = std::exp(xblock[0]);
180 dgemm_(¬rans,¬rans,&linsize,&linsize,&linsize,&alpha,xblock,&linsize,xblock,&linsize,&beta,B,&linsize);
185 int lwork = 3*linsize - 1;
186 double *eigB = &temp1[size];
187 double *work = temp2;
190 dsyev_(&jobz,&uplo,&linsize,B,&linsize,eigB,work,&lwork,&info);
193 std::cerr <<
"dsyev in updateUnitary failed. info = " << info << std::endl;
195 double *expC = temp2;
196 double *tmp = &temp2[size];
197 memset(expC, 0,
sizeof(
double)*size);
198 for(
int i=0;i<linsize/2;i++)
200 const double lambda = std::sqrt(-1*eigB[i*2]);
201 const double cos = std::cos(lambda);
202 const double sin = std::sin(lambda);
204 expC[idx*(linsize+1)] = cos;
205 expC[(idx+1)*(linsize+1)] = cos;
206 expC[idx+(idx+1)*linsize] = sin;
207 expC[idx+1+idx*linsize] = -sin;
216 dgemm_(¬rans,&trans,&linsize,&linsize,&linsize,&alpha,expC,&linsize,B,&linsize,&beta,tmp,&linsize);
224 dgemm_(¬rans,¬rans,&linsize,&linsize,&linsize,&alpha,B,&linsize,tmp,&linsize,&beta,res,&linsize);
228 dgemm_(¬rans,¬rans,&linsize,&linsize,&linsize,&alpha,res,&linsize,
unitary[irrep].
get(),&linsize,&beta,B,&linsize);
229 std::memcpy(
unitary[irrep].
get(), B,
sizeof(
double)*size);
238 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++)
240 int linsize =
_index->getNORB(irrep);
241 int size = linsize * linsize;
247 double * xblock = temp1;
248 double * Bmat = temp1 + size;
249 double * work1 = temp1 + 2*size;
250 double * work2 = temp1 + 3*size;
252 double * workLARGE = temp2;
253 int lworkLARGE = 4*size;
262 dgemm_(¬r,¬r,&linsize,&linsize,&linsize,&alpha,xblock,&linsize,xblock,&linsize,&beta,Bmat,&linsize);
269 dsyev_(&jobz, &uplo, &linsize, Bmat, &linsize, work1, workLARGE, &lworkLARGE, &info);
273 cerr <<
"A problem occured in the diagonalisation of the anti-symmetric matrix squared to generated the unitary -> exp(X).";
278 dgemm_(¬r,¬r,&linsize,&linsize,&linsize,&alpha,xblock,&linsize,Bmat,&linsize,&beta,work1,&linsize);
280 dgemm_(&trans,¬r,&linsize,&linsize,&linsize,&alpha,Bmat,&linsize,work1,&linsize,&beta,work2,&linsize);
284 cout <<
" UnitaryMatrix::updateUnitary : Lambdas of irrep block " << irrep <<
" : " << endl;
285 for (
int cnt=0; cnt<linsize/2; cnt++)
287 cout <<
" block = [ " << work2[2*cnt + linsize*2*cnt] <<
" , " << work2[2*cnt + linsize*(2*cnt+1)] <<
" ] " << endl;
288 cout <<
" [ " << work2[2*cnt+1 + linsize*2*cnt] <<
" , " << work2[2*cnt+1 + linsize*(2*cnt+1)] <<
" ] " << endl;
293 for (
int cnt=0; cnt<linsize/2; cnt++)
294 work1[cnt] = 0.5*( work2[2*cnt + linsize*(2*cnt+1)] - work2[2*cnt+1 + linsize*(2*cnt)] );
298 for (
int cnt=0; cnt<linsize/2; cnt++)
300 work2[2*cnt + linsize*(2*cnt+1)] -= work1[cnt];
301 work2[2*cnt+1 + linsize*(2*cnt)] += work1[cnt];
305 double RMSdeviation =
ddot_(&size, work2, &inc, work2, &inc);
306 RMSdeviation = sqrt(RMSdeviation);
308 cout <<
" UnitaryMatrix::updateUnitary : RMSdeviation of irrep block " << irrep <<
" (should be 0.0) = " << RMSdeviation << endl;
313 memset(work2, 0,
sizeof(
double)*size);
314 for (
int cnt=0; cnt<linsize/2; cnt++)
316 double cosine = cos(work1[cnt]);
317 double sine = sin(work1[cnt]);
318 work2[2*cnt + linsize*(2*cnt )] = cosine;
319 work2[2*cnt+1 + linsize*(2*cnt+1)] = cosine;
320 work2[2*cnt + linsize*(2*cnt+1)] = sine;
321 work2[2*cnt+1 + linsize*(2*cnt )] = - sine;
325 for (
int cnt=2*(linsize/2); cnt<linsize; cnt++)
326 work2[cnt*(linsize + 1)] = 1.0;
329 dgemm_(¬r,¬r,&linsize,&linsize,&linsize,&alpha,Bmat,&linsize,work2,&linsize,&beta,work1,&linsize);
330 dgemm_(¬r,&trans,&linsize,&linsize,&linsize,&alpha,work1,&linsize,Bmat,&linsize,&beta,work2,&linsize);
337 dgemm_(¬r,¬r,&linsize,&linsize,&linsize,&alpha,work2,&linsize,
unitary[irrep].
get(),&linsize,&beta,work1,&linsize);
352 const int linsize =
_index->getNORB(irrep);
355 for (
int cnt=0; cnt<irrep; cnt++)
357 int linsizeCNT =
_index->getNORB(cnt);
358 jump += linsizeCNT * (linsizeCNT-1) / 2;
361 for (
int row=0; row<linsize; row++)
363 result[ row + linsize * row ] = 0;
365 for (
int col=row+1; col<linsize; col++)
367 result[ row + linsize * col ] = Xelem[ jump + row + col*(col-1)/2 ];
368 result[ col + linsize * row ] = - Xelem[ jump + row + col*(col-1)/2 ];
375 assert(0 &&
"Not manually checked everything here!");
377 int nOrbDMRG =
_index->getL();
378 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++){
380 const int NDMRG =
_index->getNORB(irrep);
383 int rotationlinsize = NDMRG;
384 int blocklinsize =
_index->getNORB(irrep);
386 double * temp1 = work;
387 double * temp2 = work + rotationlinsize*blocklinsize;
388 double * BlockEigen = eigenvecs + passed * (nOrbDMRG + 1);
390 for (
int row = 0; row<rotationlinsize; row++){
391 for (
int col = 0; col<blocklinsize; col++){
392 temp1[row + rotationlinsize*col] =
unitary[irrep][ row + blocklinsize * col ];
400 dgemm_(&tran,¬r,&rotationlinsize,&blocklinsize,&rotationlinsize,&alpha,BlockEigen,&nOrbDMRG,temp1,&rotationlinsize,&beta,temp2,&rotationlinsize);
402 for (
int row = 0; row<rotationlinsize; row++){
403 for (
int col = 0; col<blocklinsize; col++){
404 unitary[irrep][ row + blocklinsize * col ] = temp2[row + rotationlinsize*col];
424 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++)
426 int linsize =
_index->getNORB(irrep);
431 dgemm_(&tran,¬r,&linsize,&linsize,&linsize,&alpha,
unitary[irrep].
get(),&linsize,
unitary[irrep].
get(),&linsize,&beta,work,&linsize);
433 for(
int i=0;i<linsize;i++)
434 work[(linsize+1)*i] -= 1;
437 int n = linsize*linsize;
438 double norm =
ddot_(&n, work, &inc, work, &inc);
442 cout <<
"Two-norm of unitary[" << irrep <<
"]^(dagger) * unitary[" << irrep <<
"] - I = " << norm << endl;
443 if( fabs(norm) > 1e-13)
445 cerr <<
"WARNING: we reseted the unitary because we lost unitarity." << endl;
454 hid_t file_id = H5Fcreate(savename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
455 hid_t group_id = H5Gcreate(file_id,
"/Data", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
457 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++)
459 int norb =
_index->getNORB(irrep);
463 std::stringstream irrepname;
464 irrepname <<
"irrep_" << irrep;
466 hsize_t dimarray = norb * norb;
467 hid_t dataspace_id = H5Screate_simple(1, &dimarray, NULL);
468 hid_t dataset_id = H5Dcreate(group_id, irrepname.str().c_str(), H5T_IEEE_F64LE, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
469 H5Dwrite(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
unitary[irrep].
get());
471 H5Dclose(dataset_id);
472 H5Sclose(dataspace_id);
482 hid_t file_id = H5Fopen(unitname.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT);
483 hid_t group_id = H5Gopen(file_id,
"/Data", H5P_DEFAULT);
485 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++)
487 int norb =
_index->getNORB(irrep);
491 std::stringstream irrepname;
492 irrepname <<
"irrep_" << irrep;
494 hid_t dataset_id = H5Dopen(group_id, irrepname.str().c_str(), H5P_DEFAULT);
495 H5Dread(dataset_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT,
unitary[irrep].
get());
497 H5Dclose(dataset_id);
507 assert(0 &&
"Don't use this!");
508 std::stringstream temp;
509 temp <<
"rm " << name;
510 int info = system(temp.str().c_str());
511 cout <<
"Info on CASSCF::Unitary rm call to system: " << info << endl;
517 for(
int irrep = 0 ; irrep <
_index->getNirreps() ; irrep ++)
519 cout <<
"#irrep : " << irrep << endl;
520 int linsize =
_index->getNORB(irrep);
521 for(
int j = 0 ; j < linsize ; j ++)
523 for(
int l = 0 ; l < linsize ; l ++)
524 cout <<
unitary[irrep][j + linsize* l] <<
" ";
538 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++)
540 const int linsize =
_index->getNORB(irrep);
541 const int size = linsize * linsize;
542 MPI_Bcast(
unitary[irrep].
get(), size, MPI_DOUBLE, orig, MPI_COMM_WORLD);
549 return _index->getNirreps();
554 std::random_device rd;
555 auto mt = std::mt19937_64(rd());
556 std::uniform_real_distribution<double> dist_angles(-1000, 1000);
561 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++)
563 const int linsize =
_index->getNORB(irrep);
564 const int size = linsize * linsize;
565 for(
int j=0;j<size;j++)
566 unitary[irrep][j] = dist_angles(mt);
573 for (
int irrep=0; irrep<
_index->getNirreps(); irrep++)
575 const int linsize =
_index->getNORB(irrep);
576 for(
int i=0;i<linsize;i++)
578 unitary[irrep][i+i*linsize] = 0;
579 for(
int j=i+1;j<linsize;j++)
double ddot_(int *n, double *x, int *incx, double *y, int *incy)
void build_skew_symm_x(const int irrep, double *xblock, const double *Xelem) const
UnitaryMatrix & operator=(const UnitaryMatrix &unit)
void dcopy_(int *n, double *x, int *incx, double *y, int *incy)
void rotate_active_space_vectors(double *eigenvecs, double *work)
Rotate the unitary matrix to the NO eigenbasis.
void jacobi_rotation(int irrep, int i, int j, double angle)
Implements a simple jacobi rotation of the i, and j th orbital.
void print_unitary() const
void dgemm_(char *transA, char *transB, int *m, int *n, int *k, double *alpha, double *A, int *lda, double *B, int *ldb, double *beta, double *C, int *ldc)
void dsyev_(char *jobz, char *uplo, int *n, double *A, int *lda, double *W, double *work, int *lwork, int *info)
unsigned int x_linearlength
unsigned int getNumVariablesX() const
Get the number of variables in the x-parametrization of the unitary update.
void CheckDeviationFromUnitary(double *work) const
Calculate the two-norm of U^T*U - I.
std::unique_ptr< OptIndex > _index
UnitaryMatrix(const OptIndex &)
Constructor.
std::vector< std::unique_ptr< double[]> > unitary
void deleteStoredUnitary(std::string name) const
Delete the stored unitary (on disk)
void saveU(std::string savename) const
Save the unitary to disk.
const bool Orbopt_debugPrint
void loadU(std::string loadname)
Load the unitary from disk.
double * getBlock(const int irrep) const
Get the unitary rotation for block irrep.
void updateUnitary(double *workmem1, double *workmem2, double *vector, const bool multiply)
Update the unitary transformation based on the new vector and the previous unitary.
void make_skew_symmetric()
void reset_unitary()
Resets the unitary matrix.