let ltl_to_neg_dnf (f : Types.ltl_type) : Types.if_term list list =
  let lists_from_dnf f =

    let rec list_from_dij = function
      | Dij(f1,f2) -> (list_from_dij f1) @ (list_from_dij f2)
      | x -> [x]
    in
    let rec list_from_conj = function
      | Pred(str) -> [str]
      | Conj(f1,f2) -> (list_from_conj f1) @ (list_from_conj f2)
      | x -> failwith "list_from_conj: impossible case"
    in

    List.map list_from_conj (list_from_dij f)
  in

  let rec ltl_to_dnf neg = function
    | Pred(Ifnot(str)) ->
        if neg then
          Pred(str)
        else
          Pred(Ifnot(str))

    | Pred(str) ->
        if neg then
          Pred(Ifnot(str))
        else
          Pred(str)

            (* ~f *)
    | Op5(f)    -> 
        ltl_to_dnf (not neg) f

          (* f1 /\ f2 *)
    | Conj(f1,f2) ->
        if neg then
          ltl_to_dnf false (Dij(Op5(f1),Op5(f2)))
        else
          let f1' = ltl_to_dnf false f1
          and f2' = ltl_to_dnf false f2
          in
          (match f1' with
            Dij(f1a,f1b) ->
              Dij(ltl_to_dnf false (Conj(f1a,f2')),
                  ltl_to_dnf false (Conj(f1b,f2')))
          | _ ->
              (match f2' with
                Dij(f2a,f2b) ->
                  Dij(ltl_to_dnf false (Conj(f1',f2a)),
                      ltl_to_dnf false (Conj(f1',f2b)))
              | _ ->
                  Conj(f1',f2')))

            (* f1 \/ f2 *)
    | Dij(f1,f2) ->
        if neg then
          ltl_to_dnf false (Conj(Op5(f1),Op5(f2)))
        else
          let f1' = ltl_to_dnf false f1
          and f2' = ltl_to_dnf false f2
          in
          Dij(f1',f2')

            (* f1 => f2 *)
    | Impl(f1,f2) ->
        ltl_to_dnf neg (Dij(Op5(f1),f2))

    | x -> x (* impossible case *)
  in

  lists_from_dnf (ltl_to_dnf true f)