(* END VERSION 1 *)

Definition mem_add_nonempty x s :=
  if isEq (compare_clause x (mkPureClause nil nil)) then None else
    mem_add x s.Definition add_list_to_set_simple (l: list M.elt) (s: M.t) : M.t :=
  fold_left (Basics.flip M.add) l s.Fixpoint add_list_to_set (l: list M.elt) (s: M.t) : option M.t :=
 match l with
 | x::xs => match mem_add x s with
                  | None => add_list_to_set xs s
                  | Some s' => Some (add_list_to_set_simple xs s')
                  end
 | nil => None
 end.(** Perform one inference step.  G(=given) is the set of previously selected
   clauses (the given clause set). U is the set of unselected clauses.

   The clause ordering, which is lexicographic first in the size of the clauses,
   then in the clauses themselves, ensures that the smallest clause in the
   unselected set is always returned.  this strategy is called best-first by
   McCune, "33 Basic Test Problems: A Practical Evaluation of Some
   Paramodulation Strategies", and performs reasonably well in practice.

   Algorithm:
   - Pick an unselected clause c \in U using the best-first (ie., small first)
      heuristic.
   - c <- simpflify(c, wrt. G)
   - G <- G \cup {c}
   - I <- infer(c, G) //all inferences between c and clauses in G
   - U <- (U \cup (I - G)) //add any clauses not yet in G and U to U
   - ret(U, G) *)

Definition is_pure_clause (c : clause) : bool :=
 match c with PureClause _ _ _ _ => true | _ => false end.Definition one_inference_step (given_unselected: M.t*M.t)
  : (M.t * M.t) :=
  let (given, unselected) := given_unselected in
  match M.delete_min unselected with
  | Some (given_clause, unselected') =>
    if is_pure_clause given_clause &&
       not_taut given_clause
    then let s := M.elements given in
      let c := simplify s given_clause in
      match mem_add c given with
      | None => (given, unselected')
      | Some new_given =>
        let inferred_clauses := infer_list c s in
        let new_unselected :=
          fold_left (fun s0 c =>
            if M.mem c new_given then s0
            else M.add c s0) inferred_clauses unselected'
          in (new_given, new_unselected)
      end
    else (given, unselected')
  | None => (given, unselected)
  end.Definition model := list (var * expr).Inductive superposition_result : Type :=
| Valid : superposition_result
| C_example : model -> M.t -> superposition_result
| Aborted : list clause -> superposition_result.Inductive superposition_result : Type :=
| Valid : superposition_result
| C_example : model -> M.t -> superposition_result
| Aborted : list clause -> superposition_result.Inductive superposition_result : Type :=
| Valid : superposition_result
| C_example : model -> M.t -> superposition_result
| Aborted : list clause -> superposition_result.Inductive superposition_result : Type :=
| Valid : superposition_result
| C_example : model -> M.t -> superposition_result
| Aborted : list clause -> superposition_result.(******** Model Generation ********)
Definition apply_model (R: model) (cl: clause) : clause :=
  fold_right (fun ve => subst_clause (fst ve) (snd ve)) cl R.Definition is_model_of (R: model) (gamma delta : list pure_atom) : bool :=
  match fold_right (fun ve => subst_pures_delete (fst ve) (snd ve)) gamma R,
          fold_right (fun ve => subst_pures (fst ve) (snd ve)) delta R with
  | _::_, _ => true
  | nil , delta' => negb (forallb nonreflex_atom delta')
  end.Definition is_model_of_PI (R: model) (nc : (*negative spatial*) clause) : bool :=
 match nc with NegSpaceClause pi_plus _ pi_minus =>
  match remove_trivial_atoms (fold_right (fun ve =>
          subst_pures_delete (fst ve) (snd ve)) pi_plus R),
        fold_right (fun ve =>
          subst_pures (fst ve) (snd ve)) pi_minus R with
  | nil , pi_minus' => forallb nonreflex_atom pi_minus'
  | _ :: _ , _ => false
  end
 | _ => false
 end.Definition clause_generate (R: model) (cl: clause) : option (var * expr * clause) :=
  match apply_model R cl with
  | PureClause gamma (Eqv (Var l' as l) r :: delta) _ _ as c' =>
    if (andb (greater_than_expr l' r)
         (andb (greater_than_all l' gamma)
           (andb (greater_than_atoms (Eqv l r) delta)
             (negb (is_model_of R gamma delta))))) then Some (l', r, cl)
    else None
  | _ => None
  end.Fixpoint clauses_generate (R: model) (cl: list clause) : model * M.t :=
  match cl with
  | nil => (R, M.empty)
  | c::cs => match clause_generate R c with
             | Some (i,e,c') => match clauses_generate ((i,e)::R) cs with
                                | (R', cs') => (R', M.add c cs')
                                end
             | None => clauses_generate R cs
             end
  end.(* main_loop(n, G, U):
   if n<=0: return Abort
   else:
       if empty_clause \in U: return Valid
       else:
           (G, U) <- one_inference_step(G, U)
           if is_empty U: return counter-example //G is saturated
           else: loop(n-1, G', U') *)
Definition arg := (M.t * M.t)%type.Definition varbound (ss: arg) : vset := var_upto (freshmax_list freshmax_clause (M.elements (M.union (fst ss) (snd ss)))).Definition effective_cardinal (vb : vset) (s: M.t) (n: nat) :=
  cardinal _ (Intersection _ (Basics.flip M.In s) (clause_bound vb) ) n.Definition headroom (vb: vset) (s: M.t) (h: nat) :=
 exists n, effective_cardinal vb s n /\ cardinal _ (clause_bound vb) (n+h).Definition clause_set_increases vb (s s':  M.t) : Prop :=
  exists n, exists n',  headroom vb s n /\ headroom vb s' n' /\ n < n'.

Lemma effective_cardinal_fun: forall vb s n n', effective_cardinal vb s n -> effective_cardinal vb s n' -> n=n'.