LCP smooth_lcp(const sp_mat & smoother, const vector<sp_mat> & blocks, const mat & Q, const bvec & free_vars){ uint n = smoother.n_rows; assert(n == smoother.n_cols); uint A = blocks.size(); uint N = n*(A+1); assert(A >= 1); assert(size(n,n) == size(blocks.at(0))); assert(size(n,A+1) == size(Q)); assert(N == free_vars.n_elem); // Smooth blocks vector<sp_mat> sblocks = block_rmult(smoother,blocks); // Smooth Q mat sQ = mat(size(Q)); sQ.col(0) = Q.col(0); // State weights unchanged sQ.tail_cols(A) = smoother * Q.tail_cols(A); sp_mat M = build_M(sblocks); vec q = vectorise(sQ); return LCP(M,q,free_vars); }
LCP build_lcp(const Simulator * sim, const Discretizer * disc, double gamma, bool include_oob, bool value_nonneg){ cout << "Generating transition matrices..."<< endl; vector<sp_mat> E_blocks = build_E_blocks(sim,disc, gamma,include_oob); sp_mat M = build_M(E_blocks); vec q = build_q_vec(sim,disc,gamma,include_oob); assert(q.n_elem == M.n_rows); assert(q.n_elem == M.n_cols); if(value_nonneg) return LCP(M,q); uint A = sim->num_actions(); uint N; if(include_oob) N= disc->number_of_all_nodes(); else N= disc->number_of_spatial_nodes(); bvec free_vars = zeros<bvec>((A+1)*N); assert(size(q) == size(free_vars)); free_vars.head(N).fill(1); return LCP(M,q,free_vars); }
//calculate energies for isolated molecules //if we don't know it, calculate it and save the value double calc_e_iso ( system_t * system, double * sqrtKinv, molecule_t * mptr ) { int nstart, nsize; // , curr_dimM; (unused variable) double e_iso; //total vdw energy of isolated molecules struct mtx * Cm_iso; //matrix Cm_isolated double * eigvals; //eigenvalues of Cm_cm molecule_t * molecule_ptr; atom_t * atom_ptr; nstart=nsize=0; //loop through each individual molecule for ( molecule_ptr = system->molecules; molecule_ptr; molecule_ptr=molecule_ptr->next ) { if ( molecule_ptr != mptr ) { //count atoms then skip to next molecule for ( atom_ptr = molecule_ptr->atoms; atom_ptr; atom_ptr = atom_ptr->next ) nstart++; continue; } //now that we've found the molecule of interest, count natoms, and calc energy for ( atom_ptr = molecule_ptr->atoms; atom_ptr; atom_ptr = atom_ptr->next ) nsize++; //build matrix for calculation of vdw energy of isolated molecule Cm_iso = build_M(3*(nsize), 3*nstart, system->A_matrix, sqrtKinv); //diagonalize M and extract eigenvales -> calculate energy eigvals=lapack_diag(Cm_iso,1); //no eigenvectors e_iso=eigen2energy(eigvals,Cm_iso->dim,system->temperature); //free memory free(eigvals); free_mtx(Cm_iso); //convert a.u. -> s^-1 -> K return e_iso * au2invsec * halfHBAR ; } //unmatched molecule return NAN; //we should never get here }
//returns interaction VDW energy double vdw(system_t *system) { int N; // dimC; (unused variable) //number of atoms, number of non-zero rows in C-Matrix double e_total, e_iso; //total energy, isolation energy (atoms @ infinity) double * sqrtKinv; //matrix K^(-1/2); cholesky decomposition of K double ** Am = system->A_matrix; //A_matrix struct mtx * Cm; //C_matrix (we use single pointer due to LAPACK requirements) double * eigvals; //eigenvales double fh_corr, lr_corr; N=system->natoms; //allocate arrays. sqrtKinv is a diagonal matrix. d,e are used for matrix diag. sqrtKinv = getsqrtKinv(system,N); //calculate energy vdw of isolated molecules e_iso = sum_eiso_vdw ( system, sqrtKinv ); //Build the C_Matrix Cm = build_M (3*N, 0, Am, sqrtKinv); //setup and use lapack diagonalization routine dsyev_() eigvals = lapack_diag (Cm, system->polarvdw); //eigenvectors if system->polarvdw == 2 if ( system->polarvdw == 2 ) printevects(Cm); //return energy in inverse time (a.u.) units e_total = eigen2energy(eigvals, Cm->dim, system->temperature); e_total *= au2invsec * halfHBAR; //convert a.u. -> s^-1 -> K //vdw energy comparison if ( system->polarvdw == 3 ) printf("VDW Two-Body | Many Body = %lf | %lf\n", twobody(system),e_total-e_iso); if ( system->feynman_hibbs ) { if ( system->vdw_fh_2be ) fh_corr = fh_vdw_corr_2be(system); //2be method else fh_corr = fh_vdw_corr(system); //mpfd } else fh_corr=0; if ( system->rd_lrc ) lr_corr = lr_vdw_corr(system); else lr_corr=0; //cleanup and return free(sqrtKinv); free(eigvals); free_mtx(Cm); return e_total - e_iso + fh_corr + lr_corr; }
PLCP approx_lcp(const sp_mat & value_basis, const sp_mat & smoother, const vector<sp_mat> & blocks, const mat & Q, const bvec & free_vars){ //Sizing and checking uint n = smoother.n_rows; assert(n == smoother.n_cols); uint A = blocks.size(); assert(A >= 1); assert(size(n,n) == size(blocks.at(0))); assert(size(n,A+1) == size(Q)); uint N = n*(A+1); assert(N == free_vars.n_elem); assert(n == value_basis.n_rows); // Smooth blocks vector<sp_mat> sblocks = block_rmult(smoother,blocks); // Build freebie flow bases for the smoothed problem bool ignore_q = false; vector<sp_mat> flow_bases; vec q; if(ignore_q){ flow_bases = make_freebie_flow_bases_ignore_q(value_basis, sblocks); // Project smoothed costs onto `freebie' basis mat sQ = mat(size(Q)); sQ.col(0) = Q.col(0); for(uint a = 0; a < A; a++){ sp_mat F = flow_bases.at(a); sQ.col(a+1) = F * F.t() * smoother * Q.col(a+1); } q = vectorise(sQ); } else{ mat sQ = mat(size(Q)); sQ.col(0) = Q.col(0); sQ.tail_cols(A) = smoother * Q.tail_cols(A); q = vectorise(sQ); flow_bases = make_freebie_flow_bases(value_basis, sblocks, sQ); } // Build the basis blocks and the basis matrix block_sp_vec p_blocks; p_blocks.reserve(A + 1); p_blocks.push_back(value_basis); p_blocks.insert(p_blocks.end(), flow_bases.begin(), flow_bases.end()); assert((A+1) == p_blocks.size()); sp_mat P = block_diag(p_blocks); // Build LCP matrix M and the U coefficient matrix sp_mat M = build_M(sblocks);// + 1e-10 * speye(N,N); // Regularize sp_mat U = P.t() * M * P * P.t(); return PLCP(P,U,q,free_vars); }