(**
A spin-determinant is one of the two determinants in the Waller-Hartree
double determinant representation of a Slater determinant. It is represented
as a bit string and a phase factor.
*)

type t 
type hole = int
type particle = int

(** {1 Accessors}. *)

val phase : t -> Phase.t
(** Phase factor.
    @raise Invalid_argument if the spin-determinant is [None].
*)

val set_phase : Phase.t -> t -> t
(** Returns a spin-determinant with the phase set to [p]. *)


val bitstring : t -> Bitstring.t
(** Bit string.
    @raise Invalid_argument if the spin-determinant is [None].
*)

val is_none : t -> bool
(** Tests if a spin-determinant is [None]. *)

val negate_phase : t -> t
(** Returns a spin-determinant with the phase reversed. *)


(** {1 Second quantization operators} *)

val vac : int -> t
(** Vacuum state, [vac = Some ]{% $|\rangle$ %}. The integer parameter contains the
   number of orbitals in the basis set. *)

val creation : particle -> t -> t
(** [creation p] is the creation operator {% $a^\dagger_p$ %}. *)

val annihilation : hole -> t -> t
(** [annihilation h] is the annihilation operator {% $a_h$ %}. *)

val single_excitation : hole -> particle -> t -> t
(** Single excitation operator {% $T_h^p = a^\dagger_p a_h$ %}. *)

val double_excitation : hole -> particle -> hole -> particle -> t -> t
(** Double excitation operator {% $T_{hh'}^{pp'} = a^\dagger_p a^\dagger_{p'} a_{h'} a_h$ %}. *)

val degree : t -> t -> int
(** Returns degree of excitation between two spin-determinants. *)

val holes_of : t -> t -> int list
(** Returns the list of holes in the excitation from one determinant to another. *)

val particles_of : t -> t -> int list
(** Returns the list of particles in the excitation from one determinant to another. *)

val holes_particles_of : t -> t -> (int*int) list
(** Returns the list of pairs of holes/particles in the excitation from one determinant to
another. *)

val n_electrons : t -> int
(** Returns the number of electrons in the determinant. *)


(** {1 Creation} *)

val of_bitstring : ?phase:Phase.t -> Bitstring.t -> t
(** Creates from a bitstring and an optional phase.*)

val of_list : int -> int list -> t
(** Builds a spin-determinant from a list of orbital indices. If the creation of the
    spin-determinant is not possible because of Pauli's exclusion principle, a [None]
    spin-determinant is returned. 
    The first integer is the size of the MO basis set. *)

val to_list : t -> int list
(** Transforms a spin-determinant into a list of orbital indices. *)

val to_array : t -> int array
(** Transforms a spin-determinant into an array of orbital indices. *)

(** {1 Printers}. *)

val pp : int -> Format.formatter -> t -> unit
(** First [int] is the number of MOs to print *)


(** {1 Unit testing} *)

val test_case : unit -> (string * [> `Quick ] * (unit -> unit)) list
