Skip to content
Snippets Groups Projects
CoAlgLogics.ml 17.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Thorsten Wißmann's avatar
    Thorsten Wißmann committed
    (** The "plug-in" functions for each individual logic.
        @author Florian Widmann
     *)
    
    
    open CoAlgMisc
    
    open CoAlgLogicUtils
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
    open Gmlmip
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
    
    
    module S = MiscSolver
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
    
    
    (** directly return a list of rules **)
    
    let mkRuleList_MultiModalK sort bs sl : rule list =
    
      (* arguments: 
        sort: type of formulae in bs (needed to disambiguate hashing)
        sl: sorts functor arguments, e.g. type of argument formulae
        bs: tableau sequent  consisting of modal atoms
            (premiss, conjunctive set of formulae represented by hash values)
        result: set R of (propagation function, rule conclusion) pairs
            s.t. [ (premiss / conc) : (_, conc) \in R ] are all rules
            applicable to premiss.
            Propagation functions map unsatisfiable subsets of the
            (union of all?) conclusion(s) to unsatisfiable subsets of
            the premiss -- this is a hook for backjumping.
            NB: propagating the whole premiss is always safe.
      *)
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
      assert (List.length sl = 1);
    
      let dep f bsl =                 (* dependencies for formula f (f is a diamond) *)
    
        assert (List.length bsl = 1); (* -+                 *)
        let bs1 = List.hd bsl in      (* -+-> [bs1] := bsl  *)
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
        let res = bsetMake () in
        bsetAdd res f;
    
        let (role : int) = lfGetDest3 sort f in (* ♥R.? := f, ♥ ∈ {∃,∀} *)
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
        let filterFkt f1 =
          if lfGetType sort f1 = AxF && lfGetDest3 sort f1 = role
            && bsetMem bs1 (lfGetDest1 sort f1)
    
          then
            (* if f1 = ∀R.C and C ∈ bs1 then res = res ∪ {∀R.C} *)
            bsetAdd res f1
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
          else ()
        in
        bsetIter filterFkt bs;
        res
      in
      let getRules f acc =
    
        if lfGetType sort f = ExF then (* f = ∃R.C,i.e. a diamond *)
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
          let bs1 = bsetMake () in
    
          bsetAdd bs1 (lfGetDest1 sort f); (* bs1 := { C }          *)
          let (role : int) = lfGetDest3 sort f in (* role := R *)
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
          let filterFkt f1 =
            if lfGetType sort f1 = AxF && lfGetDest3 sort f1 = role then
    
              (* if f1 = ∀R.D then bs1 = bs1 ∪ { D } *)
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
              bsetAdd bs1 (lfGetDest1 sort f1)
            else ()
          in
    
          bsetIter filterFkt bs; (* bs1 := bs1 ∪ { D | some "∀R.D" ∈ bs } *)
          let s1 = List.hd sl in (* [s1] := sl *)
    
          let rle = (dep f, lazylistFromList [(s1, bs1)]) in
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
          rle::acc
        else acc
      in
    
      (* effectively:
            mkRule_MultiModalK sort bs [s1]
                = { ( λ[bs1]. { ∃R.C } ∪ { ∀R.D
                                         | ∀R.D ∈ bs, D ∈ bs1
                                         }
                    , [(s1, {C}∪{D | "∀R.D" ∈ bs)]
                    )
                  | "∃R.C" ∈ bs
                  }
      *)
    
      bsetFold getRules bs []
    
    
    let mkRule_MultiModalK sort bs sl : stateExpander =
    
      let rules = mkRuleList_MultiModalK sort bs sl in
    
      lazylistFromList rules
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
    
    
    (* TODO: test it with:
         make && ./coalg sat <<< $'<R> False \n [R] False \n [R] True'
    *)
    
    let mkRule_MultiModalKD sort bs sl : stateExpander =
    
      assert (List.length sl = 1); (* functor has just one argument *)
      let s1 = List.hd sl in (* [s1] = sl *)
    
      let roles = S.makeBS () in
      (* step 1: for each ∀R._ add R *)
      let addRoleIfBox formula =
    
        if lfGetType sort formula = AxF then
    
          ignore (S.addBSNoChk roles (lfGetDest3 sort formula))
    
        else ()
      in
      bsetIter (addRoleIfBox) bs;
      (* step 2: for each ∃R._ remove R again from roles (optimization) *)
      let rmRoleIfDiamond formula =
        if lfGetType sort formula = ExF then
          S.remBS roles (lfGetDest3 sort formula)
        else ()
      in
      bsetIter (rmRoleIfDiamond) bs;
      (* step 3: for each R in roles enforce one successor *)
      let getRules r acc = (* add the rule for a concrete R *)
        let dep r bsl =
    
          assert (List.length bsl = 1); (* -+                 *)
          let bs1 = List.hd bsl in      (* -+-> [bs1] := bsl  *)
          let res = bsetMake () in (* res := { ∀R.D ∈ bs | D ∈ bs1} *)
          let f formula =
            if lfGetType sort formula = AxF
               && lfGetDest3 sort formula = r
               && bsetMem bs1 (lfGetDest1 sort formula)
            then ignore (bsetAdd res formula)
            else ()
          in
          bsetIter f bs; (* fill res *)
          res
        in
        let succs = bsetMake () in (* succs := {D | ∀r.D ∈ bs *)
        let f formula =
          if lfGetType sort formula = AxF
             && lfGetDest3 sort formula = r
          then ignore (bsetAdd succs (lfGetDest1 sort formula))
          else ()
    
        bsetIter f bs;
    
        (dep r, lazylistFromList [(s1, succs)])::acc
    
      in
      (*
        mkRule_MultiModalKD sort bs [s1]
            = { (λ[bs1]. { ∀R.D ∈ bs | D ∈ bs1}
                , [(s1, {D | "∀R.D" ∈ bs)]
                )
              | R ∈ signature(bs) (or R ∈ roles)
              }
              ∪ mkRule_MultiModalK sort bs [s1]
      *)
      let rules = mkRuleList_MultiModalK sort bs sl in
      (* extend rules from K with enforcing of successors *)
      let rules = S.foldBS getRules roles rules in
    
      lazylistFromList rules
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
    
    
    (* CoalitionLogic: helper functions *)
    (*val subset : bitset -> bitset -> bool*)
    let bsetlen (a: bset) : int =
        let res = ref (0) in
        bsetIter (fun _ -> res := !res + 1) a;
        !res
    
    let subset (a: bset) (b: bset) : bool =
        let res = ref (true) in
        let f formula =
            if bsetMem b formula
            then ()
            else res := false
        in
        bsetIter f a;
        !res && (bsetlen a < bsetlen b)
    
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
    let bsetForall (a: bset) (f: CoAlgMisc.localFormula -> bool) : bool =
        let res = ref (true) in
        let helper formula =
            if (f formula) then () else res := false
        in
        bsetIter helper a;
        !res
    
    let bsetExists (a: bset) (f: CoAlgMisc.localFormula -> bool) : bool =
        not (bsetForall a (fun x -> not (f x)))
    
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
    let compatible sort (a: bset) formula1 =
        let res = ref (true) in
        let f formula2 =
            if not (disjointAgents sort formula1 formula2)
            then res := false
            else ()
        in
        bsetIter f a;
        !res
    
    (*
        CoalitionLogic: tableau rules for satisfiability
    
        Rule 1:
    
         /\  n
        /  \i=1 [C_i] a_i       n ≥ 0,
      ——————————————————————    C_i pairwise disjoint
         /\  n
        /  \i=1  a_i
    
        Rule 2:
    
         /\ n                         /\ m
        /  \i=1 [C_i] a_i  /\ <D> b  /  \j=1 <N> c_j    n,m ≥ 0
      ————————————————————————————————————————————————  C_i pairwise disjoint
         /\ n                         /\ m              all C_i ⊆ D
        /  \i=1 a_i        /\    b   /  \j=1 c_j
    *)
    
    
    (* Not yet implemented: backjumping hooks. 
    
      E.g. in Rule 1, if a subset I of {a_1, ..., a_n} is unsat, then {[C_i] a_i : i \in I} is
      already unsat.
    *)
    
    
    let mkRule_CL sort bs sl : stateExpander =
    
      assert (List.length sl = 1); (* TODO: Why? *)
      let s1 = List.hd sl in (* [s1] = List.hd sl *)
    
      let boxes = bsetFilter bs (fun f -> lfGetType sort f = EnforcesF) in
      let diamonds = bsetFilter bs (fun f -> lfGetType sort f = AllowsF) in
      let disjoints = maxDisjoints sort boxes in
    
      (*print_endline ("disjoints: "^(string_of_coalition_list sort disjoints)); *)
    
      let nCandsEmpty = ref (true) in
    
      let nCands = bsetMakeRealEmpty () in (* all N-diamonds *)
    
      let dCandsEmpty = ref (true) in
    
      let hasFullAgentList formula =
        let aglist = lfGetDestAg sort formula in
    
        let value = TArray.all (fun x -> TArray.elem x aglist) (cl_get_agents ()) in
    
        if (value) then
        begin
            bsetAdd nCands formula;
            nCandsEmpty := false
        end
        else dCandsEmpty := false;
    
        value
      in
      (* Candidates for D in Rule 2 *)
    
      (* implicitly fill nCands *)
    
      let dCands = bsetFilter diamonds (fun f -> not (hasFullAgentList f)) in
    
      (*
      print_endline ("For set " ^(CoAlgMisc.bsetToString sort bs));
      print_endline ("N-Cands: " ^(CoAlgMisc.bsetToString sort nCands));
      print_endline ("D-Cands: " ^(CoAlgMisc.bsetToString sort dCands));
      *)
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
      let c_j : localFormula list =
        bsetFold (fun f a -> (lfGetDest1 sort f)::a) nCands []
      in
    
      (* rule 2 for diamaonds where D is a proper subset of the agent set N *)
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
      let getRule2 diamDb acc = (* diamDb = <D> b *)
    
        (* print_endline "Rule2" ; *)
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
        let d = lfGetDestAg sort diamDb in (* the agent list *)
        let b = lfGetDest1 sort diamDb in
        let hasAppropriateAglist f =
            let aglist = lfGetDestAg sort f in
            TArray.included aglist d
        in
        let maxdisj = maxDisjoints sort (bsetFilter boxes hasAppropriateAglist) in
        let createSingleRule acc coalitions =
            let a_i : localFormula list =
                bsetFold (fun f a -> (lfGetDest1 sort f)::a) coalitions []
            in
            (* now do rule 2:
                coalitions  /\ <d> b /\ nCands
               ————————————————————————————————
                  a_i       /\     b /\ c_j
            *)
    
            let children = bsetMakeRealEmpty () in
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
            List.iter (bsetAdd children) (b::c_j) ;
            List.iter (bsetAdd children) (a_i) ;
    
            ((fun bs1 -> bs), lazylistFromList [(s1, children)])::acc
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
        in
        List.fold_left createSingleRule acc maxdisj
      in
      let rules = bsetFold getRule2 dCands [] in
    
      let getRule2ForFullAgents acc =
        (* if there are N-diamonds but no diamonds with a proper subset of the agents,
           then we need an explicit rule 2
        *)
        if not !nCandsEmpty && !dCandsEmpty then begin
            (* create rule 2 once for all the diamonds with a full agent set *)
            let maxdisj = maxDisjoints sort boxes in
            let createSingleRule acc coalitions =
                let a_i : localFormula list =
                    bsetFold (fun f a -> (lfGetDest1 sort f)::a) coalitions []
                in
                (* now do rule 2:
                    coalitions  /\ nCands
                   ———————————————————————
                      a_i       /\ c_j
                *)
                let children = bsetMakeRealEmpty () in
                List.iter (bsetAdd children) (c_j) ;
                List.iter (bsetAdd children) (a_i) ;
                ((fun bs1 -> bs), lazylistFromList [(s1, children)])::acc
            in
            List.fold_left createSingleRule acc maxdisj
        end else acc
      in
      let rules = getRule2ForFullAgents rules in
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
      let getRule1 acc coalitions =
    
        (* print_endline "Rule1" ; *)
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
        (* do rule 1:
            coalitions
           ————————————
               a_i
        *)
    
        let a_i : bset = bsetMakeRealEmpty () in
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
        bsetIter (fun f -> bsetAdd a_i (lfGetDest1 sort f)) coalitions ;
    
        ((fun bs1 -> bs), lazylistFromList [(s1, a_i)])::acc
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
      in
      let rules = List.fold_left getRule1 rules disjoints in
    
      (*
        mkRule_CL sort bs [s1]
    
        = { (λ[bs1]. bs, [(s1, { a_i | i∈I })])
    
            | {[C_i]a_i | i∈I} ⊆ bs,
              C_i pairwise disjoint and I maximal
            }
      *)
    
      lazylistFromList rules
    
    let mkRule_GML sort bs sl : stateExpander =
    
      assert (List.length sl = 1);
      let s1 = List.hd sl in (* [s1] = List.hd sl *)
    
      let diamonds = bsetFilter bs (fun f -> lfGetType sort f = MoreThanF) in
      let boxes = bsetFilter bs (fun f -> lfGetType sort f = MaxExceptF) in
      let roles = S.makeBS () in
      (* step 1: for each diamond/box add R *)
      let addRole formula =
    
          ignore (S.addBSNoChk roles (lfGetDest3 sort formula))
    
      in
      bsetIter addRole boxes;
      bsetIter addRole diamonds;
    
      let addRule role acc =
          let premise: (bool*int*int) list =
            let modality isDiamond m acc =
                if lfGetDest3 sort m = role
                then (isDiamond,lfGetDestNum sort m,lfToInt (lfGetDest1 sort m))::acc
                else acc
            in
            List.append
                (bsetFold (modality true) diamonds [])
                (bsetFold (modality false) boxes [])
          in
          let conclusion = gml_rules premise in
    
          (* conclusion is a set of rules, *each* of the form \/ /\ lit *)
    
          let handleRuleConcl rc acc =
            let handleConjunction conj =
                let res = bsetMake () in
                List.iter (fun (f,positive) ->
                            let f = lfFromInt f in
                            let f = if positive then f else
                                        match lfGetNeg sort f with
                                        | Some nf -> nf
                                        | None -> raise (CoAlgFormula.CoAlgException ("Negation of formula missing"))
                                        in
                            bsetAdd res f)
                          conj;
                (s1,res)
            in
            let rc = List.map handleConjunction rc in
    
            ((fun bs1 -> bs),lazylistFromList rc)::acc
    
          in List.fold_right handleRuleConcl conclusion acc
      in
      let rules = S.foldBS addRule roles [] in
    
      lazylistFromList rules
    
    let mkRule_PML sort bs sl : stateExpander =
      assert (List.length sl = 1);
      let s1 = List.hd sl in (* [s1] = List.hd sl *)
      let diamonds = bsetFilter bs (fun f -> lfGetType sort f = AtLeastProbF) in
    
      let boxes = bsetFilter bs (fun f -> lfGetType sort f = LessProbFailF) in
    
      let premise: (bool*int*int*int) list =
        let modality isDiamond m acc =
            let nominator   = lfGetDestNum sort m in
            let denominator = lfGetDestNum2 sort m in
    
            let nestedFormula = lfToInt (lfGetDest1 sort m) in
            (*print_endline ("putting formula "^(string_of_int nestedFormula)); *)
            (isDiamond,nominator,denominator,nestedFormula)::acc
    
        in
        List.append
            (bsetFold (modality true) diamonds [])
            (bsetFold (modality false) boxes [])
      in
      let conclusion = pml_rules premise in
      let error message = raise (CoAlgFormula.CoAlgException message) in
      (* conclusion is a set of rules, *each* of the form \/ /\ lit *)
      let handleRuleConcl rc acc =
        let handleConjunction conj =
            let res = bsetMake () in
    
            let handleLiteral = fun (f_int,positive) -> begin
                        let f = lfFromInt f_int in
    
                        let f = if positive
                                then f
    
                                else begin
                                    (*print_endline ("getting "^(string_of_int f_int)); *)
                                    match lfGetNeg sort f with
    
                                     | Some nf -> nf
                                     | None -> error ("Negation of formula missing")
    
                                end
                                in
                        bsetAdd res f
                        end
    
            in
            List.iter handleLiteral conj;
            (s1,res)
        in
        let rc = List.map handleConjunction rc in
        ((fun bs1 -> bs),lazylistFromList rc)::acc
      in
      let rules = List.fold_right handleRuleConcl conclusion [] in
      lazylistFromList rules
    
    
    (* constant functor *)
    let mkRule_Const colors sort bs sl : stateExpander =
      assert (List.length sl = 1);    (* just one (formal) argument *)
      let helper (f:localFormula)  (pos, neg) =
        let col = lfGetDest3 sort f in
        match (lfGetType sort f) with
          |  ConstnF -> (pos, (col::neg))
          |  ConstF  -> ((col::pos), neg)
          |  _       -> (pos, neg)
      in
      let (pos, neg) = bsetFold helper bs ([], []) in (* pos/neg literals *) 
      let clash = List.exists (fun l -> List.mem l pos) neg in (* =a /\ ~ = a *)
      let allneg = List.length colors = List.length neg in
      let twopos = List.length pos > 1 in
      let rules = if (clash || allneg || twopos) 
    
                  then [((fun x -> bs), lazylistFromList [])]  (* no backjumping *)
    
                  else []
      in 
      lazylistFromList rules
    
    
    let mkRule_Identity sort bs sl : stateExpander = 
      assert (List.length sl = 1); (* Identity has one argument *)
      let s1 = List.hd sl in
      let dep bsl = (* return arguments prefixed with identity operator *)
        assert (List.length bsl = 1);
        let bs1 = List.hd bsl in
        let res = bsetMake () in
        let filterFkt f =
          if lfGetType sort f = IdF &&
            bsetMem bs1 (lfGetDest1 sort f)
          then bsetAdd res f
          else ()
        in
        bsetIter filterFkt bs;
        res
      in
      let bs1 = bsetMake () in
      let getRule f =
        if lfGetType sort f = IdF 
        then bsetAdd bs1 (lfGetDest1 sort f)
        else ()
      in
      bsetIter getRule bs;
      lazylistFromList [(dep, lazylistFromList [(s1, bs1)])]
    
    
    let mkRule_DefaultImplication sort bs sl : stateExpander =
      raise (CoAlgFormula.CoAlgException ("Default Implication Not yet implemented."))
      
    
    let mkRule_Choice sort bs sl : stateExpander =
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
      assert (List.length sl = 2);
      let dep bsl =
        assert (List.length bsl = 2);
        let bs1 = List.nth bsl 0 in
        let bs2 = List.nth bsl 1 in
        let res = bsetMake () in
        let filterFkt f =
          if lfGetType sort f = ChcF &&
            (bsetMem bs1 (lfGetDest1 sort f) || bsetMem bs2 (lfGetDest2 sort f))
          then bsetAdd res f
          else ()
        in
        bsetIter filterFkt bs;
        res
      in
      let bs1 = bsetMake () in
      let bs2 = bsetMake () in
      let getRule f =
        if lfGetType sort f = ChcF then begin
          bsetAdd bs1 (lfGetDest1 sort f);
          bsetAdd bs2 (lfGetDest2 sort f)
        end else ()
      in
      bsetIter getRule bs;
      let s1 = List.nth sl 0 in
      let s2 = List.nth sl 1 in
    
      lazylistFromList [(dep, lazylistFromList [(s1, bs1); (s2, bs2)])]
    
    let mkRule_Fusion sort bs sl : stateExpander =
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
      assert (List.length sl = 2);
      let dep proj bsl =
        assert (List.length bsl = 1);
        let bs1 = List.hd bsl in
        let res = bsetMake () in
        let filterFkt f =
          if lfGetType sort f = FusF && lfGetDest3 sort f = proj &&
            bsetMem bs1 (lfGetDest1 sort f)
          then bsetAdd res f
          else ()
        in
        bsetIter filterFkt bs;
        res
      in
      let bs1 = bsetMake () in
      let bs2 = bsetMake () in
      let getRule f =
        if lfGetType sort f = FusF then
          if lfGetDest3 sort f = 0 then bsetAdd bs1 (lfGetDest1 sort f)
          else bsetAdd bs2 (lfGetDest1 sort f)
        else ()
      in
      bsetIter getRule bs;
      let s1 = List.nth sl 0 in
      let s2 = List.nth sl 1 in
    
      lazylistFromList [(dep 0, lazylistFromList [(s1, bs1)]); (dep 1, lazylistFromList [(s2, bs2)])]
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
    
    
    (* Maps a logic represented by the type "functors" to the corresponding
       "plug-in" function.
     *)
    let getExpandingFunctionProducer = function
    
      | MultiModalK -> mkRule_MultiModalK
    
      | MultiModalKD -> mkRule_MultiModalKD
    
      | CoalitionLogic -> mkRule_CL
    
      | GML -> mkRule_GML
    
      | PML -> mkRule_PML
    
      | Constant colors -> mkRule_Const colors
    
      | Identity -> mkRule_Identity
      | DefaultImplication -> mkRule_DefaultImplication
    
    Thorsten Wißmann's avatar
    Thorsten Wißmann committed
      | Choice -> mkRule_Choice
      | Fusion -> mkRule_Fusion