Context[]
Needs["Notation`"]
Notation[(NotationTemplateTag[⟨x_\[VerticalSeparator]A_\[VerticalSeparator]y_⟩]) ⟺ (NotationTemplateTag[BraCKet[{x_},A_,{y_}]])]
AddInputAlias["braCKet"->(NotationTemplateTag[⟨\[Placeholder]\[VerticalSeparator]\[Placeholder]\[VerticalSeparator]\[Placeholder]⟩])]
Clear[BraKet, BraCKet];
αβ[x_]:=MatchQ[x,α|β]
Nαβ[x_]:=!αβ[x]  (* defines pattern to identify function that is not spin states α or β *)

(* used to show that electron density of from Slater determinant is sum of orbital electron densities *)
(*BraKet[{f_[τ1]q_},{g_[τ1]r_}]:=f[τ1]g[τ1]BraKet[{q},{r}] *)

(* Linearity of <f|g> *)
BraKet[{f_+g_},{k_}]:=BraKet[{f},{k}]+BraKet[{g},{k}]
BraKet[{f_},{i_+k_}]:=BraKet[{f},{i}]+BraKet[{f},{k}]
BraKet[{c_?NumericQ f_},{g_}]:=c BraKet[{f},{g}]
BraKet[{f_},{c_?NumericQ g_}]:=c BraKet[{f},{g}]
BraKet[{q_ f_[x_]},{r_ g_[x_]}]:=BraKet[{f[x]},{g[x]}]BraKet[{q},{r}]

(* Linearity of <f|A|k> *)
BraCKet[{f_+g_},A_,{k_}]:=BraCKet[{f},A,{k}]+BraCKet[{g},A,{k}]//Simplify
BraCKet[{f_},A_,{i_+k_}]:=BraCKet[{f},A,{i}]+BraCKet[{f},A,{k}]//Simplify
BraCKet[{c_?NumericQ f_},A_,{k_}]:=c BraCKet[{f},A,{k}]//Simplify
BraCKet[{f_},A_,{c_?NumericQ k_}]:=c BraCKet[{f},A,{k}]//Simplify

(* Orthogonality of spin states *)
BraKet[{α[x_]_},_,{β[x_]_}]:=0
BraKet[{β[x_]_},_,{α[x_]_}]:=0
BraCKet[{α[x_]_},_,{β[x_]_}]:=0
BraCKet[{β[x_]_},_,{α[x_]_}]:=0


(* Separation of products involving different variables *)
(* If spin states are present, need to ensure that is they that are separated out, 
	and the spatial orbitals (which return true by Nαβ) stay in bracket *)
BraCKet[{f_?(Nαβ)[x_]ab_?(αβ)[x_]q_},A_[x_],{g_?(Nαβ)[x_]ab_?(αβ)[x_]r_}]:=BraCKet[{f[x]ab},A[x],{g[x]ab}]BraKet[{q},{r}]
BraCKet[{f_?(Nαβ)[x_]i_?(Nαβ)[y_]abx_?(αβ)[x_]aby_?(αβ)[y_]q_?(Nαβ)},A_[x_,y_],{g_?(Nαβ)[x_]h_?(Nαβ)[y_]abx_?(αβ)[x_]aby_?(αβ)[y_]r_?(Nαβ)}]:=BraCKet[{f[x]i[y]abx[x] aby[y]},A[x,y],{g[x]h[y]abx[x] aby[y]}]BraKet[{q},{r}]

(* Linearity with respect to operators *)
BraCKet[{f_},A_+B_,{g_}]:=BraCKet[{f},A,{g}]+BraCKet[{f},B,{g}]
BraCKet[{f_},c_?NumericQ A_,{g_}]:=c BraCKet[{f},A,{g}]

spinSumRules={(c_:1) BraCKet[{ab1_?(αβ)[x_]ab2_?(αβ)[y_]f_[x_]g_[y_]},A_[x_,y_],{ab1_?(αβ)[x_]ab2_?(αβ)[y_]f_[x_]g_[y_]}]+(d_ :1) BraCKet[{ab2_?(αβ)[x_]ab1_?(αβ)[y_]f_[x_]g_[y_]},A_[x_,y_],{ab2_?(αβ)[x_]ab1_?(αβ)[y_]f_[x_]g_[y_]}]:>(c+d)BraCKet[{ab1[x]ab2[y]f[x]g[y]},A[x,y],{ab1[x]ab2[y]f[x]g[y]}]}


(* Terms with different dummy indices are equivalent and can be summed *)
sumRules={(c_:1) BraCKet[{f_[x_]g_[y_]q___},A_[x_,y_],{f_[x_]g_[y_]r___}]+(d_ :1) BraCKet[{f_[w_]g_[z_]q___},A_[z_,w_],{f_[w_]g_[z_]r___}]:> (c+d) BraCKet[{f[x]g[y]q},A[x,y],{f[x]g[y]r}],(c_:1) BraCKet[{f_[x_]g_[y_]},A_[x_,y_],{f_[x_]g_[y_]}]+(d_ :1) BraCKet[{f_[w_]g_[z_]},A_[z_,w_],{f_[w_]g_[z_]}]:> (c+d) BraCKet[{f[x]g[y]},A[x,y],{f[x]g[y]}],
(c_:1) BraCKet[{f_[x_]g_[y_]},A_[x_,y_],{f_[y_]g_[x_]}]+(d_:1) BraCKet[{f_[w_]g_[z_]},A_[z_,w_],{f_[z_]g_[w_]}]:>(c+d) BraCKet[{f[x]g[y]},A[x,y],{f[y]g[x]}],
(c_:1) BraCKet[{f_[x_]g_[y_]},A_[x_,y_],{h_[x_]i_[y_]}]+(d_:1) BraCKet[{f_[w_]g_[z_]},A_[w_,z_],{h_[w_]i_[z_]}]:>(c+d) BraCKet[{f[x]g[y]},A[x,y],{h[x]i[y]}],
(c_:1) BraCKet[{f_[x_]},A_[x_],{g_[x_]}]+(d_:1) BraCKet[{f_[y_]},A_[y_],{g_[y_]}]:>(c+d) BraCKet[{f[x]},A[x],{g[x]}]
};

(* Orthonomality condition *)
orthonormalRule = {BraKet[{f_[x_]},{g_[x_]}] :> If[f===g,1,0]};

(* Remove dummy variables *)
noDummiesRule = {BraCKet[{f_[x_]},A_[x_],{k_[x_]}] :> BraCKet[{f},A,{k}]};

Clear[mullikenFormRule]
mullikenString[i_,ab_]:=If[ab===α,ToString[Style[i,Black],StandardForm],ToString[Style[i,Red],StandardForm]]
mullikenFormRule={
⟨(Subscript[ϕ, i_])[x_] (Subscript[ϕ, k_])[y_]\[VerticalSeparator]_\[VerticalSeparator](Subscript[ϕ, j_])[x_] (Subscript[ϕ, l_])[y_]⟩:>"["<>ToString[i]<>ToString[j]<>"|"<>ToString[k]<>ToString[l]<>"]"};
mullikenFormRule={
⟨abi_?(αβ)[x_] abk_?(αβ)[y_] (Subscript[ϕ, i_])[x_] (Subscript[ϕ, k_])[y_]\[VerticalSeparator]_\[VerticalSeparator]abj_?(αβ)[x_]abl_?(αβ)[y_](Subscript[ϕ, j_])[x_] (Subscript[ϕ, l_])[y_]⟩:>"["<>mullikenString[i,abi]<>mullikenString[j,abj]<>"|"<>mullikenString[k,abk]<>mullikenString[l,abl]<>"]"};