(**************************************************************************) (* *) (* Ocamlgraph: a generic graph library for OCaml *) (* Copyright (C) 2004-2007 *) (* Sylvain Conchon, Jean-Christophe Filliatre and Julien Signoles *) (* *) (* This software is free software; you can redistribute it and/or *) (* modify it under the terms of the GNU Library General Public *) (* License version 2, with the special exception on linking *) (* described in file LICENSE. *) (* *) (* This software is distributed in the hope that it will be useful, *) (* but WITHOUT ANY WARRANTY; without even the implied warranty of *) (* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *) (* *) (**************************************************************************) (* $Id:$ *) (* Signature for graphs *) module type G = sig type t module V : Sig.ORDERED_TYPE type vertex = V.t val mem_vertex : t -> vertex -> bool val succ : t -> vertex -> vertex list val fold_vertex : (vertex -> 'a -> 'a) -> t -> 'a -> 'a val fold_succ : (vertex -> 'a -> 'a) -> t -> vertex -> 'a -> 'a end (* Signature for graph add-ons: an initial vertex, final vertices and membership of vertices to either true or false, i.e. first or second player *) module type PLAYER = sig type t type vertex val get_initial : t -> vertex val is_final : t -> vertex -> bool val turn : t -> vertex -> bool end (* Signature for strategies : for a given state, the strategy tells which state to go to *) module type STRAT = sig type t type vertex val empty : t val add : t -> vertex -> vertex -> t val next : t -> vertex -> vertex (* Raises Invalid_argument if vertex's image is not defined *) end (* Implements strategy algorithms on graphs *) module Algo (G : G) (P : PLAYER with type vertex = G.vertex) (S : STRAT with type vertex = G.vertex) : sig (* coherent_player g p returns true iff the completion p is coherent w.r.t. the graph g *) val coherent_player : G.t -> P.t -> bool (* coherent_strat g s returns true iff the strategy s is coherent w.r.t. the graph g *) val coherent_strat : G.t -> S.t -> bool (* game g p a b returns true iff a wins in g given the completion p (i.e. the game goes through a final state). *) val game : G.t -> P.t -> S.t -> S.t -> bool (* strategy g p s returns true iff s wins in g given the completion p, whatever strategy plays the other player. *) val strategy : G.t -> P.t -> S.t -> bool (* strategyA g p returns true iff there exists a winning stragegy for the true player. In this case, the winning strategy is provided. *) val strategyA : G.t -> P.t -> (bool * S.t) end = struct module SetV = Set.Make (G.V) let rec eq l1 l2 = match l1, l2 with [], [] -> true | e1 :: l1', e2 :: l2' -> (e1 = e2) && (eq l1' l2') | _ -> false let rec eq_mem i l1 l2 = match l1, l2 with [], [] -> (true, false) | e1 :: l1', e2 :: l2' -> if e1 = e2 then if e1 = i then (eq l1' l2', true) else eq_mem i l1' l2' else (false, false) | _ -> (false, false) let puit g v = match G.succ g v with [] -> true | _ -> false let get_finals g p = let f a l = if P.is_final p a then a :: l else l in G.fold_vertex f g [] let coherent_player g p = G.mem_vertex g (P.get_initial p) let coherent_strat g s = let f v b = try let v' = S.next s v in b && (G.mem_vertex g v') with Invalid_argument _ -> true in G.fold_vertex f g true let game g p a b = let rec game_aux l pi = let continue x = try game_aux (SetV.add pi l) (S.next x pi) with Invalid_argument _ -> false in (P.is_final p pi) || (if SetV.mem pi l then false else if P.turn p pi then continue a else continue b) in game_aux SetV.empty (P.get_initial p) let rec attract1 g p s l = let f v l1 = if not (List.mem v l1) then if P.turn p v then try if List.mem (S.next s v) l1 then v :: l1 else l1 with Invalid_argument _ -> l1 else if puit g v then l1 else if G.fold_succ (fun v' b -> b && (List.mem v' l1)) g v true then v :: l1 else l1 else l1 in G.fold_vertex f g l let rec strategy g p s = let rec strategy_aux l1 l2 = let (b1, b2) = eq_mem (P.get_initial p) l1 l2 in if b1 then b2 else strategy_aux (attract1 g p s l1) l1 in let finaux = get_finals g p in strategy_aux (attract1 g p s finaux) finaux let rec attract g p (l, l') = let f v (l1, l1') = if not (List.mem v l1) then if P.turn p v then let f' v' l2 = (match l2 with [] -> if List.mem v' l1 then [v'] else [] | _ -> l2) in (match G.fold_succ f' g v [] with [] -> (l1, l1') | v' :: _ -> (v :: l1, S.add l1' v v' )) else if puit g v then (l1, l1') else if G.fold_succ (fun v' b -> b && (List.mem v' l1)) g v true then (v :: l1, l1') else (l1, l1') else (l1, l1') in G.fold_vertex f g (l, l') let rec strategyA g p = let rec strategyA_aux l1 l2 f = let (b1, b2) = eq_mem (P.get_initial p) l1 l2 in if b1 then (b2, f) else let (new_l1, new_f) = attract g p (l1, f) in strategyA_aux new_l1 l1 new_f in let finaux = get_finals g p in let (l, r) = attract g p (finaux, S.empty) in strategyA_aux l finaux r;; end