mirror of
https://gitlab.com/scemama/QCaml.git
synced 2024-12-22 20:33:36 +01:00
158 lines
4.6 KiB
OCaml
158 lines
4.6 KiB
OCaml
|
open Common
|
||
|
|
||
|
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.excitation_level 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.multiply (Phase.multiply (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.multiply 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.excitation_level 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 "@]"
|
||
|
|