(* gsl-ocaml - OCaml interface to GSL                       *)
(* Copyright (©) 2002-2012 - Olivier Andrieu                *)
(* Distributed under the terms of the GPL version 3         *)


let () = Error.init ()

open Bigarray

type permut = 
    (int, int_elt, c_layout) Array1.t

let of_array arr =
  Array1.of_array int c_layout arr

let to_array perm = 
  let len = Array1.dim perm in
  Array.init len (Array1.get perm)

external init : permut -> unit
    = "ml_gsl_permutation_init"

let create len = 
  Array1.create int c_layout len

let make len = 
  let p = create len in
  init p ;
  p

let swap p i j =
  let tmp_i = p.{i} in
  let tmp_j = p.{j} in
  p.{i} <- tmp_j ;
  p.{j} <- tmp_i

let size = 
  Array1.dim

external _valid : permut -> bool
    = "ml_gsl_permutation_valid"

let valid p =
  try _valid p
  with Error.Gsl_exn (Error.FAILURE, _) -> false

external reverse : permut -> unit
    = "ml_gsl_permutation_reverse"

external _inverse : src:permut -> dst:permut -> unit
    = "ml_gsl_permutation_inverse"

let inverse p =
  let i = create (size p) in
  _inverse ~src:p ~dst:i ;
  i

external next : permut -> unit
    = "ml_gsl_permutation_next"

external prev : permut -> unit
    = "ml_gsl_permutation_prev"

external permute : permut -> 'a array -> unit
    = "ml_gsl_permute"
external permute_barr : permut -> ('a, 'b, 'c) Bigarray.Array1.t -> unit
    = "ml_gsl_permute_barr"
external permute_complex : permut -> Gsl_complex.complex_array -> unit
    = "ml_gsl_permute_complex"

external permute_inverse : permut -> 'a array -> unit
    = "ml_gsl_permute_inverse"
external permute_inverse_barr : permut -> 
  ('a, 'b, 'c) Bigarray.Array1.t -> unit
    = "ml_gsl_permute_inverse_barr"
external permute_inverse_complex : permut -> Gsl_complex.complex_array -> unit
    = "ml_gsl_permute_inverse_complex"

external _mul : permut -> permut -> permut -> unit = "ml_gsl_permute_mul"
let mul pa pb =
  let p = create (size pa) in
  _mul p pa pb ;
  p

external _lin_to_can : permut -> permut -> unit = "ml_gsl_permute_linear_to_canonical"
let linear_to_canonical p =
  let q = create (size p) in
  _lin_to_can q p ;
  q

external _can_to_lin : permut -> permut -> unit = "ml_gsl_permute_canonical_to_linear"
let canonical_to_linear q =
  let p = create (size q) in
  _can_to_lin p q ;
  p

external inversions : permut -> int = "ml_gsl_permute_inversions"
external canonical_cycles : permut -> int = "ml_gsl_permute_canonical_cycles"
external linear_cycles : permut -> int = "ml_gsl_permute_linear_cycles"
