/***************************************************************************
 *  PSIMRCC : Copyright (C) 2007 by Francesco Evangelista and Andrew Simmonett
 *  frank@ccc.uga.edu   andysim@ccc.uga.edu
 *  A multireference coupled cluster code
 ***************************************************************************/

#include "blas.h"
#include "mrcc.h"

extern FILE* outfile;

namespace psi{ namespace psimrcc{

void CCMRCC::add_matrices()
{
  // O^4
  blas->add_Matrix("<[oo]:[oo]>");
  blas->add_Matrix("<[oo]|[oo]>");

  // O^3V  
  blas->add_Matrix("([oo]:[ov])");
  blas->add_Matrix("([oo]|[ov])");
  blas->add_Matrix("<[ooo]:[v]>");
  blas->add_Matrix("<[ooo]|[v]>");
  blas->add_Matrix("<[o]:[oov]>");
  blas->add_Matrix("<[o]|[oov]>");
  blas->add_Matrix("<[o]:[voo]>");
  blas->add_Matrix("<[o]|[voo]>");
  blas->add_Matrix("<[o]|[ovo]>");
  blas->add_Matrix("<[o]:[ovo]>");

  // O^2V^2
  blas->add_Matrix("<[o>o]:[v>v]>");
  blas->add_Matrix("<[oo]:[vv]>");
  blas->add_Matrix("<[oo]|[vv]>");
  blas->add_Matrix("<[v]:[voo]>");
  blas->add_Matrix("<[v]|[voo]>");
  blas->add_Matrix("<[o]:[ovv]>");
  blas->add_Matrix("<[o]|[ovv]>");
  blas->add_Matrix("([ov]|[ov])");
  blas->add_Matrix("([ov]:[ov])");
  blas->add_Matrix("([ov]|[vo])");
  blas->add_Matrix("([ov]:[vo])");
  blas->add_Matrix("<[ov]:[vo]>");
  blas->add_Matrix("<[ov]|[vo]>");
  blas->add_Matrix("<[vo]|[ov]>");
  blas->add_Matrix("<[vo]|[vo]>");
  blas->add_Matrix("<[ov]:[ov]>");
  blas->add_Matrix("<[ov]|[ov]>");

  // OV^3
  blas->add_Matrix("([ov]|[vv])");
/*
  mrcc_f_int.cc:  blas->append("F_ae[v][v]{c} += #12# ([ov]|[vv]) 1@1 t1[ov]{c} ");
  mrcc_f_int.cc:  blas->append("F_ae[v][v]{o} += #12# ([ov]|[vv]) 1@1 t1[OV]{o} ");
  mrcc_f_int.cc:  blas->append("F_AE[V][V]{o} += #12# ([ov]|[vv]) 1@1 t1[ov]{o} ");
*/

  blas->add_Matrix("([ov]:[vv])");  // Used only three times in ccmrcc_f_int.cpp
/*
  mrcc_f_int.cc:  blas->append("F_ae[v][v]{c} += #12# ([ov]:[vv]) 1@1 t1[ov]{c}");
  mrcc_f_int.cc:  blas->append("F_ae[v][v]{o} += #12# ([ov]:[vv]) 1@1 t1[ov]{o}");
  mrcc_f_int.cc:  blas->append("F_AE[V][V]{o} += #12# ([ov]:[vv]) 1@1 t1[OV]{o}");
*/

  blas->add_Matrix("<[vo]|[vv]>");
/*
  mrcc_z_int.cc:  blas->append("Z_ijam[oov][o]{u} = #1234#   tau[oo][vv]{u} 2@2 <[vo]|[vv]>");
  mrcc_z_int.cc:  blas->append("Z_iJaM[oOv][O]{u} = #1234#   tau[oO][vV]{u} 2@2 <[vo]|[vv]>");
  mrcc_z_int.cc:  blas->append("Z_iJAm[oOV][o]{u} = #1234# - tau[oO][Vv]{u} 2@2 <[vo]|[vv]>");
  mrcc_z_int.cc:  blas->append("Z_IJAM[OOV][O]{u} = #1234#   tau[OO][VV]{u} 2@2 <[vo]|[vv]>");
*/

  blas->add_Matrix("<[v]|[ovv]>");
/*
  mrcc_t1_amps.cc:  blas->append("t1_eqns[o][v]{c} +=     t2[o][OvV]{c} 2@2 <[v]|[ovv]>");
  mrcc_t1_amps.cc:  blas->append("t1_eqns[o][v]{o} +=     t2[o][OvV]{o} 2@2 <[v]|[ovv]>");
  mrcc_t1_amps.cc:  blas->append("t1_eqns[O][V]{o} +=     t2[O][oVv]{o} 2@2 <[v]|[ovv]>");
  mrcc_t2_amps.cc:  blas->append("t2_eqns[oO][vV]{c} += #1234#   t1[o][v]{c} 2@1 <[v]|[ovv]>");
  mrcc_t2_amps.cc:  blas->append("t2_eqns[oO][vV]{c} += #2143#   t1[O][V]{c} 2@1 <[v]|[ovv]>");
  mrcc_t2_amps.cc:  blas->append("t2_eqns[oO][vV]{o} += #1234#   t1[o][v]{o} 2@1 <[v]|[ovv]>");
  mrcc_t2_amps.cc:  blas->append("t2_eqns[oO][vV]{o} += #2143#   t1[O][V]{o} 2@1 <[v]|[ovv]>");
  mrcc_w_int.cc:  blas->append("W_jbme[ov][ov]{u} += #3241#   <[v]|[ovv]> 1@2 t1[o][v]{u}");
  mrcc_w_int.cc:  blas->append("W_JBme[OV][ov]{o} += #3241# <[v]|[ovv]> 1@2 t1[O][V]{o}");
  mrcc_w_int.cc:  blas->append("W_jbME[ov][OV]{u} += #3241# <[v]|[ovv]> 1@2 t1[o][v]{u}");
  mrcc_w_int.cc:  blas->append("W_JBME[OV][OV]{o} += #3241#   <[v]|[ovv]> 1@2 t1[O][V]{o}");
  mrcc_w_t3_int.cc:   blas->solve("W'_aBIc[vVO][v]{u}  = #4312# <[v]|[ovv]>");
  mrcc_w_t3_int.cc:   blas->solve("W'_AbiC[Vvo][V]{u}  = #4312# <[v]|[ovv]>");
  mrcc_w_t3_int.cc:  blas->solve("W_aIbC[v][OvV]{u}  = <[v]|[ovv]>");
  mrcc_w_t3_int.cc:  blas->solve("W_AiBc[V][oVv]{u}  = <[v]|[ovv]>");
*/

  blas->add_Matrix("<[v]:[ovv]>");  // Used several times
/*
  mrcc_t1_amps.cc:  blas->append("t1_eqns[o][v]{c} += 1/2 t2[o][ovv]{c} 2@2 <[v]:[ovv]>");
  mrcc_t1_amps.cc:  blas->append("t1_eqns[o][v]{o} += 1/2 t2[o][ovv]{o} 2@2 <[v]:[ovv]>");
  mrcc_t1_amps.cc:  blas->append("t1_eqns[O][V]{o} += 1/2 t2[O][OVV]{o} 2@2 <[v]:[ovv]>");
  mrcc_t2_amps.cc:    blas->append("t2_eqns[oo][vv]{c} += #1234#   t1[o][v]{c} 2@1 <[v]:[ovv]>");
  mrcc_t2_amps.cc:    blas->append("t2_eqns[oo][vv]{c} += #2134# - t1[o][v]{c} 2@1 <[v]:[ovv]>");
  mrcc_t2_amps.cc:  blas->append("t2_eqns[oo][vv]{o} += #1234#   t1[o][v]{o} 2@1 <[v]:[ovv]>");
  mrcc_t2_amps.cc:  blas->append("t2_eqns[oo][vv]{o} += #2134# - t1[o][v]{o} 2@1 <[v]:[ovv]>");
  mrcc_t2_amps.cc:  blas->append("t2_eqns[OO][VV]{o} += #1234#   t1[O][V]{o} 2@1 <[v]:[ovv]>");
  mrcc_t2_amps.cc:  blas->append("t2_eqns[OO][VV]{o} += #2134# - t1[O][V]{o} 2@1 <[v]:[ovv]>");
  mrcc_w_t3_int.cc:   blas->solve("W'_abic[vvo][v]{u}  = #4312# <[v]:[ovv]>");
  mrcc_w_t3_int.cc:   blas->solve("W'_ABIC[VVO][V]{u}  = #4312# <[v]:[ovv]>");
  mrcc_w_t3_int.cc:  blas->solve("W_aibc[v][ovv]{u}  = <[v]:[ovv]>");
  mrcc_w_t3_int.cc:  blas->solve("W_AIBC[V][OVV]{u}  = <[v]:[ovv]>");
*/

  blas->add_Matrix("([vvo]|[v])");  // Used four times in ccmrcc_w_int.cpp
/*
  mrcc_w_int.cc:  blas->append("W_jbme[ov][ov]{u} += #2431# - ([vvo]|[v]) 2@2 t1[o][v]{u}");
  mrcc_w_int.cc:  blas->append("W_jBmE[oV][oV]{u} += #2431# - ([vvo]|[v]) 2@2 t1[o][v]{u}");
  mrcc_w_int.cc:  blas->append("W_JbMe[Ov][Ov]{o} += #2431# - ([vvo]|[v]) 2@2 t1[O][V]{o}");
  mrcc_w_int.cc:  blas->append("W_JBME[OV][OV]{o} += #2431# - ([vvo]|[v]) 2@2 t1[O][V]{o}");
*/

//  blas->add_Matrix("<[ov]|[vv]>");  // Eliminated
//  blas->add_Matrix("<[ovv]:[v]>");  // Eliminated
//  blas->add_Matrix("<[vo]:[vv]>");  // Eliminated : used originally two times in mrcc_z_int.cpp

  // V^4
  blas->add_Matrix("<[v>v]:[v>v]>");
  blas->add_Matrix("<[vv]|[v>=v]>");

  // Fock Matrix
  blas->add_Matrix("fock[o][o]{u}");
  blas->add_Matrix("fock[o][v]{u}");
  blas->add_Matrix("fock[v][v]{u}");
  blas->add_Matrix("fock[O][O]{u}");
  blas->add_Matrix("fock[O][V]{u}");
  blas->add_Matrix("fock[V][V]{u}");

  blas->add_Matrix("fock[v][o]{u}");
  blas->add_Matrix("fock[V][O]{u}");

  blas->add_Matrix("fock[oo]{u}");
  blas->add_Matrix("fock[ov]{u}");
  blas->add_Matrix("fock[vv]{u}");
  blas->add_Matrix("fock[OO]{u}");
  blas->add_Matrix("fock[OV]{u}");
  blas->add_Matrix("fock[VV]{u}");

  blas->add_Matrix("fock[vo]{u}");
  blas->add_Matrix("fock[VO]{u}");

  // Denominators
  blas->add_Matrix("d1[ov]{u}");
  blas->add_Matrix("d1[OV]{u}");
  blas->add_Matrix("d1[o][v]{u}");
  blas->add_Matrix("d1[O][V]{u}");
  blas->add_Matrix("d2[oo][vv]{u}");
  blas->add_Matrix("d2[oO][vV]{u}");
  blas->add_Matrix("d2[OO][VV]{u}");
  blas->add_Matrix("d2[o>o][v>v]{u}");
  blas->add_Matrix("d2[oO][vV]{u}");
  blas->add_Matrix("d2[O>O][V>V]{u}");
  // Shifted denominators
  blas->add_Matrix("d'1[o][v]{u}");
  blas->add_Matrix("d'1[O][V]{u}");
  blas->add_Matrix("d'2[oo][vv]{u}");
  blas->add_Matrix("d'2[oO][vV]{u}");
  blas->add_Matrix("d'2[OO][VV]{u}");

  // Amplitudes
  blas->add_Matrix("t1[ov]{u}");
  blas->add_Matrix("t1[OV]{u}");
  blas->add_Matrix("t1[o][v]{u}");
  blas->add_Matrix("t1[O][V]{u}");
  blas->add_Matrix("t2[oO][vV]{u}");
  blas->add_Matrix("t2[oo][vv]{u}");
  blas->add_Matrix("t2[OO][VV]{u}");

  blas->add_Matrix("t2[ov][OV]{u}");
  blas->add_Matrix("t2[ov][ov]{u}");
  blas->add_Matrix("t2[OV][OV]{u}");
  blas->add_Matrix("t2[oV][Ov]{u}");

  blas->add_Matrix("t2[o][ovv]{u}");
  blas->add_Matrix("t2[o][OvV]{u}");
  blas->add_Matrix("t2[O][oVv]{u}");
  blas->add_Matrix("t2[O][OVV]{u}");

  blas->add_Matrix("t2[v][voo]{u}");
  blas->add_Matrix("t2[v][VoO]{u}");
  blas->add_Matrix("t2[V][vOo]{u}");
  blas->add_Matrix("t2[V][VOO]{u}");

  blas->add_Matrix("t2[oo][v>v]{u}");
  blas->add_Matrix("t2[OO][V>V]{u}");
  blas->add_Matrix("t2[oO][v>=V]{u}");
  blas->add_Matrix("t2[oO][V>=v]{u}");

  blas->add_Matrix("t1_delta[o][v]{u}");
  blas->add_Matrix("t1_delta[O][V]{u}");
  blas->add_Matrix("t2_delta[oo][vv]{u}");
  blas->add_Matrix("t2_delta[oO][vV]{u}");
  blas->add_Matrix("t2_delta[OO][VV]{u}");

  // Similarity transformed Hamiltonian
  blas->add_Matrix("t1_eqns[o][v]{u}");
  blas->add_Matrix("t1_eqns[O][V]{u}");
  blas->add_Matrix("t2_eqns[oo][vv]{u}");
  blas->add_Matrix("t2_eqns[oO][vV]{u}");
  blas->add_Matrix("t2_eqns[OO][VV]{u}");
  blas->add_Matrix("t2_eqns[oo][v>v]{u}");
  blas->add_Matrix("t2_eqns[OO][V>V]{u}");

  // F intermediates
  blas->add_Matrix("F_ae[v][v]{u}");
  blas->add_Matrix("F_AE[V][V]{u}");
  blas->add_Matrix("F_mi[o][o]{u}");
  blas->add_Matrix("F_MI[O][O]{u}");

  // W intermediates
  blas->add_Matrix("W_mnij[oo][oo]{u}");
  blas->add_Matrix("W_mNiJ[oO][oO]{u}");
  blas->add_Matrix("W_MNIJ[OO][OO]{u}");

  blas->add_Matrix("W_jbme[ov][ov]{u}");
  blas->add_Matrix("W_jbME[ov][OV]{u}");
  blas->add_Matrix("W_JBme[OV][ov]{o}");
  blas->add_Matrix("W_JBME[OV][OV]{o}");
  blas->add_Matrix("W_jBmE[oV][oV]{u}");
  blas->add_Matrix("W_JbMe[Ov][Ov]{o}");

  blas->add_Matrix("t1_old[o][v]{u}");
  blas->add_Matrix("t1_old[O][V]{u}");
  blas->add_Matrix("t2_old[oO][vV]{u}");
  blas->add_Matrix("t2_old[oo][vv]{u}");
  blas->add_Matrix("t2_old[OO][VV]{u}");

  // MRPT2 Intermediates
  blas->add_Matrix("ERef{u}");
  blas->add_Matrix("EPT2{u}");
  blas->add_Matrix("Eaa{u}");
  blas->add_Matrix("Ebb{u}");
  blas->add_Matrix("Eaaaa{u}");
  blas->add_Matrix("Eabab{u}");
  blas->add_Matrix("Ebbbb{u}");

  blas->add_Matrix("t1[a][v]{u}");
  blas->add_Matrix("t1_eqns[a][a]{u}");
  blas->add_Matrix("t1_eqns[A][A]{o}");
  blas->add_Matrix("fock[a][a]{u}");
  blas->add_Matrix("fock[a][v]{u}");
  blas->add_Matrix("fock[A][A]{o}");

  blas->add_Matrix("factor_mk{u}");
  blas->add_Matrix("neg_factor_mk{u}");

//   blas->add_Matrix("F_ae[v][v]{u}");
//   blas->add_Matrix("F_AE[V][V]{o}");
// 
//   blas->add_Matrix("F_mi[o][o]{u}");
//   blas->add_Matrix("F_MI[O][O]{o}");

  blas->add_Matrix("F_me[o][v]{u}");
  blas->add_Matrix("F_me[ov]{u}");

  blas->add_Matrix("F_ME[O][V]{o}");
  blas->add_Matrix("F_ME[OV]{o}");

  blas->add_Matrix("F'_ae[v][v]{u}");
  blas->add_Matrix("F'_AE[V][V]{o}");

  blas->add_Matrix("F'_mi[o][o]{u}");
  blas->add_Matrix("F'_MI[O][O]{o}");

  blas->add_Matrix("tau[oo][vv]{u}");
  blas->add_Matrix("tau[oO][vV]{u}");
  blas->add_Matrix("tau[oO][Vv]{u}");
  blas->add_Matrix("tau[OO][VV]{u}");

  // Tau tilde intermediates (8 * O^2V^2)
  blas->add_Matrix("tau2[v][voo]{u}");
  blas->add_Matrix("tau2[o][ovv]{u}");

  blas->add_Matrix("tau2[V][VOO]{u}");
  blas->add_Matrix("tau2[O][OVV]{u}");

  blas->add_Matrix("tau2[v][VoO]{u}");
  blas->add_Matrix("tau2[o][OvV]{u}");

  blas->add_Matrix("tau2[V][vOo]{u}");
  blas->add_Matrix("tau2[O][oVv]{u}");

  blas->add_Matrix("tau[oo][v>v]{u}");
  blas->add_Matrix("tau[OO][V>V]{u}");
  blas->add_Matrix("tau[oO][v>=V]{u}");
  blas->add_Matrix("tau[oO][V>=v]{u}");
  
  // Amplitudes
  blas->add_Matrix("ECCSD{u}");
  blas->add_Matrix("t1_norm{u}");
  blas->add_Matrix("||Delta_t1||{u}");
  blas->add_Matrix("||Delta_t2||{u}");


  blas->add_Matrix("t1t1_iame[ov][ov]{u}");
  blas->add_Matrix("t1t1_iAMe[oV][Ov]{u}");
  blas->add_Matrix("t1t1_IAME[OV][OV]{u}");

  blas->add_Matrix("tau3[ov][ov]{u}");
  blas->add_Matrix("tau3[OV][OV]{u}");
  blas->add_Matrix("tau3[oV][vO]{u}");
  blas->add_Matrix("tau3[Ov][Vo]{u}");

  blas->add_Matrix("Z_ijam[oov][o]{u}");
  blas->add_Matrix("Z_iJaM[oOv][O]{u}");
  blas->add_Matrix("Z_iJAm[oOV][o]{u}");
  blas->add_Matrix("Z_IJAM[OOV][O]{u}");

  // Mukherjee Terms
  blas->add_Matrix("Mk1[o][v]{u}");
  blas->add_Matrix("Mk1[O][V]{u}");
  blas->add_Matrix("Mk2[oo][vv]{u}");
  blas->add_Matrix("Mk2[oO][vV]{u}");
  blas->add_Matrix("Mk2[OO][VV]{u}");

  // Triples
  if(triples_type >= ccsd_t){  // TODO: ccsd_t should not require storage

    blas->add_Matrix("ERROR{u}");
    blas->add_Matrix("<[oo]:[ov]>");
    blas->add_Matrix("<[oo]|[ov]>");
   

/*
    blas->add_Matrix("t2_test[oo][vv]{u}");
    blas->add_Matrix("t2_test[oO][vV]{u}");
    blas->add_Matrix("t2_test[OO][VV]{u}");*/

    blas->add_Matrix("F2_me[o][v]{u}");
    blas->add_Matrix("F2_ME[O][V]{u}");

    blas->add_Matrix("W'_abic[vvo][v]{u}");
    blas->add_Matrix("W'_aBIc[vVO][v]{u}");
    blas->add_Matrix("W'_AbiC[Vvo][V]{u}");
    blas->add_Matrix("W'_ABIC[VVO][V]{u}");

    blas->add_Matrix("W'_ajki[voo][o]{u}");
    blas->add_Matrix("W'_AjKi[VoO][o]{u}");
    blas->add_Matrix("W'_aJkI[vOo][O]{u}");
    blas->add_Matrix("W'_AJKI[VOO][O]{u}");

    blas->add_Matrix("W_kija[o][oov]{u}");
    blas->add_Matrix("W_kiJA[o][oOV]{u}");
    blas->add_Matrix("W_KIja[O][Oov]{u}");
    blas->add_Matrix("W_KIJA[O][OOV]{u}");

    blas->add_Matrix("W_aibc[v][ovv]{u}");
    blas->add_Matrix("W_aIbC[v][OvV]{u}");
    blas->add_Matrix("W_AiBc[V][oVv]{u}");
    blas->add_Matrix("W_AIBC[V][OVV]{u}");

    // 
    blas->add_Matrix("DELTA_t1[o][v]");
    blas->add_Matrix("DELTA_t1[O][V]");
    blas->add_Matrix("DELTA_t2[oo][vv]");
    blas->add_Matrix("DELTA_t2[oO][vV]");
    blas->add_Matrix("DELTA_t2[OO][VV]");

    // Required by T2*W_mcjk
    blas->add_Matrix("t2[ovv][o]{u}");
    blas->add_Matrix("t2[OvV][o]{u}");
    blas->add_Matrix("t2[oVv][O]{u}");
    blas->add_Matrix("t2[OVV][O]{u}");

    // Required by T2*W_bcek
    blas->add_Matrix("t2[oov][v]{u}");         
    blas->add_Matrix("t2[oOv][V]{u}");
    blas->add_Matrix("t2[OoV][v]{u}");
    blas->add_Matrix("t2[OOV][V]{u}");

    blas->add_Matrix("t3[ooo][vvv]{u}");
    blas->add_Matrix("t3[ooO][vvV]{u}");
    blas->add_Matrix("t3[oOO][vVV]{u}");
    blas->add_Matrix("t3[OOO][VVV]{u}");
/*
    blas->add_Matrix("t3_test[ooo][vvv]{u}");
    blas->add_Matrix("t3_test[ooO][vvV]{u}");
    blas->add_Matrix("t3_test[oOO][vVV]{u}");
    blas->add_Matrix("t3_test[OOO][VVV]{u}");*/

    blas->add_Matrix("t3_eqns[ooo][vvv]{u}");
    blas->add_Matrix("t3_eqns[ooO][vvV]{u}");
    blas->add_Matrix("t3_eqns[oOO][vVV]{u}");
    blas->add_Matrix("t3_eqns[OOO][VVV]{u}");
  }

}

}} /* End Namespaces */
