25 #ifndef _chemistry_qc_lmp2_contractpartdef_h
26 #define _chemistry_qc_lmp2_contractpartdef_h
34 inline void operator()(
double &res,
double val) { res += val; }
39 inline void operator()(
double &res,
double val) { res /= val; }
42 template <
int N,
int N2>
46 std::vector<int> &fixed, std::vector<int> &fixed_values,
47 std::vector<int> &external, std::vector<int> &external_on_other,
48 bool same_external_index_order_required)
50 for (
int i=0; i<array.array().nindex(); i++) {
51 bool found =
false, isfixed =
false;
55 if (i != fixed.size()) {
56 throw std::runtime_error(
"fixed indices must be first");
59 fixed_values.push_back(array.index(i).
value());
63 for (
int j=0; j<
other.array().nindex(); j++) {
65 external.push_back(i);
66 external_on_other.push_back(j);
71 if (isfixed && !found) {
72 if (!array.array().index(i).all_size_one()) {
73 throw std::runtime_error(
"nonexternal fixed indices require blocksize == 1");
76 if (!found && !isfixed) {
77 throw std::runtime_error(
"index not found");
81 if (same_external_index_order_required) {
82 for (
int i=1; i<external_on_other.size(); i++) {
83 if (external_on_other[i] < external_on_other[i-1]) {
85 std::runtime_error(
"external indices must be in same order");
92 template <
int N2,
class Op>
93 void ContractPart<N>::do_binary_op_with_fixed_indices(
94 double f,
const ContractPart<N2> &o,
bool initarray, Op &op)
const
96 double alpha = f * o.factor() / factor();
98 array_.allocate_blocks();
103 sma2::Array<N> &C = array_;
104 std::vector<int> C_fixed, C_fixed_values;
105 std::vector<int> C_external, C_external_on_A;
106 get_all_indices(*
this, o, C_fixed, C_fixed_values, C_external,
107 C_external_on_A,
false);
110 const sma2::Array<N2> &A = o.array();
111 std::vector<int> A_fixed, A_fixed_values;
112 std::vector<int> A_external, A_external_on_C;
113 get_all_indices(o, *
this, A_fixed, A_fixed_values, A_external,
114 A_external_on_C,
false);
118 sma2::BlockInfo<N2> A_bi;
119 for (
int i=0; i<A_fixed.size(); i++) {
123 A_bi.block(A_fixed[i]) = A_fixed_values[i];
127 sma2::IndexList A_external_il(A_external);
128 sma2::IndexList A_external_on_C_il(A_external_on_C);
132 sma2::BlockInfo<N> first_C_bi;
133 sma2::BlockInfo<N> last_C_bi;
134 for (
int i=0; i<N; i++) {
135 first_C_bi.block(i) = 0;
136 last_C_bi.block(i) = C.index(i).nindex();
138 for (
int i=0; i<C_fixed.size(); i++) {
139 first_C_bi.block(C_fixed[i]) = C_fixed_values[i];
140 last_C_bi.block(C_fixed[i]) = C_fixed_values[i];
142 typename sma2::Array<N>::blockmap_t::const_iterator
143 C_iter_begin = C.blockmap().lower_bound(first_C_bi);
144 typename sma2::Array<N>::blockmap_t::const_iterator
145 C_iter_fence = C.blockmap().upper_bound(last_C_bi);
147 bool same_index_order = A_external_on_C_il.is_identity();
164 for (
typename sma2::Array<N>::blockmap_t::const_iterator C_iter = C_iter_begin;
165 C_iter != C_iter_fence;
167 const sma2::BlockInfo<N> &C_bi = C_iter->first;
169 A_bi.assign_blocks(A_external_il, C_bi, A_external_on_C_il);
173 typename sma2::Array<N2>::blockmap_t::const_iterator
174 A_iter = A.blockmap().find(A_bi);
175 if (A_iter == A.blockmap().end())
continue;
176 double *C_data = C_iter->second;
177 double *A_data = A_iter->second;
178 int sz = C.block_size(C_bi);
180 if (same_index_order) {
181 for (
int i=0; i<sz; i++) {
182 op(C_data[i], alpha * A_data[i]);
186 BlockIter<N> cbiter(C.indices(),C_bi);
188 for (cbiter.start(); cbiter.ready(); cbiter++,coff++) {
189 int aoff = cbiter.subset_offset(A_external_on_C_il);
190 op(C_data[coff], alpha * A_data[aoff]);
195 if (!skip_bounds_update_) C.compute_bounds();
200 void ContractPart<N>::do_binary_op(
double f,
const ContractPart<N> &o,
201 bool initarray, Op &op)
const {
203 for (
int i=0; i<N; i++) {
204 if (index(i).has_value()) nvalue++;
206 for (
int i=0; i<N; i++) {
207 if (o.index(i).has_value()) nvalue++;
210 do_binary_op_with_fixed_indices(f,o,initarray,op);
214 std::vector<int> indvec;
215 for (
int i=0; i<N; i++) {
216 for (
int j=0; j<N; j++) {
217 if (o.index(i) == index(j)) {
223 if (indvec.size() != N) {
224 throw std::invalid_argument(
"sma::ContractPart: nindex != N");
226 double alpha = f * o.factor() / factor();
227 IndexList indlist(indvec);
229 array_.allocate_blocks();
233 for (
int i=0; i<N; i++)
234 array_.set_index(indlist.i(i),o.array().index(i));
236 binary_op(array_, alpha, o.array(), indlist, skip_bounds_update_, op);
240 template <
int Nl,
int Nr>
241 void ContractPart<N>::doprod(
double f,
const ContractProd<Nl,Nr> &o,
242 bool initarray)
const {
243 std::vector<int> extCAv, extCBv, extAv, extBv, intAv, intBv;
244 std::vector<int> fixextCAv, fixextCBv, fixextAv, fixextBv;
246 for (
int i=0; i<N; i++) {
247 for (
int j=0; j<Nl; j++) {
248 if (indices_[i].symbolically_equivalent(o.l.index(j))) {
251 if (o.l.index(j).has_value() != indices_[i].has_value()
252 || (indices_[i].has_value()
253 && indices_[i].value() != o.l.index(j).value())) {
254 throw std::runtime_error(
"ContractPart<N>::doprod: two equivalent indices do not have the same value");
256 if (indices_[i].has_value()) {
257 fixextAv.push_back(j);
258 fixextCAv.push_back(i);
264 for (
int i=0; i<N; i++) {
265 for (
int j=0; j<Nr; j++) {
266 if (indices_[i].symbolically_equivalent(o.r.index(j))) {
269 if (o.r.index(j).has_value() != indices_[i].has_value()
270 || (indices_[i].has_value()
271 && indices_[i].value() != o.r.index(j).value())) {
272 throw std::runtime_error(
"ContractPart::doprod: two equivalent indices do not have the same value");
274 if (indices_[i].has_value()) {
275 fixextBv.push_back(j);
276 fixextCBv.push_back(i);
282 for (
int i=0; i<Nl; i++) {
283 for (
int j=0; j<Nr; j++) {
284 if (o.l.index(i).symbolically_equivalent(o.r.index(j))) {
291 IndexList extCA(extCAv), extCB(extCBv);
292 IndexList intA(intAv), extA(extAv);
293 IndexList intB(intBv), extB(extBv);
294 IndexList fixextCA(fixextCAv), fixextCB(fixextCBv);
295 IndexList fixextA(fixextAv), fixextB(fixextBv);
298 std::vector<int> fixCv, fixAv, fixBv;
299 std::vector<sma2::bi_t> fixvalCv, fixvalAv, fixvalBv;
300 for (
int i=0; i<N; i++) {
301 if (indices_[i].has_value()) {
303 fixvalCv.push_back(indices_[i].value());
306 for (
int i=0; i<Nl; i++) {
307 if (o.l.index(i).has_value()) {
309 fixvalAv.push_back(o.l.index(i).value());
312 for (
int i=0; i<Nr; i++) {
313 if (o.r.index(i).has_value()) {
315 fixvalBv.push_back(o.r.index(i).value());
319 IndexList fixC(fixCv), fixA(fixAv), fixB(fixBv);
320 BlockInfo<N> fixvalC(fixvalCv);
321 BlockInfo<Nl> fixvalA(fixvalAv);
322 BlockInfo<Nr> fixvalB(fixvalBv);
324 double ABfactor = f * o.l.factor() * o.r.factor() / factor();
327 array_.allocate_blocks();
329 for (
int i=0; i<extCA.n(); i++) {
330 array_.set_index(extCA.i(i), o.l.array().index(extA.i(i)));
332 for (
int i=0; i<extCB.n(); i++) {
333 array_.set_index(extCB.i(i), o.r.array().index(extB.i(i)));
337 contract(array_, extCA, extCB, fixextCA, fixextCB, fixC, fixvalC,
338 o.l.array(), extA, fixextA, intA, fixA, fixvalA, o.l.clear_after_use(),
339 o.r.array(), extB, fixextB, intB, fixB, fixvalB, o.r.clear_after_use(),
340 ABfactor, initarray, o.regtimer);
344 template <
int Nl,
int Nr>
345 void ContractPart<N>::dounion(
const ContractProd<Nl,Nr> &o)
const {
346 std::vector<int> extCAv, extCBv, extAv, extBv, intAv, intBv;
348 for (
int i=0; i<N; i++) {
349 for (
int j=0; j<Nl; j++) {
350 if (indices_[i].symbolically_equivalent(o.l.index(j))) {
357 for (
int i=0; i<N; i++) {
358 for (
int j=0; j<Nr; j++) {
359 if (indices_[i].symbolically_equivalent(o.r.index(j))) {
366 for (
int i=0; i<Nl; i++) {
367 for (
int j=0; j<Nr; j++) {
368 if (o.l.index(i).symbolically_equivalent(o.r.index(j))) {
375 IndexList extCA(extCAv), extCB(extCBv);
376 IndexList intA(intAv), extA(extAv);
377 IndexList intB(intBv), extB(extBv);
379 std::vector<int> fixCv, fixAv, fixBv;
380 std::vector<sma2::bi_t> fixvalCv, fixvalAv, fixvalBv;
381 for (
int i=0; i<N; i++) {
382 if (indices_[i].has_value()) {
383 if (fixCv.size() != i)
384 throw std::invalid_argument(
"fixed indices must be first (in C)");
386 fixvalCv.push_back(indices_[i].value());
387 if (fixvalCv[i] >= array().index(i).nblock()) {
388 throw std::invalid_argument(
"fixed index out of range (in C)");
392 for (
int i=0; i<Nl; i++) {
393 if (o.l.index(i).has_value()) {
394 if (fixAv.size() != i)
395 throw std::invalid_argument(
"fixed indices must be first (in A)");
397 fixvalAv.push_back(o.l.index(i).value());
398 if (fixvalAv[i] >= o.l.array().index(i).nblock()) {
399 throw std::invalid_argument(
"fixed index out of range (in A)");
403 for (
int i=0; i<Nr; i++) {
404 if (o.r.index(i).has_value()) {
406 fixvalBv.push_back(o.r.index(i).value());
407 if (fixvalBv[i] >= o.r.array().index(i).nblock()) {
408 throw std::invalid_argument(
"fixed index out of range (in B)");
413 IndexList fixC(fixCv), fixA(fixAv), fixB(fixBv);
414 BlockInfo<N> fixvalC(fixvalCv);
415 BlockInfo<Nl> fixvalA(fixvalAv);
416 BlockInfo<Nr> fixvalB(fixvalBv);
418 bool bad_index =
false;
419 for (
int i=0; i<extCA.n(); i++) {
420 if (array_.index(extCA.i(i)) != o.l.array().index(extA.i(i)))
424 for (
int i=0; i<extCB.n(); i++) {
425 if (array_.index(extCB.i(i)) != o.r.array().index(extB.i(i)))
430 throw std::invalid_argument(
"sma2::contract_union: C range inconsistency");
433 contract_union(array_, extCA, extCB, fixC, fixvalC,
434 o.l.array(), extA, intA, fixA, fixvalA,
435 o.r.array(), extB, intB, fixB, fixvalB);
439 ContractPart<N>::ContractPart(Array<N> &array):
440 array_(array), factor_(1.0), clear_after_use_(false),
441 skip_bounds_update_(false) {
442 if (N != 0)
throw std::invalid_argument(
"sma::ContractPart: N != 0");
446 ContractPart<N>::ContractPart(Array<N> &array,
448 array_(array), factor_(1.0), clear_after_use_(false),
449 skip_bounds_update_(false) {
450 if (N != 1)
throw std::invalid_argument(
"sma::ContractPart: N != 1");
451 indices_.push_back(i1);
455 ContractPart<N>::ContractPart(Array<N> &array,
458 array_(array), factor_(1.0), clear_after_use_(false),
459 skip_bounds_update_(false) {
460 if (N != 2)
throw std::invalid_argument(
"sma::ContractPart: N != 2");
461 indices_.push_back(i1);
462 indices_.push_back(i2);
466 ContractPart<N>::ContractPart(Array<N> &array,
470 array_(array), factor_(1.0), clear_after_use_(false),
471 skip_bounds_update_(false) {
472 if (N != 3)
throw std::invalid_argument(
"sma::ContractPart: N != 3");
473 indices_.push_back(i1);
474 indices_.push_back(i2);
475 indices_.push_back(i3);
479 ContractPart<N>::ContractPart(Array<N> &array,
484 array_(array), factor_(1.0), clear_after_use_(false),
485 skip_bounds_update_(false) {
486 if (N != 4)
throw std::invalid_argument(
"sma::ContractPart: N != 4");
487 indices_.push_back(i1);
488 indices_.push_back(i2);
489 indices_.push_back(i3);
490 indices_.push_back(i4);
494 ContractPart<N>::ContractPart(Array<N> &array,
500 array_(array), factor_(1.0), clear_after_use_(false),
501 skip_bounds_update_(false) {
502 if (N != 5)
throw std::invalid_argument(
"sma::ContractPart: N != 5");
503 indices_.push_back(i1);
504 indices_.push_back(i2);
505 indices_.push_back(i3);
506 indices_.push_back(i4);
507 indices_.push_back(i5);
511 ContractPart<N>::ContractPart(Array<N> &array,
518 array_(array), factor_(1.0), clear_after_use_(false),
519 skip_bounds_update_(false) {
520 if (N != 6)
throw std::invalid_argument(
"sma::ContractPart: N != 6");
521 indices_.push_back(i1);
522 indices_.push_back(i2);
523 indices_.push_back(i3);
524 indices_.push_back(i4);
525 indices_.push_back(i5);
526 indices_.push_back(i6);
530 void ContractPart<N>::apply_factor(
double f)
536 double ContractPart<N>::factor()
const
542 Array<N>& ContractPart<N>::array()
const {
return array_; }
545 const Index &ContractPart<N>::index(
int i)
const {
return indices_[i]; }
553 std::vector<int> C_fixed, C_fixed_values;
554 std::vector<int> C_external, C_external_on_A;
555 get_all_indices(*
this, o, C_fixed, C_fixed_values, C_external,
556 C_external_on_A,
false);
560 std::vector<int> A_fixed, A_fixed_values;
561 std::vector<int> A_external, A_external_on_C;
562 get_all_indices(o, *
this, A_fixed, A_fixed_values, A_external,
563 A_external_on_C,
false);
565 for (
int i=0; i<A_external.size(); i++) {
566 if (A.
index(A_external[i]) != C.
index(A_external_on_C[i])) {
567 throw std::invalid_argument(
"|=: Range conflict between A and C");
574 for (
int i=0; i<C_fixed.size(); i++) {
575 C_bi.block(C_fixed[i]) = C_fixed_values[i];
586 for (
int i=0; i<N2; i++) {
587 first_A_bi.block(i) = 0;
590 for (
int i=0; i<A_fixed.size(); i++) {
591 first_A_bi.block(A_fixed[i]) = A_fixed_values[i];
592 last_A_bi.block(A_fixed[i]) = A_fixed_values[i];
595 A_iter_begin = A.
blockmap().lower_bound(first_A_bi);
597 A_iter_fence = A.
blockmap().upper_bound(last_A_bi);
601 A_iter != A_iter_fence;
613 do_binary_op(1.0, o,
true, op);
618 void ContractPart<N>::operator = (
const ContractPart<N2> &o)
const {
620 do_binary_op_with_fixed_indices(1.0,o,
true,op);
624 void ContractPart<N>::operator += (
const ContractPart<N> &o)
const {
626 do_binary_op(1.0, o,
false, op);
631 void ContractPart<N>::operator += (
const ContractPart<N2> &o)
const {
633 do_binary_op_with_fixed_indices(1.0,o,
false,op);
637 void ContractPart<N>::operator /= (
const ContractPart<N> &o)
const {
639 do_binary_op(1.0, o,
false, op);
644 void ContractPart<N>::operator /= (
const ContractPart<N2> &o)
const {
646 do_binary_op_with_fixed_indices(1.0,o,
false,op);
650 void ContractPart<N>::operator -= (
const ContractPart<N> &o)
const {
652 do_binary_op(-1.0, o,
false, op);
656 template <
int Nl,
int Nr>
657 void ContractPart<N>::operator = (
const ContractProd<Nl,Nr> &o)
const {
658 doprod(1.0, o,
true);
662 template <
int Nl,
int Nr>
663 void ContractPart<N>::operator += (
const ContractProd<Nl,Nr> &o)
const{
664 doprod(1.0, o,
false);
668 template <
int Nl,
int Nr>
669 void ContractPart<N>::operator -= (
const ContractProd<Nl,Nr> &o)
const{
670 doprod(-1.0, o,
false);
674 template <
int Nl,
int Nr>
680 ContractPart<N> operator *(
double f,
const ContractPart<N> &o)
682 ContractPart<N> result(o);
683 result.apply_factor(f);
691 result.clear_after_use_ =
true;
699 result.skip_bounds_update_ =
true;
707 if (indices_.size() != N) {
708 throw std::runtime_error(
"ContractPart::value: indices_.size() != N");
711 for (
int i=0; i<N; i++) {
712 if (!indices_[i].has_value()) {
713 throw std::runtime_error(
"ContractPart::value: requires fixed indices");
715 bi.block(i) = indices_[i].value();
717 size_t blocksize = array_.block_size(bi);
719 throw std::runtime_error(
"ContractPart::value: blocksize must be 1");
723 if (biter == array_.
blockmap().end()) {
726 if (biter->second == 0) {
727 throw std::runtime_error(
"ContractPart::value: array not allocated");
729 return *biter->second;