open Prims
type 'n nat_at_most = Prims.nat
type ('a, 's) index_fun = Obj.t nat_at_most -> Obj.t nat_at_most
type ('a, 's0, 's1) seqperm = ('a, 's0) index_fun
let rec find :
  'a .
    'a ->
      'a FStar_Sequence_Base.seq ->
        ('a FStar_Sequence_Base.seq * 'a FStar_Sequence_Base.seq)
  =
  fun x s ->
    if (FStar_Sequence_Util.head s) = x
    then ((FStar_Sequence_Base.empty ()), (FStar_Sequence_Util.tail s))
    else
      (let uu___ = find x (FStar_Sequence_Util.tail s) in
       match uu___ with
       | (pfx, sfx) ->
           ((FStar_Sequence_Util.cons (FStar_Sequence_Util.head s) pfx), sfx))
let rec permutation_from_equal_counts :
  'a .
    'a FStar_Sequence_Base.seq ->
      'a FStar_Sequence_Base.seq -> ('a, Obj.t, Obj.t) seqperm
  =
  fun s0 s1 ->
    if (FStar_Sequence_Base.length s0) = Prims.int_zero
    then let f i = i in f
    else
      (let uu___ = find (FStar_Sequence_Util.head s0) s1 in
       match uu___ with
       | (pfx, sfx) ->
           let s1' = FStar_Sequence_Base.append pfx sfx in
           let f' =
             permutation_from_equal_counts (FStar_Sequence_Util.tail s0) s1' in
           let n = FStar_Sequence_Base.length pfx in
           let f i =
             if i = Prims.int_zero
             then n
             else
               if (f' (i - Prims.int_one)) < n
               then f' (i - Prims.int_one)
               else (f' (i - Prims.int_one)) + Prims.int_one in
           f)
let foldm_back (m : 'a FStar_Algebra_CommMonoid.cm)
  (s : 'a FStar_Sequence_Base.seq) : 'a=
  FStar_Sequence_Util.fold_back
    (FStar_Algebra_CommMonoid.__proj__CM__item__mult m) s
    (FStar_Algebra_CommMonoid.__proj__CM__item__unit m)
let remove_i (s : 'a FStar_Sequence_Base.seq) (i : Prims.nat) :
  ('a * 'a FStar_Sequence_Base.seq)=
  let uu___ = FStar_Sequence_Util.split s i in
  match uu___ with
  | (s0, s1) ->
      ((FStar_Sequence_Util.head s1),
        (FStar_Sequence_Base.append s0 (FStar_Sequence_Util.tail s1)))
let shift_perm' (s0 : 'a FStar_Sequence_Base.seq)
  (s1 : 'a FStar_Sequence_Base.seq) (uu___ : unit)
  (p : ('a, Obj.t, Obj.t) seqperm) : ('a, Obj.t, Obj.t) seqperm=
  let uu___1 = FStar_Sequence_Util.un_build s0 in
  match uu___1 with
  | (s0', last) ->
      let n = FStar_Sequence_Base.length s0' in
      let p' i = if (p i) < (p n) then p i else (p i) - Prims.int_one in
      let uu___2 = remove_i s1 (p n) in
      (match uu___2 with | (uu___3, s1') -> p')
let shift_perm (s0 : 'a FStar_Sequence_Base.seq)
  (s1 : 'a FStar_Sequence_Base.seq) (uu___ : unit)
  (p : ('a, Obj.t, Obj.t) seqperm) : ('a, Obj.t, Obj.t) seqperm=
  shift_perm' s0 s1 () p
