Require Import Vector Arith.
Notation vec := Vector.t.
Class funcs_signature := { syms : Type; ar_syms : syms -> nat }.
Class preds_signature := { preds : Type; ar_preds : preds -> nat }.
Class operators := { binop : Type ; quantop : Type }.
Coercion syms : funcs_signature >-> Sortclass.
Coercion preds : preds_signature >-> Sortclass.
Section Syntax.
Context {Σ_funcs : funcs_signature}.
Unset Elimination Schemes.
Inductive function : nat -> Type :=
| var_func : nat -> forall ar, function ar
| sym : forall f : syms, function (ar_syms f).
Inductive term : Type :=
| var_indi : nat -> term
| func {ar} (_ : function ar) (v : vec term ar) : term.
Set Elimination Schemes.
Context {Σ_preds : preds_signature}.
Inductive predicate : nat -> Type :=
| var_pred : nat -> forall ar, predicate ar
| pred : forall P : preds, predicate (ar_preds P).
Context {ops : operators}.
Inductive form : Type :=
| fal : form
| atom : forall {ar}, predicate ar -> vec term ar -> form
| bin : binop -> form -> form -> form
| quant_indi : quantop -> form -> form
| quant_func : quantop -> nat -> form -> form
| quant_pred : quantop -> nat -> form -> form.
End Syntax.
Arguments var_func {_} _ {_}, {_} _ _.
Arguments var_pred {_} _ {_}, {_} _ _.
Inductive full_logic_sym : Type :=
| Conj : full_logic_sym
| Disj : full_logic_sym
| Impl : full_logic_sym.
Inductive full_logic_quant : Type :=
| All : full_logic_quant
| Ex : full_logic_quant.
#[global]
Instance full_operators : operators :=
{| binop := full_logic_sym ; quantop := full_logic_quant |}.
Section Tarski.
Definition env_indi domain := nat -> domain.
Definition env_func domain := nat -> forall ar, vec domain ar -> domain.
Definition env_pred domain := nat -> forall ar, vec domain ar -> Prop.
Record env domain := new_env { get_indi : env_indi domain ; get_func : env_func domain ; get_pred : env_pred domain }.
Notation "⟨ a , b , c ⟩" := (new_env _ a b c).
Arguments get_indi {_}.
Arguments get_func {_}.
Arguments get_pred {_}.
Class Econs X Env := econs : X -> Env -> Env.
Local Notation "x .: rho" := (econs x rho) (at level 70, right associativity).
#[global] Instance econs_indi domain : Econs domain (nat -> domain) :=
fun x env n => match n with 0 => x | S n => env n end.
Definition econs_ar ar p : Econs (p ar) (nat -> forall ar, p ar) :=
fun x env n => match n with
| 0 => fun ar' => match Nat.eq_dec ar ar' with
| left e => match e in _ = ar' return p ar' with eq_refl => x end
| right _ => env n ar'
end
| S n => fun ar' => if Nat.eq_dec ar ar' then env n ar' else env (S n) ar'
end.
#[global] Instance econs_func domain ar : Econs _ _ := econs_ar ar (fun ar => vec domain ar -> domain).
#[global] Instance econs_pred domain ar : Econs _ _ := econs_ar ar (fun ar => vec domain ar -> Prop).
Context {Σ_funcs : funcs_signature}.
Context {Σ_preds : preds_signature}.
Variable domain : Type.
Class interp := B_I {
i_f : forall f : syms, vec domain (ar_syms f) -> domain ;
i_P : forall P : preds, vec domain (ar_preds P) -> Prop ;
}.
Context { I : interp }.
Definition eval_function {ar} (rho : env domain) (f : function ar) : vec domain ar -> domain :=
match f with
| var_func f => get_func rho f _
| sym f => i_f f
end.
Definition eval_predicate {ar} (rho : env domain) (P : predicate ar) : vec domain ar -> Prop :=
match P with
| var_pred P => get_pred rho P _
| pred P => i_P P
end.
Fixpoint eval (rho : env domain) (t : term) : domain :=
match t with
| var_indi x => get_indi rho x
| func f v => eval_function rho f (Vector.map (eval rho) v)
end.
Fixpoint sat (rho : env domain) (phi : form) : Prop :=
match phi with
| atom P v => eval_predicate rho P (Vector.map (eval rho) v)
| fal => False
| bin Impl phi psi => sat rho phi -> sat rho psi
| bin Conj phi psi => sat rho phi /\ sat rho psi
| bin Disj phi psi => sat rho phi \/ sat rho psi
| quant_indi Ex phi => exists d : domain, sat ⟨d .: get_indi rho, get_func rho, get_pred rho⟩ phi
| quant_indi All phi => forall d : domain, sat ⟨d .: get_indi rho, get_func rho, get_pred rho⟩ phi
| quant_func Ex ar phi => exists (f : vec domain ar -> domain), sat ⟨get_indi rho, f .: get_func rho, get_pred rho⟩ phi
| quant_func All ar phi => forall (f : vec domain ar -> domain), sat ⟨get_indi rho, f .: get_func rho, get_pred rho⟩ phi
| quant_pred Ex ar phi => exists (P : vec domain ar -> Prop), sat ⟨get_indi rho, get_func rho, P .: get_pred rho⟩ phi
| quant_pred All ar phi => forall (P : vec domain ar -> Prop), sat ⟨get_indi rho, get_func rho, P .: get_pred rho⟩ phi
end.
End Tarski.
Record Model `{funcs_signature, preds_signature} := {
M_domain : Type ;
M_interp : interp M_domain
}.
Coercion M_domain : Model >-> Sortclass.
#[global] Instance M_I `{funcs_signature, preds_signature} M : interp (M_domain M) := M_interp M.
Module SOLNotations.
Notation "x .: rho" := (econs x rho) (at level 70, right associativity).
Notation "$ x" := (var_indi x) (at level 5, format "$ '/' x").
Notation "i$ x" := (var_indi x) (at level 5, format "i$ '/' x").
Notation "f$ x" := (func (var_func x)) (at level 5, format "f$ '/' x").
Notation "p$ x" := (atom (var_pred x)) (at level 5, format "p$ '/' x").
Notation "⊥" := fal.
Notation "A ∧ B" := (@bin _ _ full_operators Conj A B) (at level 41).
Notation "A ∨ B" := (@bin _ _ full_operators Disj A B) (at level 42).
Notation "A '~>' B" := (@bin _ _ full_operators Impl A B) (at level 43, right associativity).
Notation "A '<~>' B" := ((A ~> B) ∧ (B ~> A)) (at level 43).
Notation "¬ A" := (A ~> ⊥) (at level 40).
Notation "∀i Phi" := (@quant_indi _ _ full_operators All Phi) (at level 50).
Notation "∃i Phi" := (@quant_indi _ _ full_operators Ex Phi) (at level 50).
Notation "∀f ( ar ) Phi" := (@quant_func _ _ full_operators All ar Phi) (at level 50).
Notation "∃f ( ar ) Phi" := (@quant_func _ _ full_operators Ex ar Phi) (at level 50).
Notation "∀p ( ar ) Phi" := (@quant_pred _ _ full_operators All ar Phi) (at level 50).
Notation "∃p ( ar ) Phi" := (@quant_pred _ _ full_operators Ex ar Phi) (at level 50).
End SOLNotations.
#[global] Instance empty_funcs_sig : funcs_signature := {| syms := False; ar_syms := fun f => match f with end |}.
#[global] Instance empty_preds_sig : preds_signature := {| preds := False; ar_preds := fun P => match P with end |}.
Definition SOL_valid (phi : form) := forall (M : Model) rho, sat M rho phi.
Definition SOL_satis (phi : form) := exists (M : Model) rho, sat M rho phi.