type single_exc = { hole : int ; particle : int ; spin : Spin.t ; } type t = | Identity of Phase.t | Single of Phase.t * single_exc | Double of Phase.t * single_exc * single_exc | Triple of Phase.t * single_exc * single_exc * single_exc | Multiple of Phase.t * single_exc list let single_of_spindet t t' = assert (Spindeterminant.degree t t' = 1); let d = Spindeterminant.bitstring t and d' = Spindeterminant.bitstring t' in let tmp = Bitstring.logxor d d' in let shift_left_one = Bitstring.(shift_left_one (numbits tmp)) in let hole_z = Bitstring.logand (Spindeterminant.bitstring t ) tmp and particle_z = Bitstring.logand (Spindeterminant.bitstring t') tmp in let hole = 1 + Bitstring.trailing_zeros hole_z and particle = 1 + Bitstring.trailing_zeros particle_z in (* Phase calculation *) let low, high = if particle > hole then hole, particle else particle, hole in let mask = let h = high-1 in let l = low in let mask_up = shift_left_one h |> Bitstring.minus_one and mask_dn = Bitstring.plus_one @@ Bitstring.lognot (shift_left_one l) in Bitstring.logand mask_up mask_dn in let phase = Phase.add (Phase.add (Spindeterminant.phase t) (Spindeterminant.phase t')) (Phase.of_nperm (Bitstring.popcount @@ Bitstring.logand d mask )) in (hole, particle, phase) let single_of_det t t' = assert Determinant.(beta t = beta t' || alfa t = alfa t'); if Determinant.(beta t = beta t') then let hole, particle, phase = single_of_spindet (Determinant.alfa t) (Determinant.alfa t') in Single (phase, { hole ; particle ; spin=Spin.Alfa }) else let hole, particle, phase = single_of_spindet (Determinant.beta t) (Determinant.beta t') in Single (phase, { hole ; particle ; spin=Spin.Beta }) let multiple_of_spindet t t' = let holes = Spindeterminant.holes_of t t' and particles = Spindeterminant.particles_of t t' in let t'' = List.fold_left (fun accu h -> Spindeterminant.annihilation h accu) t holes in let t'' = List.fold_left (fun accu p -> Spindeterminant.creation p accu) t'' particles in assert (t' = t'' || t' = Spindeterminant.negate_phase t''); let phase = if Spindeterminant.phase t' = Spindeterminant.phase t'' then Phase.Pos else Phase.Neg in (phase, List.rev @@ List.rev_map2 (fun hole particle -> (hole, particle)) holes (List.rev particles) ) let double_of_spindet t t' = match multiple_of_spindet t t' with | (phase, (h1,p1)::(h2,p2)::[]) -> (h1, p1, h2, p2, phase) | _ -> invalid_arg "t and t' are not doubly excited" let triple_of_spindet t t' = match multiple_of_spindet t t' with | (phase, (h1,p1)::(h2,p2)::(h3,p3)::[]) -> (h1, p1, h2, p2, h3, p3, phase) | _ -> invalid_arg "t and t' are not doubly excited" let multiple_of_det t t' = let pa, a = multiple_of_spindet (Determinant.alfa t) (Determinant.alfa t') and pb, b = multiple_of_spindet (Determinant.beta t) (Determinant.beta t') in let phase = Phase.add pa pb in Multiple (phase, List.concat [ List.rev @@ List.rev_map (fun (hole, particle) -> { hole ; particle ; spin=Spin.Alfa }) a ; List.rev @@ List.rev_map (fun (hole, particle) -> { hole ; particle ; spin=Spin.Beta }) b ]) let double_of_det t t' = match multiple_of_det t t' with | Multiple (phase, [e1 ; e2]) -> Double (phase, e1, e2) | _ -> assert false let triple_of_det t t' = match multiple_of_det t t' with | Multiple (phase, [e1 ; e2 ; e3]) -> Triple (phase, e1, e2, e3) | _ -> assert false let of_det t t' = match Determinant.degree t t' with | 0 -> if Determinant.phase t = Determinant.phase t' then Identity Phase.Pos else Identity Phase.Neg | 1 -> single_of_det t t' | 2 -> double_of_det t t' | 3 -> triple_of_det t t' | _ -> multiple_of_det t t' let pp_s_exc ppf t = Format.fprintf ppf "@[T^{%s}_{%d->%d}@]" (match t.spin with | Spin.Alfa -> "\\alpha" | Spin.Beta -> "\\beta " ) t.hole t.particle let pp ppf t = let phase, l = match t with | Identity p -> p, [] | Single (p,x) -> p, x::[] | Double (p,x,y) -> p, x::y::[] | Triple (p,x,y,z) -> p, x::y::z::[] | Multiple (p,l) -> p, l in Format.fprintf ppf "@[%c" (match phase with | Phase.Pos -> '+' | Phase.Neg -> '-' ); List.iter (fun x -> Format.fprintf ppf "@[T^{%s}_{%d->%d}@]" (match x.spin with | Spin.Alfa -> "\\alpha" | Spin.Beta -> "\\beta " ) x.hole x.particle) l; Format.fprintf ppf "@]" let test_case () = (* let test_id () = let l_a = [ 1 ; 2 ; 3 ; 5 ; 64 ] and l_b = [ 2 ; 3 ; 5 ; 65 ] in let det1 = Determinant.of_lists l_a l_b in let det2 = Determinant.negate_phase det1 in in *) let test_single () = let l_a = [ 1 ; 2 ; 3 ; 5 ; 64 ] and l_b = [ 2 ; 3 ; 5 ; 65 ] in let det1 = Determinant.of_lists 66 l_a l_b in let det2 = Determinant.single_excitation Spin.Alfa 3 7 det1 in let t = single_of_det det1 det2 in Alcotest.(check bool) "single 1" true (t = Single (Phase.Pos, { hole=3 ; particle=7 ; spin=Spin.Alfa}) ); let det2 = Determinant.single_excitation Spin.Alfa 2 7 det1 |> Determinant.negate_phase in let t = single_of_det det1 det2 in Alcotest.(check bool) "single 2" true (t = Single (Phase.Neg, { hole=2 ; particle=7 ; spin=Spin.Alfa }) ); let det2 = Determinant.single_excitation Spin.Beta 2 7 det1 in let t = single_of_det det1 det2 in Alcotest.(check bool) "single 3" true (t = Single (Phase.Pos, { hole=2 ; particle=7 ; spin=Spin.Beta}) ); let det2 = Determinant.single_excitation Spin.Beta 3 256 det1 in let t = single_of_det det1 det2 in Alcotest.(check bool) "single 4" true (t = Single (Phase.Pos, { hole=3 ; particle=256 ; spin=Spin.Beta}) ); in let test_double () = let l_a = [ 1 ; 2 ; 3 ; 5 ; 64 ] and l_b = [ 2 ; 3 ; 5 ; 65 ] in let det1 = Determinant.of_lists 66 l_a l_b in let det2 = Determinant.double_excitation Spin.Alfa 3 7 Spin.Alfa 2 6 det1 in let t = double_of_det det1 det2 in Alcotest.(check bool) "double 1" true (t = Double (Phase.Neg, { hole=2 ; particle=7 ; spin=Spin.Alfa}, { hole=3 ; particle=6 ; spin=Spin.Alfa})); in [ "Single", `Quick, test_single; "Double", `Quick, test_double; ]