toss-devel-svn Mailing List for Toss (Page 10)
Status: Beta
Brought to you by:
lukaszkaiser
You can subscribe to this list here.
2010 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(25) |
Dec
(62) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2011 |
Jan
(26) |
Feb
(38) |
Mar
(67) |
Apr
(22) |
May
(41) |
Jun
(30) |
Jul
(24) |
Aug
(32) |
Sep
(29) |
Oct
(34) |
Nov
(18) |
Dec
(2) |
2012 |
Jan
(19) |
Feb
(25) |
Mar
(16) |
Apr
(2) |
May
(18) |
Jun
(21) |
Jul
(11) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <luk...@us...> - 2011-08-04 03:58:43
|
Revision: 1524 http://toss.svn.sourceforge.net/toss/?rev=1524&view=rev Author: lukstafi Date: 2011-08-04 03:58:35 +0000 (Thu, 04 Aug 2011) Log Message: ----------- GDL translation bugfixing: detect turn based games using random playouts (minor commit). Modified Paths: -------------- trunk/Toss/GGP/GDL.ml trunk/Toss/GGP/GDLTest.ml trunk/Toss/GGP/TranslateGame.ml trunk/Toss/GGP/TranslateGameTest.ml trunk/Toss/www/reference/reference.tex Modified: trunk/Toss/GGP/GDL.ml =================================================================== --- trunk/Toss/GGP/GDL.ml 2011-08-03 14:57:48 UTC (rev 1523) +++ trunk/Toss/GGP/GDL.ml 2011-08-04 03:58:35 UTC (rev 1524) @@ -577,14 +577,15 @@ raise Playout_over) else let step = saturate (does @ base) rules in - let step = Aux.map_some (function ("next", [|arg|]) -> Some arg - | _ -> None) step in + let step_state = Aux.map_some + (function ("next", [|arg|]) -> Some arg + | _ -> None) step in if !playout_fixpoint && (* fixpoint reached *) List.for_all (function | Func (_,[|arg|]) when Aux.array_existsi (fun _ player -> arg=player) players -> true | term -> List.mem term current - ) step + ) step_state then ( (* {{{ log entry *) if !debug_level > 0 then ( @@ -592,8 +593,17 @@ ); (* }}} *) raise Playout_over) + else if not aggregate && (* terminal position reached *) + List.mem_assoc "terminal" step + then ( + (* {{{ log entry *) + if !debug_level > 0 then ( + Printf.printf "GDL.ply: playout over due to terminal position\n%!"; + ); + (* }}} *) + raise Playout_over) else - List.map snd does, step + List.map snd does, step_state (* Besides the playout, also return the separation of rules into static and dynamic. Note that the list of playout states is Modified: trunk/Toss/GGP/GDLTest.ml =================================================================== --- trunk/Toss/GGP/GDLTest.ml 2011-08-03 14:57:48 UTC (rev 1523) +++ trunk/Toss/GGP/GDLTest.ml 2011-08-04 03:58:35 UTC (rev 1524) @@ -23,7 +23,7 @@ let descr = GDLParser.parse_game_description KIFLexer.lex (Lexing.from_channel f) in - (* List.map GDL.rule_of_entry *) descr + descr let emb_str (game, state) (rname, emb) = let r = List.assoc rname game.Arena.rules in @@ -104,7 +104,7 @@ (List.map GDL.rel_atom_str res)); ); - "playout" >:: + "playout simple" >:: (fun () -> let descr = parse_game_descr " @@ -156,6 +156,27 @@ (does o (mark b a)) (does x noop)"]) ); + "playout connect5" >:: + (fun () -> + let descr = load_rules ("./GGP/examples/connect5.gdl") in + + let _, _, _, _, (rand_actions, _) = + GDL.playout ~aggregate:false [|GDL.Const "x"; GDL.Const "o"|] + 10 (Aux.concat_map GDL.rules_of_clause descr) in + let noop_actions = Aux.take_n 9 + (List.map + (Aux.map_some + (function [|player; Const "noop"|] -> Some player + | _ -> None)) rand_actions) in + let res = + String.concat "; " + (List.map (fun pacts -> String.concat ", " + (List.map term_str pacts)) noop_actions) in + assert_equal ~msg:"connect5 noop moves by players" + ~printer:(fun x->x) + "o; x; o; x; o; x; o; x; o" res; + ); + ] let exec = Aux.run_test_if_target "GDLTest" tests Modified: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml 2011-08-03 14:57:48 UTC (rev 1523) +++ trunk/Toss/GGP/TranslateGame.ml 2011-08-04 03:58:35 UTC (rev 1524) @@ -283,6 +283,7 @@ let elem_term_map = Aux.intmap_of_assoc (List.map (fun e -> Structure.find_elem struc (term_to_name e), e) element_reps) in + players, rules, next_clauses, f_paths, m_paths, mask_reps, defined_rels, !stable_rels, !fluents, stable_base, init_state, struc, agg_actions, elem_term_map @@ -629,73 +630,90 @@ (* Check if game is turn based and return the player cycle if it is, otherwise rise [Not_turn_based]. Also return the [noop] actions for players in the locations. *) -let check_turn_based players agg_actions = - let noop_cands = List.map (fun actions -> - let actions = Aux.map_reduce - (function [|player; action|] -> player, action - | _ -> assert false) (fun y x->x::y) [] actions in - List.map (function - | player, [Const _ as noop] -> player, Some noop - | player, _ -> player, None) actions - ) agg_actions in - let control_cands = List.map (fun noop_cands -> - List.fold_left (fun accu -> function - | player, None -> - if accu = None then Some player - else raise Not_turn_based - | _, Some _ -> accu) None noop_cands) noop_cands in - let noop_cands = List.map Aux.collect noop_cands in +let check_turn_based players rules = + let check_one_playout () = + let _, _, _, _, (playout_actions, _) = + playout ~aggregate:false players !agg_playout_horizon rules in + let noop_cands = List.map (fun actions -> + let actions = Aux.map_reduce + (function [|player; action|] -> player, action + | _ -> assert false) (fun y x->x::y) [] actions in + List.map (function + | player, [Const _ as noop] -> player, Some noop + | player, _ -> player, None) actions + ) playout_actions in + let control_cands = List.map (fun noop_cands -> + List.fold_left (fun accu -> function + | player, None -> + if accu = None then Some player + else raise Not_turn_based + | _, Some _ -> accu) None noop_cands) noop_cands in + let noop_cands = List.map Aux.collect noop_cands in (* throw in players with (multiple) constant actions *) - let control_noop_cands = List.map2 (fun ccand noops -> - let nccands, noops = Aux.partition_map - (function player, [] -> assert false - | player, [noop] -> Aux.Right (player, noop) - | player, more_actions -> Aux.Left player) noops in - match ccand, nccands with - | None, [player] -> Some player, noops - | Some _, [] -> ccand, noops - | _ -> raise Not_turn_based - ) control_cands noop_cands in - let control_cands, noop_cands = - List.split control_noop_cands in + let control_noop_cands = List.map2 (fun ccand noops -> + let nccands, noops = Aux.partition_map + (function player, [] -> assert false + | player, [noop] -> Aux.Right (player, noop) + | player, more_actions -> Aux.Left player) noops in + match ccand, nccands with + | None, [player] -> Some player, noops + | Some _, [] -> ccand, noops + | _ -> raise Not_turn_based + ) control_cands noop_cands in + let control_cands, noop_cands = + List.split control_noop_cands in + (* {{{ log entry *) + if !debug_level > 1 then ( + Printf.printf "check_turn_based: control player cands %s\n%!" + (String.concat " " + (List.map (function Some t->term_str t | None->"None") + control_cands)) + ); + (* }}} *) (* 2b *) - let loc_players = find_cycle control_cands in + let loc_players = find_cycle control_cands in (* {{{ log entry *) - if !debug_level > 0 then ( - Printf.printf "check_turn_based: location players %s\n%!" - (String.concat " " - (List.map (function Some t->term_str t | None->"None") - loc_players)) - ); + if !debug_level > 0 then ( + Printf.printf "check_turn_based: location players %s\n%!" + (String.concat " " + (List.map (function Some t->term_str t | None->"None") + loc_players)) + ); (* }}} *) - let loc_players = Array.of_list - (List.map (function Some p -> p | None -> players.(0)) - loc_players) in - let loc_n = Array.length loc_players in - let players_n = Array.length players in - let find_player p = Aux.array_argfind (fun x -> x = p) players in + let loc_players = Array.of_list + (List.map (function Some p -> p | None -> players.(0)) + loc_players) in + let loc_n = Array.length loc_players in + let players_n = Array.length players in + let find_player p = Aux.array_argfind (fun x -> x = p) players in (* noop actions of a player in a location *) - let loc_noops = - let i = ref 0 in - let noops = ref noop_cands in - let loc_noops = Array.make_matrix loc_n players_n None in - while !noops <> [] do - List.iter (function _, None -> () - | player, (Some _ as noop) -> - let p_i = find_player player in - if loc_noops.(!i).(p_i) = None - then loc_noops.(!i).(p_i) <- noop - else if loc_noops.(!i).(p_i) <> noop + let loc_noops = + let i = ref 0 in + let noops = ref noop_cands in + let loc_noops = Array.make_matrix loc_n players_n None in + while !noops <> [] do + List.iter (function _, None -> () + | player, (Some _ as noop) -> + let p_i = find_player player in + if loc_noops.(!i).(p_i) = None + then loc_noops.(!i).(p_i) <- noop + else if loc_noops.(!i).(p_i) <> noop (* moves are not simultaneous, but different [noop] actions are used by the same player -- can be resolved by introducing separate locations for each noop case *) - then raise Not_turn_based) - (List.hd !noops); - incr i; if !i = loc_n then i := 0; - noops := List.tl !noops - done; - loc_noops in - loc_players, loc_noops + then raise Not_turn_based) + (List.hd !noops); + incr i; if !i = loc_n then i := 0; + noops := List.tl !noops + done; + loc_noops in + loc_players, loc_noops in + (* doing the playouts "a couple" = 3 times *) + let data1 = check_one_playout () in + let data2 = check_one_playout () in + let data3 = check_one_playout () in + if data1 = data2 && data1 = data3 then data1 + else raise Not_turn_based let build_toss_rule transl_data rule_names struc fluents @@ -946,17 +964,13 @@ let translate_game ~playing_as clauses = let clauses = expand_players clauses in let used_vars, clauses = rename_clauses clauses in - let next_cls, f_paths, m_paths, mask_reps, defined_rels, + let players, rules, + next_cls, f_paths, m_paths, mask_reps, defined_rels, stable_rels, fluents, stable_base, init_state, struc, agg_actions, elem_term_map = create_init_struc clauses in - let players = Array.of_list - (Aux.map_some (function - | ("role", [|player|]), _ -> Some player - | _ -> None - ) clauses) in let turn_data = - try Some (check_turn_based players agg_actions) + try Some (check_turn_based players rules) with Not_turn_based -> None in let rule_cands, is_concurrent = create_rule_cands (turn_data <> None) used_vars next_cls clauses in Modified: trunk/Toss/GGP/TranslateGameTest.ml =================================================================== --- trunk/Toss/GGP/TranslateGameTest.ml 2011-08-03 14:57:48 UTC (rev 1523) +++ trunk/Toss/GGP/TranslateGameTest.ml 2011-08-04 03:58:35 UTC (rev 1524) @@ -23,7 +23,7 @@ let descr = GDLParser.parse_game_description KIFLexer.lex (Lexing.from_channel f) in - (* List.map GDL.rule_of_entry *) descr + descr let emb_str (game, state) (rname, emb) = let r = List.assoc rname game.Arena.rules in @@ -171,7 +171,7 @@ ] let a () = - (* GDL.debug_level := 5; *) + (* GDL.debug_level := 2; *) TranslateGame.debug_level := 4; GameSimpl.debug_level := 4; (* DiscreteRule.debug_level := 4; *) Modified: trunk/Toss/www/reference/reference.tex =================================================================== --- trunk/Toss/www/reference/reference.tex 2011-08-03 14:57:48 UTC (rev 1523) +++ trunk/Toss/www/reference/reference.tex 2011-08-04 03:58:35 UTC (rev 1524) @@ -2110,16 +2110,16 @@ attempting a complex analysis to detect as many turn-based games as possible, we recognize some cases where in all states, all players but one have a single legal move that is a constant (term of size -one). Such move is conventionally called \texttt{noop}. We simply -check what moves are available to players in the states of the -aggregate playout. Due to the character of aggregate playout, we only -handle the case where the alternation of control forms a cycle -(players do not need to strictly alternate, for example a -single-player game is also a turn-based game, as another example in a -three-player game the first player may intersperse the moves of second -and third player). We build a corresponding cyclic graph of Toss -locations. We limit the turn-based translation to the case where all -rule clauses have exactly one \texttt{does} atom (\ie can be +one). Such move is conventionally called \texttt{noop}. In the current +implementation we simply check what moves are available to players in +the states of a couple of random playouts, so the detection is +unsound. We only handle the case where the alternation of control +forms a cycle (players do not need to strictly alternate, for example +a single-player game is also a turn-based game, as another example in +a three-player game the first player may intersperse the moves of +second and third player). We build a corresponding cyclic graph of +Toss locations. We limit the turn-based translation to the case where +all rule clauses have exactly one \texttt{does} atom (\ie can be attributed to exactly one of the players). \subsubsection{Concurrent Moves Games} \label{par-concurrent-moves} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-08-03 14:57:54
|
Revision: 1523 http://toss.svn.sourceforge.net/toss/?rev=1523&view=rev Author: lukstafi Date: 2011-08-03 14:57:48 +0000 (Wed, 03 Aug 2011) Log Message: ----------- GDL translation bugfixing started: [rules_of_clause] disjunction distribution fix; (both aggregate and) random playouts; GDL tests. Modified Paths: -------------- trunk/Toss/GGP/GDL.ml trunk/Toss/GGP/GDL.mli trunk/Toss/GGP/GDLTest.ml trunk/Toss/GGP/TranslateGame.ml trunk/Toss/GGP/TranslateGame.mli trunk/Toss/GGP/TranslateGameTest.ml Modified: trunk/Toss/GGP/GDL.ml =================================================================== --- trunk/Toss/GGP/GDL.ml 2011-07-31 22:11:24 UTC (rev 1522) +++ trunk/Toss/GGP/GDL.ml 2011-08-03 14:57:48 UTC (rev 1523) @@ -10,8 +10,8 @@ open Aux.BasicOperators let debug_level = ref 0 -let aggregate_drop_negative = ref false -let aggregate_fixpoint = ref true +let aggregate_drop_negative = ref true +let playout_fixpoint = ref true type term = | Const of string @@ -104,14 +104,14 @@ | "does", [|arg1; arg2|] -> Does (arg1, arg2) | rel, args -> Rel (rel, args) -let rec body_of_literal = function +let rec bodies_of_literal = function | Pos (Distinct args) -> [Aux.Right ("distinct", args)] (* not negated actually! *) | Neg (Distinct _) -> assert false | Pos atom -> [Aux.Left (rel_of_atom atom)] | Neg atom -> [Aux.Right (rel_of_atom atom)] | Disj disjs -> - Aux.concat_map body_of_literal disjs + Aux.concat_map bodies_of_literal disjs let func_graph f terms = Aux.map_some (function Func (g, args) when f=g -> Some args | _-> None) terms @@ -135,13 +135,17 @@ (Aux.concat_map (fun (hd,body,neg_body) -> ("",hd)::body @ neg_body) (Aux.concat_map snd defs)) -let rule_of_clause (head, body) = - let body, neg_body = - Aux.partition_choice (Aux.concat_map body_of_literal body) in - head, body, neg_body +let rules_of_clause (head, body) = + let bodies = Aux.product + (List.map bodies_of_literal body) in + let bodies = List.map Aux.partition_choice bodies in + List.map (fun (body, neg_body) -> head, body, neg_body) + bodies -let clause_vars cl = gdl_rule_vars (rule_of_clause cl) +let clause_vars cl = + List.fold_left Aux.Strings.union Aux.Strings.empty + (List.map gdl_rule_vars (rules_of_clause cl)) let defs_of_rules rules = Aux.map_reduce (fun ((rel, args), body, neg_body) -> @@ -465,7 +469,7 @@ let negate_bodies conjs = let placeholder = "", [] in let clauses = List.map (fun body -> placeholder, body) conjs in - let clauses = List.map rule_of_clause clauses in + let clauses = Aux.concat_map rules_of_clause clauses in let clauses = List.map (fun (_,body,neg_body) -> List.map (fun a -> Pos (atom_of_rel a)) body @ List.map (fun a -> Neg (atom_of_rel a)) neg_body) clauses in @@ -525,24 +529,32 @@ (* ************************************************************ *) (** {3 GDL whole-game operations.} - Aggregate playout, player-denoting variable elimination. *) + Aggregate and random playouts, player-denoting variable elimination. *) -(* Collect the aggregate playout, but also the actions available in - the state. *) +(* Collect the playout, but also the actions available in the + state. *) exception Playout_over -let aggregate_ply players static current rules = +(* [~aggregate:true] performs an aggregate ply, [~aggregate:false] + performs a random ply. *) +let ply ~aggregate players static current rules = let base = Aux.map_prepend static (fun term -> "true", [|term|]) current in let base = saturate (base @ static) rules in (* {{{ log entry *) if !debug_level > 4 then ( - Printf.printf "GDL.aggregate_ply: updated base -- %s\n%!" + Printf.printf "GDL.ply: updated base -- %s\n%!" (rel_atoms_str base) ); (* }}} *) let does = Aux.map_some (fun (rel, args) -> if rel = "legal" then Some ("does", args) else None) base in + let does = + if aggregate then does + else + List.map (Aux.random_elem -| snd) + (Aux.collect (List.map (fun (_,args as atom) -> + args.(0), atom) does)) in if (* no move *) Aux.array_existsi (fun _ player -> List.for_all (function @@ -558,7 +570,7 @@ | _ -> true) does) players in Printf.printf - "GDL.aggregate_ply: playout over due to no move for %s\n%!" + "GDL.ply: playout over due to no move for %s\n%!" (String.concat ", " (List.map term_str players_nomove)) ); (* }}} *) @@ -567,7 +579,7 @@ let step = saturate (does @ base) rules in let step = Aux.map_some (function ("next", [|arg|]) -> Some arg | _ -> None) step in - if !aggregate_fixpoint && (* fixpoint reached *) + if !playout_fixpoint && (* fixpoint reached *) List.for_all (function | Func (_,[|arg|]) when Aux.array_existsi (fun _ player -> arg=player) players -> true @@ -576,17 +588,26 @@ then ( (* {{{ log entry *) if !debug_level > 0 then ( - Printf.printf "GDL.aggregate_ply: playout over due to fixpoint\n%!"; + Printf.printf "GDL.ply: playout over due to fixpoint\n%!"; ); (* }}} *) raise Playout_over) else List.map snd does, step -(* Besides the aggregate playout, also return the separation of rules +(* Besides the playout, also return the separation of rules into static and dynamic. Note that the list of playout states is - one longer than that of playout actions. *) -let aggregate_playout players horizon rules = + one longer than that of playout actions. + + When [aggregate_drop_negative] is true, to keep monotonicity, + besides removing negative literals from "legal" clauses, we also + add old terms to the state. (Only when [~aggregate:true].) + + [~aggregate:true] performs an aggregate ply, [~aggregate:false] + performs a random ply. Aggregate playouts are "deprecated", + especially for uses other than generating all possible state + terms. *) +let playout ~aggregate players horizon rules = (* separate and precompute the static part *) let rec separate static_rels state_rels = let static, more_state = @@ -607,24 +628,28 @@ List.map (function | ("legal", [|player; _|] as head), body, neg_body -> head, ("role", [|player|])::body, - if !aggregate_drop_negative then [] else neg_body + if aggregate && !aggregate_drop_negative + then [] else neg_body | ("does", _ (* as head *)), body, _ -> assert false (* head, body, [] *) | rule -> rule) dynamic_rules in let rec loop actions_accu state_accu step state = (* {{{ log entry *) if !debug_level > 0 then ( - Printf.printf "aggregate_playout: step %d...\n%!" step + Printf.printf "playout: step %d...\n%!" step ); (* }}} *) (let try actions, next = - aggregate_ply players static_base state state_rules in + ply ~aggregate players static_base state state_rules in (* {{{ log entry *) if !debug_level > 0 then ( - Printf.printf "aggregate_playout: state %s\n%!" + Printf.printf "playout: state %s\n%!" (String.concat " " (List.map term_str next)) ); (* }}} *) + let next = + if aggregate && !aggregate_drop_negative then state @ next + else next in if step < horizon then loop (actions::actions_accu) (state::state_accu) (step+1) next else @@ -639,7 +664,7 @@ | _ -> None) init_base in (* {{{ log entry *) if !debug_level > 0 then ( - Printf.printf "aggregate_playout: init %s\n%!" + Printf.printf "playout: init %s\n%!" (String.concat " " (List.map term_str init_state)) ); (* }}} *) @@ -647,6 +672,7 @@ loop [] [] 0 init_state + let find_cycle cands = (* {{{ log entry *) if !debug_level > 0 then ( Modified: trunk/Toss/GGP/GDL.mli =================================================================== --- trunk/Toss/GGP/GDL.mli 2011-07-31 22:11:24 UTC (rev 1522) +++ trunk/Toss/GGP/GDL.mli 2011-08-03 14:57:48 UTC (rev 1523) @@ -3,7 +3,7 @@ val debug_level : int ref val aggregate_drop_negative : bool ref -val aggregate_fixpoint : bool ref +val playout_fixpoint : bool ref (** {3 Datalog programs: Type definitions and saturation.} *) @@ -54,7 +54,7 @@ val clause_vars : clause -> Aux.Strings.t val defs_of_rules : gdl_rule list -> gdl_defs -val rule_of_clause : clause -> gdl_rule +val rules_of_clause : clause -> gdl_rule list val nnf_dnf : literal list -> literal list list @@ -70,6 +70,10 @@ val subst_literals : substitution -> literal list -> literal list val subst_clause : substitution -> clause -> clause +(** Saturation currently exposed for testing purposes. *) +val saturate : + rel_atom list -> gdl_rule list -> rel_atom list + (** {3 Transformations of GDL clauses: inlining, negation.} *) (** Expand branches of a definition inlining the provided definitions, @@ -99,9 +103,11 @@ val state_terms : literal list -> term list val term_arities : term -> (string * int) list +val rel_atom_str : rel_atom -> string + (** {3 GDL whole-game operations.} - Aggregate playout, player-denoting variable elimination. *) + Aggregate and random playout, player-denoting variable elimination. *) (** Partition relations into stable (not depending, even indirectly, on "true") and remaining ones. *) @@ -110,9 +116,18 @@ (** Besides the aggregate playout, also return the separation of rules into static and dynamic. Note that the list of playout states is - one longer than that of playout actions. *) -val aggregate_playout : - term array -> int -> gdl_rule list -> + one longer than that of playout actions. + + When [aggregate_drop_negative] is true, to keep monotonicity, + besides removing negative literals from "legal" clauses, we also + add old terms to the state. (Only when [~aggregate:true].) + + [~aggregate:true] performs an aggregate ply, [~aggregate:false] + performs a random ply. Aggregate playouts are "deprecated", + especially for uses other than generating all possible state + terms. *) +val playout : + aggregate:bool -> term array -> int -> gdl_rule list -> gdl_rule list * gdl_rule list * rel_atom list * term list * (term array list list * term list list) Modified: trunk/Toss/GGP/GDLTest.ml =================================================================== --- trunk/Toss/GGP/GDLTest.ml 2011-07-31 22:11:24 UTC (rev 1522) +++ trunk/Toss/GGP/GDLTest.ml 2011-08-03 14:57:48 UTC (rev 1523) @@ -46,7 +46,7 @@ let tests = "GDL" >::: [ -(* "saturate" >:: + "saturate" >:: (fun () -> let descr = parse_game_descr " @@ -58,11 +58,11 @@ (theta scisors) (gamma scisors)" in (* GDL.debug_level := 3; *) let res = GDL.saturate [] - (Aux.concat_map GDL.rules_of_entry descr) in + (Aux.concat_map GDL.rules_of_clause descr) in assert_equal ~printer:(fun x->x) ~msg:"simple stratified" "(alpha paper) (alpha rock) (beta paper) (beta rock) (beta scisors) (gamma paper) (gamma scisors) (theta scisors) (zeta rock)" (String.concat " " - (List.map GDL.fact_str res)); + (List.map GDL.rel_atom_str res)); let descr = parse_game_descr " @@ -70,11 +70,11 @@ (a 1) (a 2) (a 3)" in (* GDL.debug_level := 3; *) let res = GDL.saturate [] - (Aux.concat_map GDL.rules_of_entry descr) in + (Aux.concat_map GDL.rules_of_clause descr) in assert_equal ~printer:(fun x->x) ~msg:"simple distinct" "(a 1) (a 2) (a 3) (two-of-three 1 2) (two-of-three 1 3) (two-of-three 2 1) (two-of-three 2 3) (two-of-three 3 1) (two-of-three 3 2)" (String.concat " " - (List.map GDL.fact_str res)); + (List.map GDL.rel_atom_str res)); ); "saturate recursive" >:: @@ -97,12 +97,65 @@ " in (* GDL.debug_level := 3; *) let res = GDL.saturate [] - (Aux.concat_map GDL.rules_of_entry descr) in + (Aux.concat_map GDL.rules_of_clause descr) in assert_equal ~printer:(fun x->x) ~msg:"simple stratified" "(lte 0 0) (lte 0 1) (lte 0 2) (lte 0 3) (lte 0 4) (lte 0 5) (lte 0 6) (lte 0 7) (lte 0 8) (lte 1 1) (lte 1 2) (lte 1 3) (lte 1 4) (lte 1 5) (lte 1 6) (lte 1 7) (lte 1 8) (lte 2 2) (lte 2 3) (lte 2 4) (lte 2 5) (lte 2 6) (lte 2 7) (lte 2 8) (lte 3 3) (lte 3 4) (lte 3 5) (lte 3 6) (lte 3 7) (lte 3 8) (lte 4 4) (lte 4 5) (lte 4 6) (lte 4 7) (lte 4 8) (lte 5 5) (lte 5 6) (lte 5 7) (lte 5 8) (lte 6 6) (lte 6 7) (lte 6 8) (lte 7 7) (lte 7 8) (lte 8 8) (number 0) (number 1) (number 2) (number 3) (number 4) (number 5) (number 6) (number 7) (number 8) (succ 0 1) (succ 1 2) (succ 2 3) (succ 3 4) (succ 4 5) (succ 5 6) (succ 6 7) (succ 7 8)" (String.concat " " - (List.map GDL.fact_str res)); - ); *) + (List.map GDL.rel_atom_str res)); + ); + + "playout" >:: + (fun () -> + let descr = parse_game_descr + " +(role x) +(role o) +(init (cell a a b)) +(init (cell b a b)) +(init (control x)) +(<= (next (control ?r)) + (does ?r noop)) +(<= (next (cell ?x ?y ?r)) + (does ?r (mark ?x ?y))) +(<= (next (cell ?x ?y ?c)) + (true (cell ?x ?y ?c)) + (does ?r (mark ?x1 ?y1)) + (or (distinct ?x ?x1) + (distinct ?y ?y1))) +(<= (legal ?r (mark ?x ?y)) + (true (control ?r)) + (true (cell ?x ?y b)) + ) +(<= (legal ?r noop) + (role ?r) + (not (true (control ?r)))) +" in + + let _, _, _, _, (agg_actions, _) = + GDL.playout ~aggregate:true [|GDL.Const "x"; GDL.Const "o"|] + 10 (Aux.concat_map GDL.rules_of_clause descr) in + let actions = List.map (List.map (fun a->"does", a)) agg_actions in + assert_equal ~printer:(fun x->x) ~msg:"aggregate" + "(does o noop) (does x noop) (does x (mark a a)) (does x (mark b a)); +(does o noop) (does o (mark a a)) (does o (mark b a)) (does x noop) (does x (mark a a)) (does x (mark b a))" + (String.concat ";\n" (List.map (fun step -> String.concat " " + (List.map GDL.rel_atom_str step)) actions)); + + let _, _, _, _, (rand_actions, _) = + GDL.playout ~aggregate:false [|GDL.Const "x"; GDL.Const "o"|] + 10 (Aux.concat_map GDL.rules_of_clause descr) in + let actions = List.map (List.map (fun a->"does", a)) rand_actions in + let res = + String.concat ";\n" (List.map (fun step -> String.concat " " + (List.map GDL.rel_atom_str step)) actions) in + assert_bool ( + "random (see expected result in the test source): got " ^ res) + (List.mem res ["(does o noop) (does x (mark b a)); +(does o (mark a a)) (does x noop)"; +"(does o noop) (does x (mark a a)); +(does o (mark b a)) (does x noop)"]) + ); + ] let exec = Aux.run_test_if_target "GDLTest" tests Modified: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml 2011-07-31 22:11:24 UTC (rev 1522) +++ trunk/Toss/GGP/TranslateGame.ml 2011-08-03 14:57:48 UTC (rev 1523) @@ -5,6 +5,9 @@ open GDL open TranslateFormula +(** Local level of logging. *) +let debug_level = ref 0 + (** Translate stable relations that otherwise would be translated as structure relations, but have arity above the threshold, as defined relations. *) @@ -119,7 +122,7 @@ (as in definition of $\calP_f$). *) let fluent_paths_and_frames clauses = let defs = - defs_of_rules (List.map rule_of_clause clauses) in + defs_of_rules (Aux.concat_map rules_of_clause clauses) in let stable, nonstable = stable_rels defs in let inline_defs = List.filter (fun (rel,_) -> List.mem rel nonstable) defs in @@ -134,7 +137,7 @@ List.map (fun c -> (* it should actually be a single element association *) let brs_c = - List.assoc "next" (defs_of_rules [rule_of_clause c]) in + List.assoc "next" (defs_of_rules (rules_of_clause c)) in c, expand_positive_lits inline_defs brs_c) next_clauses in let find_br_fluents s_C (_,body,neg_body) = let true_args body = List.map @@ -182,10 +185,10 @@ | _ -> None ) clauses in let players = Array.of_list players in - let rules = List.map rule_of_clause clauses in + let rules = Aux.concat_map rules_of_clause clauses in let stable_rel_defs, nonstable_rel_defs, stable_base, init_state, (agg_actions, agg_states) = - aggregate_playout players !agg_playout_horizon rules in + playout ~aggregate:true players !agg_playout_horizon rules in let stable_rels = Aux.unique_sorted (List.map (fun ((rel,_),_,_)->rel) stable_rel_defs) in let nonstable_rels = Aux.unique_sorted Modified: trunk/Toss/GGP/TranslateGame.mli =================================================================== --- trunk/Toss/GGP/TranslateGame.mli 2011-07-31 22:11:24 UTC (rev 1522) +++ trunk/Toss/GGP/TranslateGame.mli 2011-08-03 14:57:48 UTC (rev 1523) @@ -1,3 +1,5 @@ +(** Local level of logging. *) +val debug_level : int ref type tossrule_data = { legal_tuple : GDL.term array; Modified: trunk/Toss/GGP/TranslateGameTest.ml =================================================================== --- trunk/Toss/GGP/TranslateGameTest.ml 2011-07-31 22:11:24 UTC (rev 1522) +++ trunk/Toss/GGP/TranslateGameTest.ml 2011-08-03 14:57:48 UTC (rev 1523) @@ -95,27 +95,6 @@ let tests = "TranslateGame" >::: [ - (* - "expand_def_rules" >:: - (fun () -> - let descr = parse_game_descr - " -(<= (alpha ?X) (beta ?X) (not (theta ?X))) -(<= (zeta ?X) (beta ?X) (not (gamma ?X))) -(<= (beta ?X) (rho ?X)) -(<= (theta ?X) (gamma ?X) (rho ?X))" in - (* GDL.debug_level := 3; *) - let res = Translate.expand_def_rules - (Aux.concat_map GDL.rules_of_entry descr) in - assert_equal ~printer:(fun x->x) ~msg:"simple stratified" - "((beta ?X) <= (rho ?X) ) -((theta ?X) <= (gamma ?X) (rho ?X) ) -((alpha ?X) <= (rho ?X) (not (and (gamma ?X) (rho ?X)))) -((zeta ?X) <= (rho ?X) (not (and (gamma ?X))))" - (String.concat "\n" - (List.map GDL.exp_def_str res)); - ); - "tictactoe" >:: (fun () -> game_test_case ~game_name:"tictactoe" ~player:"xplayer" @@ -130,7 +109,7 @@ "cell_x71_y26__blank_", "cell_1_1_MV1"; "control__blank_", "control_MV1"] ~loc1_noop:"noop" ~loc1_move:"(mark 1 1)" - ); *) + ); ] let bigtests = "TranslateGameBig" >::: [ @@ -191,20 +170,29 @@ ); ] - -let a = - Aux.run_test_if_target "TranslateGameTest" tests - -let a = - Aux.run_test_if_target "TranslateGameTest" bigtests - let a () = - GDL.debug_level := 4; - (* GameSimpl.debug_level := 4; *) + (* GDL.debug_level := 5; *) + TranslateGame.debug_level := 4; + GameSimpl.debug_level := 4; (* DiscreteRule.debug_level := 4; *) () let a () = + game_test_case ~game_name:"connect5" ~player:"x" + ~own_plnum:0 ~opponent_plnum:1 + ~loc0_rule_name:"mark_x161_y162_0" + ~loc0_emb:[ + "cell_x161_y162__blank_", "cell_e_f_MV1"; + "control__blank_", "control_MV1"] + ~loc0_move:"(mark e f)" ~loc0_noop:"noop" + ~loc1:1 ~loc1_rule_name:"mark_x175_y176_1" + ~loc1_emb:[ + "cell_x175_y176__blank_", "cell_f_g_MV1"; + "control__blank_", "control_MV1"] + ~loc1_noop:"noop" ~loc1_move:"(mark f g)" + + +let a () = match test_filter [(* "GDLBig:1:breakthrough" *) "GDLBig:0:connect5"] bigtests This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-31 22:11:30
|
Revision: 1522 http://toss.svn.sourceforge.net/toss/?rev=1522&view=rev Author: lukaszkaiser Date: 2011-07-31 22:11:24 +0000 (Sun, 31 Jul 2011) Log Message: ----------- Remember time of moves in the db. Modified Paths: -------------- trunk/Toss/Server/ReqHandler.ml trunk/Toss/WebClient/index.html Modified: trunk/Toss/Server/ReqHandler.ml =================================================================== --- trunk/Toss/Server/ReqHandler.ml 2011-07-30 17:34:24 UTC (rev 1521) +++ trunk/Toss/Server/ReqHandler.ml 2011-07-31 22:11:24 UTC (rev 1522) @@ -509,7 +509,7 @@ let move_play move_tup pid = let sel_s = game_select_s pid in let old_res= List.hd (dbtable sel_s "cur_states") in - let (g, p1, p2, m, old_toss, old_loc, old_info, old_svg) = + let (g, p1, p2, m, old_toss, old_loc, old_info, old_time) = (old_res.(1), old_res.(2), old_res.(3), old_res.(4), old_res.(5), old_res.(6), old_res.(7), old_res.(8)) in client_set_game (g); @@ -527,10 +527,11 @@ cur_upd ("toss='" ^ new_toss ^ "'"); cur_upd ("info='" ^ new_info_db ^ "'"); cur_upd ("loc='" ^ move3 ^ "'"); + cur_upd ("svg='" ^ string_of_float (Unix.gettimeofday ()) ^ "'"); cur_upd ("move=" ^ (string_of_int ((int_of_string m) + 1))); DB.insert_table dbFILE "old_states" "playid, game, player1, player2, move, toss, loc, info, svg" - [pid; g; p1; p2; m; old_toss; old_loc; del_q old_info; old_svg]; + [pid; g; p1; p2; m; old_toss; old_loc; del_q old_info; old_time]; new_info in let suggest player time pid = let res = List.hd (dbtable (game_select_s pid) "cur_states") in Modified: trunk/Toss/WebClient/index.html =================================================================== --- trunk/Toss/WebClient/index.html 2011-07-30 17:34:24 UTC (rev 1521) +++ trunk/Toss/WebClient/index.html 2011-07-31 22:11:24 UTC (rev 1522) @@ -177,6 +177,7 @@ <div id="news"> <h3>News</h3> <ul id="welcome-list-news" class="welcome-list"> +<li><b>31/07/11</b> Store date and time of moves in games</li> <li><b>30/07/11</b> Corrected opponent lists in the Profile tab</li> <li><b>03/07/11</b> Added game descriptions viewable when playing</li> <li><b>30/06/11</b> View previous moves in a play</li> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-30 17:34:30
|
Revision: 1521 http://toss.svn.sourceforge.net/toss/?rev=1521&view=rev Author: lukaszkaiser Date: 2011-07-30 17:34:24 +0000 (Sat, 30 Jul 2011) Log Message: ----------- Small WebClient corrections. Modified Paths: -------------- trunk/Toss/Server/ReqHandler.ml trunk/Toss/WebClient/index.html Modified: trunk/Toss/Server/ReqHandler.ml =================================================================== --- trunk/Toss/Server/ReqHandler.ml 2011-07-29 10:13:18 UTC (rev 1520) +++ trunk/Toss/Server/ReqHandler.ml 2011-07-30 17:34:24 UTC (rev 1521) @@ -564,7 +564,10 @@ let list_friends all uid = if all then List.map (fun a -> a.(0)) (dbtable "" "users") else let friends = dbtable ("id='" ^ uid ^ "'") "friends" in - List.map (fun a -> a.(1)) friends in + let friends = List.map (fun a -> a.(1)) friends in + let contacts = dbtable ("fid='" ^ uid ^ "'") "friends" in + let contacts = List.map (fun a -> a.(0)) contacts in + Aux.unique_sorted (friends @ contacts) in let open_db pid = let res = dbtable (game_select_s pid) "cur_states" in let (move, info) = ((List.hd res).(4), (List.hd res).(7)) in @@ -574,11 +577,11 @@ if res = [] then "NONE" else (List.hd res).(7) in let add_opponent uid oppid = if uid = "" then "You must login first to add opponents." else - let (name, _, _) = get_user_name_surname_mail oppid in - if name = "" then "No such opponent found among tPlay users." else ( - DB.insert_table dbFILE "friends" "id, fid" [uid; oppid]; - "OK" - ) in + let (name, _, _) = get_user_name_surname_mail oppid in + if name = "" then "No such opponent found among tPlay users." else ( + DB.insert_table dbFILE "friends" "id, fid" [uid; oppid]; + "OK" + ) in let change_user_data uid udata = if uid = "" then "You must login first to change data." else if Array.length udata <> 3 then "Internal error, data not changed." else Modified: trunk/Toss/WebClient/index.html =================================================================== --- trunk/Toss/WebClient/index.html 2011-07-29 10:13:18 UTC (rev 1520) +++ trunk/Toss/WebClient/index.html 2011-07-30 17:34:24 UTC (rev 1521) @@ -177,6 +177,7 @@ <div id="news"> <h3>News</h3> <ul id="welcome-list-news" class="welcome-list"> +<li><b>30/07/11</b> Corrected opponent lists in the Profile tab</li> <li><b>03/07/11</b> Added game descriptions viewable when playing</li> <li><b>30/06/11</b> View previous moves in a play</li> <li><b>27/06/11</b> Tabs and searching opponents in the profile page</li> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-29 10:13:24
|
Revision: 1520 http://toss.svn.sourceforge.net/toss/?rev=1520&view=rev Author: lukaszkaiser Date: 2011-07-29 10:13:18 +0000 (Fri, 29 Jul 2011) Log Message: ----------- Final small correction, TossServer runs. Modified Paths: -------------- trunk/Toss/GGP/TranslateGame.ml Modified: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml 2011-07-29 09:53:41 UTC (rev 1519) +++ trunk/Toss/GGP/TranslateGame.ml 2011-07-29 10:13:18 UTC (rev 1520) @@ -790,8 +790,8 @@ let sControl = "CONTROL__" -let loc_graph_general_int = - failwith "GDL: General Interaction Games not implemented yet" +let loc_graph_general_int = ([||], [], []), (Structure.empty_structure ()) + (* failwith "GDL: General Interaction Games not implemented yet" *) (* "environment" will the last player -- also in payoffs array. [players] are all player terms, excluding "environment"! *) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-29 09:53:52
|
Revision: 1519 http://toss.svn.sourceforge.net/toss/?rev=1519&view=rev Author: lukstafi Date: 2011-07-29 09:53:41 +0000 (Fri, 29 Jul 2011) Log Message: ----------- GDL translation work in progress: compilation fixes. Tests do not work yet. Modified Paths: -------------- trunk/Toss/GGP/GDL.ml trunk/Toss/GGP/GDL.mli trunk/Toss/GGP/TranslateFormula.ml trunk/Toss/GGP/TranslateFormula.mli trunk/Toss/GGP/TranslateGame.ml trunk/Toss/GGP/TranslateGame.mli trunk/Toss/GGP/TranslateGameTest.ml trunk/Toss/Server/ReqHandler.ml Modified: trunk/Toss/GGP/GDL.ml =================================================================== --- trunk/Toss/GGP/GDL.ml 2011-07-26 21:50:38 UTC (rev 1518) +++ trunk/Toss/GGP/GDL.ml 2011-07-29 09:53:41 UTC (rev 1519) @@ -286,8 +286,10 @@ | Neg atom -> Neg (subst_atom sb atom) | Disj disjs -> Disj (List.map (subst_literal sb) disjs) +let rec subst_literals sb = List.map (subst_literal sb) + let subst_clause sb (head, body) = - subst_rel sb head, List.map (subst_literal sb) body + subst_rel sb head, subst_literals sb body let rel_atom_str (rel, args) = "(" ^ rel ^ " " ^ @@ -675,6 +677,7 @@ let player_vars_of rels = Aux.map_some (function + | "goal", [|Var v; _|] -> Some v | "does", [|Var v; _|] -> Some v | "legal", [|Var v; _|] -> Some v | _ -> None) rels Modified: trunk/Toss/GGP/GDL.mli =================================================================== --- trunk/Toss/GGP/GDL.mli 2011-07-26 21:50:38 UTC (rev 1518) +++ trunk/Toss/GGP/GDL.mli 2011-07-29 09:53:41 UTC (rev 1519) @@ -62,8 +62,12 @@ val unify : substitution -> term list -> term list -> substitution val unify_all : substitution -> term list -> substitution +val rels_unify : rel_atom -> rel_atom -> bool val subst : substitution -> term -> term +val subst_rel : substitution -> rel_atom -> rel_atom val subst_rels : substitution -> rel_atom list -> rel_atom list +val subst_literal : substitution -> literal -> literal +val subst_literals : substitution -> literal list -> literal list val subst_clause : substitution -> clause -> clause (** {3 Transformations of GDL clauses: inlining, negation.} *) @@ -77,18 +81,24 @@ negation of disjunction of given clause bodies. *) val negate_bodies : literal list list -> literal list list +(** Rename clauses so that they have disjoint variables. Return a cell + storing all variables. *) +val rename_clauses : clause list -> Aux.Strings.t ref * clause list + val func_graph : string -> term list -> term array list + (** {3 GDL translation helpers.} *) val blank : term +val term_str : term -> string val term_to_name : ?nested:bool -> term -> string val state_terms : literal list -> term list +val term_arities : term -> (string * int) list - (** {3 GDL whole-game operations.} Aggregate playout, player-denoting variable elimination. *) @@ -107,6 +117,10 @@ rel_atom list * term list * (term array list list * term list list) +val find_cycle : term option list -> term option list + +val expand_players : clause list -> clause list + (** {3 Paths and operations involving terms and paths.} *) (** [simult_subst ps s t] substitutes [s] at all [t] paths that belong Modified: trunk/Toss/GGP/TranslateFormula.ml =================================================================== --- trunk/Toss/GGP/TranslateFormula.ml 2011-07-26 21:50:38 UTC (rev 1518) +++ trunk/Toss/GGP/TranslateFormula.ml 2011-07-29 09:53:41 UTC (rev 1519) @@ -291,11 +291,12 @@ failwith "GGP/TranslateFormula: finding path for defined relation argument undetermined by state terms not implemented yet") p_defside p_callside in (* now building the translation *) - let defvars = Array.mapi (fun i _ -> - Formula.fo_var_of_string ("v"^string_of_int i)) arg_paths in + let defvars = + Array.mapi (fun i _ -> "v"^string_of_int i) arg_paths in let defbody (args,(rels_phi,pos_state,neg_state)) s_defside = let arg_eqs = Array.mapi (fun i v -> + let v = Formula.fo_var_of_string v in let in_I = p_defside.(i) <> None in if in_I then @@ -324,7 +325,7 @@ p_defside arg_paths in data.defrel_arg_type := (rel, defrel_arg_type) :: !(data.defrel_arg_type); - rel, (defvars, Formula.Or def_disjuncts) in + rel, (Array.to_list defvars, Formula.Or def_disjuncts) in List.map build_defrel data.defined_rels Modified: trunk/Toss/GGP/TranslateFormula.mli =================================================================== --- trunk/Toss/GGP/TranslateFormula.mli 2011-07-26 21:50:38 UTC (rev 1518) +++ trunk/Toss/GGP/TranslateFormula.mli 2011-07-29 09:53:41 UTC (rev 1519) @@ -13,7 +13,14 @@ term_arities : (string * int) list; } +val blank_out : transl_data -> GDL.term -> GDL.term +val var_of_term : transl_data -> GDL.term -> Formula.fo_var + val empty_transl_data : transl_data val translate : transl_data -> GDL.literal list list -> Formula.formula + +val build_defrels : + transl_data -> GDL.clause list -> + (string * (string list * Formula.formula)) list Modified: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml 2011-07-26 21:50:38 UTC (rev 1518) +++ trunk/Toss/GGP/TranslateGame.ml 2011-07-29 09:53:41 UTC (rev 1519) @@ -3,6 +3,7 @@ *) open GDL +open TranslateFormula (** Translate stable relations that otherwise would be translated as structure relations, but have arity above the threshold, as @@ -25,9 +26,12 @@ let env_player = Const "ENVIRONMENT" type tossrule_data = { - legal_tuple : term; - (* the "legal"/"does" term of the player that performs the move, we - call its parameters "fixed variables" as they are provided externally *) + legal_tuple : term array; + (* the "legal"/"does" term of the player that performs the move + (when a singleton) or the players that participate in the move + (then ordered in the same way as players), + we call its parameters "fixed variables" as they are provided + externally *) precond : Formula.formula; (* the LHS match condition (the LHS structure and the precondition) *) rhs_add : (string * string array) list; @@ -60,8 +64,7 @@ is_concurrent : bool; transl_data : TranslateFormula.transl_data; (* mostly the same data as above, but packed for formula translation *) - element_terms : term Aux.IntMap.t; - (* term representatives of structure elements *) + fluents : string list; } let empty_gdl_translation = { @@ -74,7 +77,7 @@ playing_as = 0; is_concurrent = false; transl_data = TranslateFormula.empty_transl_data; - element_terms = Aux.IntMap.empty; + fluents = []; } let our_turn gdl state = true @@ -190,9 +193,12 @@ let frame_clauses, move_clauses, f_paths = fluent_paths_and_frames clauses in let next_clauses = - List.map (fun ((_,s_C),body_C) -> s_C, true, body_C) frame_clauses - @ List.map (fun ((_,s_C),body_C) -> s_C, false, body_C) - move_clauses in + List.map (function + | (_,[|s_C|]),body_C -> s_C, true, body_C + | _ -> assert false) frame_clauses + @ List.map (function + | (_,[|s_C|]),body_C -> s_C, false, body_C + | _ -> assert false) move_clauses in let arities = ("EQ_", 2):: Aux.unique_sorted @@ -219,8 +225,6 @@ List.assoc rel arities <= !defined_arity_above) stable_rels in let struc_rels = "EQ_"::struc_rels in let defined_rels = defined_rels @ nonstable_rels in - let elem_term_map = Aux.strmap_of_assoc - (List.map (fun e -> term_to_name e, e) element_reps) in let struc = List.fold_left (fun struc rel -> let arity = List.assoc rel arities in @@ -269,23 +273,70 @@ else struc ) struc element_reps ) struc mask_reps in + (* + let elem_term_map = Aux.strmap_of_assoc + (List.map (fun e -> term_to_name e, e) element_reps) in + *) + let elem_term_map = Aux.intmap_of_assoc + (List.map (fun e -> + Structure.find_elem struc (term_to_name e), e) element_reps) in next_clauses, f_paths, m_paths, mask_reps, defined_rels, !stable_rels, !fluents, stable_base, init_state, struc, agg_actions, elem_term_map +(* substitute a "next" clause with frame info *) +let subst_fnextcl sb (head, frame, body) = + subst sb head, frame, subst_literals sb body +(* substitute a "legal" or "next" clause (with only a legal/state term + in the head) *) +let subst_ln_cl sb (head, body) = + subst sb head, subst_literals sb body + + +(* Callgraph for creating "move tuples" and Toss rules. + + (1) [create_init_struc] prepares [next_cls], segregated into frame + clauses and normal clauses, with head term extracted. + + (2) [move_tuples] selects maximal tuples of [next_cls] such that + their "legal"/"does" terms unify. + + (3) [add_erasure_clauses] converts frame into erasure clauses, and + adds the result to non-frame clauses (without framing + information). + + (4) [process_rule_cands] calls [move_tuples], applies the unifier, + and calls [add_erasure_clauses]. + + (5) [rule_cases] distributes clauses from a move tuple to + disjointly cover all applicability conditions. Then it collects all + head terms and conflates the bodies to produce a rule + candidate. Legality conditions are not passed to [rule_cases]. + + (6) [turnbased_rule_cases], [concurrent_rule_cases] and + [general_int_rule_cases] call [rule_cases], add legal terms and + legality conditions to the result when appropriate (the + environment does not have legality conditions). Rules for players + as well as for the environment (when not turn-based) are built. + + (7) [create_rule_cands] calls the right routine of (6). + +*) + + (* Find the rule clauses $\ol{\calC},\ol{\calN}$. Do not remove the "does" atoms from clauses. Also handles as special cases: "concurrent" case with selecting clauses for only one player, and "environment" case for selecting clauses not dependent on any - player. *) + player. Preserve legal clauses into the output tuples. *) let move_tuples used_vars next_cls mode players legal_tuples = (* computing the $d_i(\calN)$ for each $\calN$ *) let fresh_x_f () = let x_f = Aux.not_conflicting_name !used_vars "x_f" in used_vars := Aux.Strings.add x_f !used_vars; Var x_f in - let does_facts (_,body) = + let does_facts (_,_,body) = List.fold_right (fun p (sb, dis) -> let djs = (* FIXME: check if "negative true" is properly handled *) @@ -304,7 +355,7 @@ let next_cls = if mode = `Environment then - Aux.map_some (fun (_,body as cl) -> + Aux.map_some (fun (_,_,body as cl) -> if List.exists (function Pos (Does _) | Neg (Does _) -> true | _ -> false) body then None @@ -313,13 +364,14 @@ else Aux.map_try (fun cl -> let sb, ds = does_facts cl in - subst_clause sb cl, ds) next_cls in + subst_fnextcl sb cl, ds) next_cls in (* selecting $\ol{\calC},\ol{\calN}$ clauses with $\sigma_{\ol{\calC},\ol{\calN}}$ applied *) let tup_unifies ts1 ts2 = try ignore (unify [] ts1 ts2); true with Not_found -> false in - let move_clauses cs = + let move_clauses legal_tup = + let cs = List.map fst legal_tup in (* bag of next clauses for each legal tuple *) let next_clauses = List.filter (fun (n_cl, ds) -> tup_unifies cs ds) next_cls in @@ -355,7 +407,8 @@ (sb, tup_ds, n_cl::n_cls) with Not_found -> cl_tup ) cl_tup next_clauses in - List.map maximality cl_tups in + let cl_tups = List.map maximality cl_tups in + List.map (fun (sb, _, n_cls) -> sb, legal_tup, n_cls) cl_tups in Aux.concat_map move_clauses legal_tuples @@ -395,7 +448,7 @@ let frames = List.map maximality frames in let frames = List.map (fun (sb, s, bodies) -> - s, List.map (subst_rels sb) bodies) frames in + s, List.map (subst_literals sb) bodies) frames in let erasure_cls = Aux.concat_map (fun (s, bodies) -> let nbodies = negate_bodies bodies in @@ -408,7 +461,8 @@ (* Assign rule clauses to rule cases, i.e. candidates for - Toss rules. Collect the conditions and RHS state terms together. *) + Toss rules. Collect the conditions and RHS state terms together. + Frame clauses are already processed into erasure clauses. *) let rule_cases next_cls = let atoms = Aux.concat_map (fun (_, body) -> Aux.map_some (function @@ -419,7 +473,7 @@ let patterns = let next_cls = Array.of_list next_cls in List.map (fun a -> - Array.map (fun i (_, body) -> + Array.mapi (fun i (_, body) -> if List.mem (Neg a) body then -1 else if List.mem (Pos a) body then 1 else 0 @@ -427,8 +481,8 @@ a) atoms in let patterns = Aux.collect patterns in let patterns = List.filter (fun (pat, _) -> - Array.exists (fun v-> v < 1) pat && - Array.exists (fun v-> v > -1) pat) patterns in + Aux.array_existsi (fun _ v-> v < 1) pat && + Aux.array_existsi (fun _ v-> v > -1) pat) patterns in let pos_choice = List.map (fun _ -> true) patterns in let neg_choice = List.map (fun _ -> false) patterns in let choices = Aux.product [pos_choice; neg_choice] in @@ -448,34 +502,63 @@ ) choice patterns ) next_cls in let case_rhs, case_conds = List.split case_cls in - case_cls, case_rhs, separation_cond @ case_conds in + case_cls, case_rhs, separation_cond @ List.concat case_conds in List.map rule_case choices -let nonint_rule_cases (legal_tup, next_cls) = - let legal_tup, legal_cond = List.split legal_tup in - let legal_cond = List.combine legal_cond in - List.map (fun (case_rhs, case_cond) -> - legal_tup, case_rhs, case_cond @ legal_cond - ) (rule_cases next_cls) +let process_rule_cands used_vars next_cls mode players legal_tuples = + let move_tups = + move_tuples used_vars next_cls mode players legal_tuples in + let move_tups = + List.map (fun (sb, legal_tup, n_cls) -> + List.map (subst_ln_cl sb) legal_tup, + List.map (subst_fnextcl sb) n_cls) move_tups in + List.map add_erasure_clauses move_tups + +let add_legal_cond (legal_tup, next_cls) = + let legal_tup, legal_cond = List.split legal_tup in + let legal_cond = List.concat legal_cond in + List.map (fun (case_cls, case_rhs, case_cond) -> + legal_tup, case_rhs, case_cond @ legal_cond + ) (rule_cases next_cls) + + +let turnbased_rule_cases used_vars next_cls players legal_by_player = + let legal_tuples = Aux.product legal_by_player in + let move_tups = + process_rule_cands + used_vars next_cls `General players legal_tuples in + let rules = Aux.concat_map add_legal_cond move_tups in + (* we do not look for the players -- for turn-based case, it's done + while building game graph *) + Aux.Left rules + + (* If "Concurrent Moves" case, divide rule clauses among players. *) -let concurrent_rule_cases players (legal_tup, next_cls) = - Array.mapi (fun i player -> - let legal_head, legal_cond = legal_tup.(i) in - let cls = List.filter - (fun (_,cl_body) -> List.exists ( - function Does (p, _) when p=player -> true | _ -> false) - cl_body) - next_cls in - List.map (fun (case_rhs, case_cond) -> - legal_head, case_rhs, case_cond @ legal_cond - ) (rule_cases cls) - ) players +let concurrent_rule_cases used_vars next_cls players legal_by_player = + let env_pl_tups = + env_player, + process_rule_cands used_vars next_cls `Environment [] [[]] in + let player_rules = + List.map2 (fun player legal_cls -> + (* [process_rule_cands] works with players tuples, so we "cheat" *) + let legal_tuples = List.map (fun cl -> [cl]) legal_cls in + let move_tups = + process_rule_cands + used_vars next_cls `Concurrent [player] legal_tuples in + player, move_tups + ) players legal_by_player in + let player_rules = List.map + (fun (player, move_tups) -> + player, Aux.concat_map add_legal_cond move_tups) + (player_rules @ [env_pl_tups]) in + Aux.Right player_rules -let general_int_rule_cases (legal_tup, next_cls) = +let general_int_rule_cases used_vars next_cls players legal_by_player = failwith "General Interaction Games not implemented yet" + (* Generate rule candidates (they need to be filtered before finishing the translation of Toss rules): returns the "legal" terms tuple (ordered by players), the right-hand-sides, and the conditions @@ -489,52 +572,35 @@ let create_rule_cands is_turn_based used_vars next_cls clauses = let players = (* Array.of_list *) Aux.map_some (function - | ("role", [player]), _ -> Some player + | ("role", [|player|]), _ -> Some player | _ -> None ) clauses in let legal_cls = List.filter (fun ((rel,_),_) -> rel="legal") clauses in let is_concurrent = not is_turn_based && List.for_all - (fun (_, body) -> + (fun (_, _, body) -> List.length - (List.filter (function Does _ -> true | _ -> false) body) + (List.filter + (function Pos (Does _) | Neg (Does _) -> true | _ -> false) body) <= 1) next_cls in - (* let next_cls = - List.filter (fun ((rel,_),_) -> rel="next") clauses in *) (* constructing $(\calC_1,...,\calC_n)$ tuples *) let legal_by_player = List.map (fun p -> Aux.map_some (function - | ("legal",[lp; l]), body when lp = p -> Some (l, body) + | ("legal",[|lp; l|]), body when lp = p -> Some (l, body) | _ -> None) legal_cls ) players in - let process_rule_cands mode players legal_tuples = - let move_tups = - move_tuples used_vars next_cls mode players legal_tuples in - let move_tups = - List.map (fun (sb, legal_tup, n_cls) -> - List.map (subst sb) legal_tup, - List.map (subst_clause sb) n_cls) move_tups in - List.map add_erasure_clauses move_tups in - let concurrent_rule_cands player legal_cls = - let legal_tuples = List.map (fun cl -> [cl]) legal_cls in - let move_tups = - process_rule_cands `Concurrent [player] legal_tuples in - player, Aux.concat_map nonint_rule_cases (move_tups @ env_tups) in - if is_concurrent then - let env_tups = - env_player, process_rule_cands `Environment [] [[]] in - Right - (List.map2 concurrent_rule_cands players legal_by_player @ env_tups) - else - let legal_tuples = Aux.product legal_by_player in - let move_tups = process_rule_cands `General players legal_tuples in - if is_turn_based then - Left (Aux.concat_map nonint_rule_cases move_tups) + let result = + if is_concurrent then + concurrent_rule_cases used_vars next_cls players legal_by_player + else if is_turn_based then + turnbased_rule_cases used_vars next_cls players legal_by_player else - Left (Aux.concat_map general_int_rule_cases move_tups) + general_int_rule_cases used_vars next_cls players legal_by_player + in + result, is_concurrent let filter_rule_cands stable_base defined_rels rule_cands = @@ -547,13 +613,13 @@ not (List.exists (rels_unify a) stable_base) | _ -> true in let check_cands cands = - List.filter (fun (_, _, _, case_conds) -> + List.filter (fun (_, _, case_conds) -> List.for_all check_atom case_conds ) cands in match rule_cands with - | Left cands -> Left (check_cands cands) - | Right cands -> - Right (List.map (fun (p,cands) -> p, check_cands cands) cands) + | Aux.Left cands -> Aux.Left (check_cands cands) + | Aux.Right cands -> + Aux.Right (List.map (fun (p,cands) -> p, check_cands cands) cands) exception Not_turn_based @@ -563,7 +629,7 @@ let check_turn_based players agg_actions = let noop_cands = List.map (fun actions -> let actions = Aux.map_reduce - (function [player; action] -> player, action + (function [|player; action|] -> player, action | _ -> assert false) (fun y x->x::y) [] actions in List.map (function | player, [Const _ as noop] -> player, Some noop @@ -603,6 +669,8 @@ (List.map (function Some p -> p | None -> players.(0)) loc_players) in let loc_n = Array.length loc_players in + let players_n = Array.length players in + let find_player p = Aux.array_argfind (fun x -> x = p) players in (* noop actions of a player in a location *) let loc_noops = let i = ref 0 in @@ -630,54 +698,56 @@ let build_toss_rule transl_data rule_names struc fluents synch_precond synch_postcond (legal_tuple, case_rhs, case_cond) = let rname = - Aux.not_conflicting_name rule_names + Aux.not_conflicting_name !rule_names (String.concat "_" (List.map term_to_name legal_tuple)) in rule_names := Aux.Strings.add rname !rule_names; let label = {Arena.rule = rname; time_in = 0.1, 0.1; parameters_in = []} in let precond = - synch_precond @ TranslateFormula.translate transl_data case_cond in + Formula.And + (synch_precond @ + (* singleton disjunct, i.e. no disjunction *) + [TranslateFormula.translate transl_data [case_cond]]) in let rhs_add = Aux.concat_map - (function _, [sterm] -> + (fun sterm -> let s_subterms = - map_paths (fun path subt -> subt, path) transl_data.f_paths sterm in + map_paths (fun path subt -> subt, path) + transl_data.TranslateFormula.f_paths sterm in let s_subterms = List.filter (fun (subt, _) -> subt <> blank) s_subterms in - let vartup = [|TranslateFormula.var_of_term data sterm|] in + (* same as [TranslateFormula.var_of_term], but only the name *) + let vartup = [|term_to_name (blank_out transl_data sterm)|] in List.map (fun (subt, path) -> pred_on_path_subterm path subt, vartup) - s_subterms - | _ -> assert false) + s_subterms) case_rhs in let rhs_add = synch_postcond @ rhs_add in let signat = Structure.rel_signature struc in + let struc_elems = List.map + (fun sterm -> term_to_name (blank_out transl_data sterm)) + case_rhs in let discrete = DiscreteRule.translate_from_precond ~precond ~add:rhs_add ~emb_rels:fluents ~signat ~struc_elems in let rule = - ContinuousRule.make_rule signature [] discrete + ContinuousRule.make_rule signat [] discrete [] [] ~pre:discrete.DiscreteRule.pre () in - let struc_elem_terms = List.map - (function _, [sterm] -> sterm | _ -> assert false) - case_rhs in - let struc_elems = List.map - (fun sterm -> Formula.var_str (TranslateFormula.var_of_term data sterm)) - struc_elem_terms in - let elemvars = Aux.strmap_of_assoc - (List.combine struc_elems struc_elem_terms) in - let fixvar_terms = List.map + let rulevar_terms = Aux.strmap_of_assoc + (List.combine struc_elems case_rhs) in + let fixvar_terms = Aux.concat_map (fun sterm -> map_paths (fun path -> function Var v -> v, (sterm, path) | _ -> assert false) - (term_paths (function Var _ -> true | _ -> false) sterm)) - struc_elem_terms in + (term_paths (function Var _ -> true | _ -> false) sterm) sterm) + case_rhs in + let fixvar_terms = Aux.collect fixvar_terms in let tossrule_data = { - legal_tuple = legal_tuple; + legal_tuple = Array.of_list legal_tuple; precond = precond; rhs_add = rhs_add; struc_elems = struc_elems; fixvar_terms = fixvar_terms; - elemvars = elemvars; + rulevar_terms = rulevar_terms; } in ((rname, tossrule_data), label), (rname, rule) @@ -695,7 +765,7 @@ let loc_rules = Aux.map_some (fun (legal_tup, _, _ as rcand) -> let legal_tup = Array.of_list legal_tup in - if Array.for_alli + if Aux.array_for_alli (fun pl noop -> pl = player_num || Some legal_tup.(pl) = noop) loc_noops.(loc) @@ -711,7 +781,7 @@ Array.mapi (fun pl_num payoff -> {Arena.payoff = payoff; - view = []; + view = Formula.And [], []; (* FIXME: ? *) heur = []; moves = if pl_num = player_num then pl_moves else []}) player_payoffs) @@ -723,49 +793,57 @@ let loc_graph_general_int = failwith "GDL: General Interaction Games not implemented yet" -(* Remember that "environment" is the last player -- also in payoffs - list. [rule_cands] is a player-indexed array. [players] are all - player terms, excluding "environment". *) +(* "environment" will the last player -- also in payoffs + array. [players] are all player terms, excluding "environment"! *) let loc_graph_concurrent players player_payoffs struc build_rule fluents rule_cands = (* finding or creating the control predicate *) + let num_players = Array.length players in let control_pred, control_e, struc = try let control_pred, _ = List.find (fun (rel, ar) -> ar = 1 && - Structure.Tuples.cardinal (Structure.find_rel rel struc) = 1) + Structure.Tuples.cardinal (Structure.rel_find rel struc) = 1) (Structure.rel_signature struc) in - let etup = Structure.Tuples.choose_elem - (Structure.find_rel control_pred struc) in + let etup = Structure.Tuples.choose + (Structure.rel_find control_pred struc) in control_pred, etup.(0), struc with Not_found -> let struc, control_e = Structure.add_new_elem struc ~name:sControl () in - let struc = Structure.add_rel struc [|control_e|] in + let struc = Structure.add_rel struc sControl [|control_e|] in sControl, control_e, struc in (* adding synchronization to rules and putting it all together *) let player_pred pl = term_to_name pl ^ "__SYNC" in - let struc = List.fold_left + let struc = Array.fold_left (fun struc player -> - Structure.add_rel_name (player_pred player) 1) players in + Structure.add_rel_name (player_pred player) 1 struc) struc players in + let control_vn = Structure.elem_name struc control_e in let control_v = - Formula.fo_var_of_string (Structure.elem_name struc control_e) in + Formula.fo_var_of_string control_vn in let player_marker pl = [player_pred pl, [|control_v|]; control_pred, [|control_v|]] in - let fluents = List.map player_pred players @ fluents in + let player_marker_rhs pl = + [player_pred pl, [|control_vn|]; control_pred, [|control_vn|]] in + let lplayers = Array.to_list players in + let fluents = List.map player_pred lplayers @ fluents in let all_players_precond = (List.map (fun (rel,tup) -> Formula.Rel (rel,tup))) - (Aux.concat_map player_marker players) in + (Aux.concat_map player_marker lplayers) in let rules = ref [] in let tossr_data = ref [] in - let player_moves = Array.mapi - (fun pl_num (pl, p_rules) -> + let players_with_env = Array.of_list + (Array.to_list players @ [env_player]) in + let player_moves = List.map + (fun (pl, p_rules) -> + let pl_num = + Aux.array_argfind (fun x -> x = pl) players_with_env in let p_rules = List.map (fun rcand -> if pl_num = num_players then (* environment *) build_rule struc fluents all_players_precond [] rcand else - build_rule struc fluents [] (player_marker pl) rcand) + build_rule struc fluents [] (player_marker_rhs pl) rcand) p_rules in (* we need to build first before adding [player_cond] because of how formula translation works *) @@ -773,14 +851,15 @@ let p_rdata, labels = List.split p_rdata in rules := !rules @ p_rules; tossr_data := !tossr_data @ p_rdata; - List.map (fun l -> l, (loc + 1) mod loc_n)) + pl_num, List.map (fun l -> l, 0) labels) rule_cands in + let player_moves = Aux.array_from_assoc player_moves in let graph = [| Aux.array_map2 (fun payoff moves -> {Arena.payoff = payoff; - view = []; + view = Formula.And [], []; (* FIXME: ? *) heur = []; moves = moves}) player_payoffs player_moves @@ -788,20 +867,98 @@ (graph, !rules, !tossr_data), struc +(* We assume that clauses for different goal values are disjoint, for + non-disjoint we sum each component. *) +let compute_payoffs transl_data players clauses = + (* TODO: we should expand non-constant value expressions... *) + let goal_cls = Aux.map_some + (function (("goal",[|player; value|]), body) -> + Some (player,(value,body)) | _ -> None) clauses in + let goal_cls = + List.map (fun (player, goal_brs) -> player, Aux.collect goal_brs) + (Aux.collect goal_cls) in + let player_goals = Array.map + (fun player -> + try List.assoc player goal_cls + with Not_found -> failwith + ("TranslateGame.compute_payoffs: no goal provided for player " + ^ term_to_name player)) + players in + (* Translate the goal conditions. *) + let payoffs = Array.map + (fun goals -> List.map + (fun (score, disjs) -> + let score = + match score with + | Const pay -> + (try float_of_string pay with _ -> assert false) + | _ -> failwith + ("TranslateGame.compute_payoffs: non-constant " ^ + "goal values not implemented yet") in + let goal_phi = translate transl_data disjs in + let phi_vars = FormulaOps.free_vars goal_phi in + score, + if phi_vars = [] then goal_phi + else Formula.Ex (phi_vars, goal_phi)) + goals) + player_goals in + (* Offset the values to remove the most inconvenient goal + condition. *) + let payoffs = Array.map + (fun payoff -> + let sized = + List.map (fun (score,phi) -> GameSimpl.niceness phi, score) + payoff in + (* Sort in increasing niceness -- to remove the least nice. *) + let base_score = + match List.sort Pervasives.compare sized with [] -> 0. + | (_, score)::_ -> score in + match payoff with + | [score, guard] -> + Formula.Times ( + Formula.Const score, Formula.Char guard) + | scores -> + List.fold_left (fun sum (score, guard) -> + if score = base_score then ( + (* {{{ log entry *) + if !debug_level > 2 then ( + Printf.printf + "translate_game: (8) dropping score %f guard:\n%s\n\n%!" + score (Formula.sprint guard) + ); + (* }}} *) + sum) + else + let guarded = Formula.Times ( + Formula.Const (score -. base_score), Formula.Char guard) in + if sum = Formula.Const 0. then guarded + else Formula.Plus (sum, guarded)) + (Formula.Const base_score) scores + ) payoffs in + payoffs -let translate_game clauses = + +(* [playing_as] is only used for building move translation data, the + translation is independent of the selected player. *) +let translate_game ~playing_as clauses = let clauses = expand_players clauses in let used_vars, clauses = rename_clauses clauses in let next_cls, f_paths, m_paths, mask_reps, defined_rels, stable_rels, fluents, stable_base, init_state, struc, agg_actions, elem_term_map = create_init_struc clauses in + let players = Array.of_list + (Aux.map_some (function + | ("role", [|player|]), _ -> Some player + | _ -> None + ) clauses) in let turn_data = try Some (check_turn_based players agg_actions) with Not_turn_based -> None in + let rule_cands, is_concurrent = + create_rule_cands (turn_data <> None) used_vars next_cls clauses in let rule_cands = - create_rule_cands (turn_data <> None) used_vars next_cls clauses in - let rule_cands = filter_rule_cands stable_base rule_cands in + filter_rule_cands stable_base defined_rels rule_cands in let all_state_terms = Aux.concat_map state_terms (List.map snd clauses) in let term_arities = Aux.unique_sorted @@ -809,35 +966,34 @@ let transl_data = { TranslateFormula.f_paths = f_paths; m_paths = m_paths; - all_paths = path_union f_paths m_paths; + all_paths = paths_union f_paths m_paths; mask_reps = mask_reps; defined_rels = defined_rels; defrel_arg_type = ref []; (* built in TranslateFormula *) term_arities = term_arities; } in - let defined_rels = build_defrels transl_data clauses in - let players = Array.of_list - (Aux.map_some (function - | ("role", [player]), _ -> Some player - | _ -> None - ) clauses) in + let defined_rels = TranslateFormula.build_defrels transl_data clauses in let player_names = Array.to_list (Array.mapi (fun i p -> term_to_name p, i) players) in (* possibly update the structure with a control element and predicate *) + let rule_names = ref Aux.Strings.empty in + let payoffs = compute_payoffs transl_data players clauses in let (graph, rules, tossrule_data), struc = match turn_data, rule_cands with - | Some (loc_players, loc_noops), Left cands -> + | Some (loc_players, loc_noops), Aux.Left cands -> let build_rule = build_toss_rule transl_data rule_names struc fluents [] [] in - loc_graph_turn_based players loc_players loc_noops build_rule - cands, struc - | None, Left cands -> - loc_graph_general_int - | None, Right cands -> + loc_graph_turn_based player_names payoffs + loc_players loc_noops build_rule + cands, + struc + | None, Aux.Right cands when is_concurrent -> let build_rule = build_toss_rule transl_data rule_names in - loc_graph_concurrent players player_payoffs struc build_rule - fluents rule_cands + loc_graph_concurrent players payoffs struc build_rule + fluents cands + | None, Aux.Right cands -> + loc_graph_general_int | _ -> assert false in let game = { @@ -850,6 +1006,8 @@ defined_rels = defined_rels; } in let tossrule_data = Aux.strmap_of_assoc tossrule_data in + let playing_as = + Aux.array_argfind (fun x -> x = playing_as) players in let gdl_translation = { (* map between structure elements and their term representations; the reverse direction is by using element names *) @@ -858,6 +1016,11 @@ m_paths = m_paths; masks = mask_reps; tossrule_data = tossrule_data; + turnbased_noops = Aux.map_option snd turn_data; + playing_as = playing_as; + is_concurrent = is_concurrent; + transl_data = transl_data; + fluents = fluents; } in gdl_translation, (game, {Arena.struc = struc; time = 0.; cur_loc = 0}) @@ -871,12 +1034,17 @@ a non-noop action. [move] is the instance of a "legal" term, performed by [player] (a number). Returns an option, since it can be called for multiple candidate rules. *) -let translate_incoming_single_action data rdata state player move rname = - let fixed_inst, _ = - unify [] [move] [rdata.legal_tuple.(player)] in +let translate_incoming_single_action + fluents data rdata state player move rname = + let legal_term = + if Array.length rdata.legal_tuple > 1 + then rdata.legal_tuple.(player) + else rdata.legal_tuple.(0) in + let fixed_inst = unify [] [move] [legal_term] in + let struc = (snd state).Arena.struc in let anchors = Aux.concat_map (fun (v,t) -> let state_terms = List.assoc v rdata.fixvar_terms in - Aux.concat_map + List.map (fun (sterm, path) -> let pred = pred_on_path_subterm path t in Formula.Rel (pred, [|TranslateFormula.var_of_term data sterm|])) @@ -895,7 +1063,7 @@ let signat = Structure.rel_signature struc in let rule = DiscreteRule.translate_from_precond ~precond ~add:rdata.rhs_add - ~emb_rels:gdl.fluents ~signat ~struc_elems:rdata.struc_elems in + ~emb_rels:fluents ~signat ~struc_elems:rdata.struc_elems in let lhs_struc = rule.DiscreteRule.lhs_struc in let rule = DiscreteRule.compile_rule signat [] rule in let asgns = @@ -928,12 +1096,15 @@ let struc = (snd state).Arena.struc in let tossrules = Aux.strmap_filter (fun _ rdata -> - try ignore (match_meta [] [] [move] - [rdata.legal_tuple.(loc_player)]); true + let legal_term = + if Array.length rdata.legal_tuple > 1 + then rdata.legal_tuple.(loc_player) + else rdata.legal_tuple.(0) in + try ignore (unify [] [move] [legal_term]); true with Not_found -> false ) gdl.tossrule_data in let candidates = Aux.map_some (fun (rname, rdata) -> - translate_incoming_single_action gdl.transl_data rdata state + translate_incoming_single_action gdl.fluents gdl.transl_data rdata state loc_player move rname ) tossrules in match candidates with @@ -949,8 +1120,8 @@ Structure.elem_str lhs_struc v ^ ": " ^ Structure.elem_str struc e) emb)) ); - (* }}} *) - loc_player, rname, emb + (* }}} *) + loc_player, (rname, emb) | _ -> (* {{{ log entry *) if !debug_level > 0 then ( @@ -980,13 +1151,13 @@ (fun player move -> let tossrules = Aux.strmap_filter (fun _ rdata -> - try ignore (match_meta [] [] [move] + try ignore (unify [] [move] [rdata.legal_tuple.(player)]); true with Not_found -> false ) gdl.tossrule_data in let candidates = Aux.map_some (fun (rname, rdata) -> - translate_incoming_single_action gdl.transl_data rdata state - player move rname + translate_incoming_single_action gdl.fluents gdl.transl_data + rdata state player move rname ) tossrules in match candidates with | [] -> @@ -1003,7 +1174,7 @@ Structure.elem_str struc e) emb)) ); (* }}} *) - player, rname, emb + player, (rname, emb) | _ -> (* {{{ log entry *) if !debug_level > 0 then ( @@ -1031,7 +1202,7 @@ let translate_incoming_move gdl state actions = if actions = [] (* start of game -- do nothing *) - then "", [] + then [] else match gdl.turnbased_noops with | Some noops -> @@ -1070,7 +1241,7 @@ rule.ContinuousRule.compiled.DiscreteRule.lhs_elem_inv_names lhs_e in Aux.StrMap.find v tossrule.rulevar_terms, - Aux.IntMap.find struc_e gdl.element_terms) emb in + Aux.IntMap.find struc_e gdl.elem_term_map) emb in (* {{{ log entry *) if !debug_level > 2 then ( Printf.printf "outgoing-emb={%s}\n%!" @@ -1085,7 +1256,11 @@ with Not_found -> failwith ("GDL.translate_outgoing_move: inconsistent match for rule " ^rname) in - let res = term_str (subst sb tossrule.legal_tuple.(gdl.playing_as)) in + let legal_term = + if Array.length tossrule.legal_tuple > 1 + then tossrule.legal_tuple.(gdl.playing_as) + else tossrule.legal_tuple.(0) in + let res = term_str (subst sb legal_term) in (* {{{ log entry *) if !debug_level > 0 then ( Printf.printf "GDL.translate_outgoing_move: result = %s\n%!" res Modified: trunk/Toss/GGP/TranslateGame.mli =================================================================== --- trunk/Toss/GGP/TranslateGame.mli 2011-07-26 21:50:38 UTC (rev 1518) +++ trunk/Toss/GGP/TranslateGame.mli 2011-07-29 09:53:41 UTC (rev 1519) @@ -1,29 +1,63 @@ + type tossrule_data = { - legal_tuple : GDL.term; - (* the "legal"/"does" term of the player that performs the move, we - call its parameters "fixed variables" as they are provided externally *) + legal_tuple : GDL.term array; + (* the "legal"/"does" term of the player that performs the move + (when a singleton) or the players that participate in the move + (then ordered in the same way as players), + we call its parameters "fixed variables" as they are provided + externally *) precond : Formula.formula; (* the LHS match condition (the LHS structure and the precondition) *) rhs_add : (string * string array) list; + struc_elems : string list; (* the elements of LHS/RHS structures, corresponding to the "next" terms *) - struc_elems : string list; fixvar_terms : (string * (GDL.term * GDL.path) list) list; + (* "state" terms indexed by GDL variables that they contain, together + with the path to the variable; in [(term * path) list], terms + can repeat *) rulevar_terms : GDL.term Aux.StrMap.t; +(* "state" terms indexed by Toss variable names they generate *) } (** Data to be used when translating moves. *) -type gdl_translation +type gdl_translation = { + (* map between structure elements and their term representations; + the reverse direction is by using element names *) + elem_term_map : GDL.term Aux.IntMap.t; + f_paths : GDL.path_set; + m_paths : GDL.path_set; + masks : GDL.term list; + tossrule_data : tossrule_data Aux.StrMap.t; + (* rule name to rule translation data *) + turnbased_noops : GDL.term option array array option; + (* in case of a turn-based translation, for each location and each + player, the player's noop move (if any) for the location *) + playing_as : int; + (* "active" player *) + is_concurrent : bool; + transl_data : TranslateFormula.transl_data; + (* mostly the same data as above, but packed for formula translation *) + fluents : string list; +} val empty_gdl_translation : gdl_translation +(* [playing_as] is only used for building move translation data, the + game translation is independent of the selected player (a dummy + term can be provided). *) val translate_game : - GDL.clause list -> gdl_translation * (Arena.game * Arena.game_state) + playing_as:GDL.term -> GDL.clause list -> + gdl_translation * (Arena.game * Arena.game_state) -val translate_incoming_move : - gdl_translation -> (Arena.game * Arena.game_state) -> GDL.term list -> - string * (int * int) list +(* Return a list of rewrites to apply, as triples: player number, + rule name, rule matching. *) +val translate_incoming_move : + gdl_translation -> + Arena.game * Arena.game_state -> + GDL.term list -> (int * (string * DiscreteRule.matching)) list + val translate_outgoing_move : gdl_translation -> (Arena.game * Arena.game_state) -> string -> (int * int) list -> string Modified: trunk/Toss/GGP/TranslateGameTest.ml =================================================================== --- trunk/Toss/GGP/TranslateGameTest.ml 2011-07-26 21:50:38 UTC (rev 1518) +++ trunk/Toss/GGP/TranslateGameTest.ml 2011-07-29 09:53:41 UTC (rev 1519) @@ -43,11 +43,13 @@ aux turn playout in aux players playout -let game_test_case ~game_name ~player ~loc0_rule_name ~loc0_emb +let game_test_case ~game_name ~player ~own_plnum ~opponent_plnum + ~loc0_rule_name ~loc0_emb ~loc0_move ~loc0_noop ~loc1 ~loc1_rule_name ~loc1_emb ~loc1_noop ~loc1_move = let game = load_rules ("./GGP/examples/"^game_name^".gdl") in - let gdl, res = TranslateGame.translate_game (*Const player*) game in + let gdl, res = + TranslateGame.translate_game ~playing_as:(Const player) game in let goal_name = (*if !GDL.prune_rulecands_at = GDL.Never then game_name^"-simpl-unpruned.toss" @@ -71,9 +73,10 @@ let transl = TranslateGame.translate_outgoing_move gdl res rname emb in assert_equal ~printer:(fun x->x) loc0_move transl; - let move = + let moves = TranslateGame.translate_incoming_move gdl res [pte loc0_move; pte loc0_noop] in + let move = List.assoc own_plnum moves in assert_equal ~msg:"own incoming move" ~printer:(emb_str res) (norm_move (rname, emb)) (norm_move move); let req = Arena.ApplyRuleInt (rname, emb, 0.1, []) in @@ -82,9 +85,10 @@ let rname = loc1_rule_name in let emb = Arena.emb_of_names res rname loc1_emb in - let move = + let moves = TranslateGame.translate_incoming_move gdl res [pte loc1_noop; pte loc1_move] in + let move = List.assoc opponent_plnum moves in assert_equal ~msg:"opponent incoming move" ~printer:(emb_str res) (norm_move (rname, emb)) (norm_move move) @@ -115,6 +119,7 @@ "tictactoe" >:: (fun () -> game_test_case ~game_name:"tictactoe" ~player:"xplayer" + ~own_plnum:0 ~opponent_plnum:1 ~loc0_rule_name:"mark_x64_y19_0" ~loc0_emb:[ "cell_x64_y19__blank_", "cell_2_2_MV1"; @@ -133,6 +138,7 @@ "connect5" >:: (fun () -> game_test_case ~game_name:"connect5" ~player:"x" + ~own_plnum:0 ~opponent_plnum:1 ~loc0_rule_name:"mark_x161_y162_0" ~loc0_emb:[ "cell_x161_y162__blank_", "cell_e_f_MV1"; @@ -148,6 +154,7 @@ "breakthrough" >:: (fun () -> game_test_case ~game_name:"breakthrough" ~player:"white" + ~own_plnum:0 ~opponent_plnum:1 ~loc0_rule_name:"move_x239_y257_x238_y256_0" ~loc0_emb:[ "cellholds_x239_y257__blank_", "cellholds_2_2_MV1"; @@ -170,6 +177,7 @@ (* TODO: finish adapting the test after game is cleanly translated. *) game_test_case ~game_name:"connect4" ~player:"white" + ~own_plnum:0 ~opponent_plnum:1 ~loc0_rule_name:"drop_???_0" ~loc0_emb:[ "cell_x_y__blank_", "cell_2_1_MV1"; Modified: trunk/Toss/Server/ReqHandler.ml =================================================================== --- trunk/Toss/Server/ReqHandler.ml 2011-07-26 21:50:38 UTC (rev 1518) +++ trunk/Toss/Server/ReqHandler.ml 2011-07-29 09:53:41 UTC (rev 1519) @@ -51,6 +51,33 @@ exception Found of int + +(* The player applying the rewrite seems not to be used. *) +let apply_rewrite state (player, (r_name, mtch)) = + if r_name <> "" then ( + let {Arena.rules=rules; graph=graph} = fst state in + let mv_loc = select_moving graph.((snd state).Arena.cur_loc) in + let moves = + Move.gen_moves Move.cGRID_SIZE rules + (snd state).Arena.struc mv_loc in + let pos = ( + try + for i = 0 to Array.length moves - 1 do + let mov = moves.(i) in + if r_name = mov.Move.rule && List.for_all + (fun (e, f) -> f = List.assoc e mov.Move.embedding) mtch then + raise (Found i) + done; + failwith "GDL Play request: action mismatched with play state" + with Found pos -> pos) in + let req = Arena.ApplyRuleInt (r_name, mtch, 0.1, []) in + let (new_state_noloc, resp) = Arena.handle_request state req in + let new_loc = moves.(pos).Move.next_loc in + (fst new_state_noloc, + {snd new_state_noloc with Arena.cur_loc = new_loc}) + ) else state + + let req_handle (g_heur, game_modified, state, gdl_transl, playclock) = function | Aux.Left (Arena.SuggestLocMoves (loc, timer, effort, _, _, heuristic, advr)) -> ( @@ -84,7 +111,7 @@ let old_force_competitive = !Heuristic.force_competitive in Heuristic.force_competitive := true; let new_gdl_transl, new_state = - TranslateGame.translate_game game_descr in + TranslateGame.translate_game ~playing_as:player game_descr in let effort, horizon, advr = (None, None, None) in let new_heur = Heuristic.default_heuristic ~struc:(snd new_state).Arena.struc @@ -97,32 +124,10 @@ | Aux.Right (GDL.Play (_,actions)) | Aux.Right (GDL.Stop (_,actions)) as rq -> let time_started = Unix.gettimeofday () in - let r_name, mtch = + let rewrites = TranslateGame.translate_incoming_move gdl_transl state actions in - let state = - if r_name <> "" then ( - let {Arena.rules=rules; graph=graph} = fst state in - let mv_loc = select_moving graph.((snd state).Arena.cur_loc) in - let moves = - Move.gen_moves Move.cGRID_SIZE rules - (snd state).Arena.struc mv_loc in - let pos = ( - try - for i = 0 to Array.length moves - 1 do - let mov = moves.(i) in - if r_name = mov.Move.rule && List.for_all - (fun (e, f) -> f = List.assoc e mov.Move.embedding) mtch then - raise (Found i) - done; - failwith "GDL Play request: action mismatched with play state" - with Found pos -> pos) in - let req = Arena.ApplyRuleInt (r_name, mtch, 0.1, []) in - let (new_state_noloc, resp) = Arena.handle_request state req in - let new_loc = moves.(pos).Move.next_loc in - (fst new_state_noloc, - {snd new_state_noloc with Arena.cur_loc = new_loc}) - ) else state in + let state = List.fold_left apply_rewrite state rewrites in let resp = if (match rq with This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-26 21:50:46
|
Revision: 1518 http://toss.svn.sourceforge.net/toss/?rev=1518&view=rev Author: lukaszkaiser Date: 2011-07-26 21:50:38 +0000 (Tue, 26 Jul 2011) Log Message: ----------- Corrections towards compilation. Modified Paths: -------------- trunk/Toss/GGP/GDL.mli trunk/Toss/GGP/GDLParser.mly trunk/Toss/GGP/GDLTest.ml trunk/Toss/GGP/TranslateFormula.ml trunk/Toss/GGP/TranslateFormula.mli trunk/Toss/GGP/TranslateGame.ml trunk/Toss/GGP/TranslateGame.mli trunk/Toss/GGP/TranslateGameTest.ml trunk/Toss/Server/ReqHandler.ml trunk/Toss/Server/Tests.ml Modified: trunk/Toss/GGP/GDL.mli =================================================================== --- trunk/Toss/GGP/GDL.mli 2011-07-26 19:50:54 UTC (rev 1517) +++ trunk/Toss/GGP/GDL.mli 2011-07-26 21:50:38 UTC (rev 1518) @@ -77,6 +77,9 @@ negation of disjunction of given clause bodies. *) val negate_bodies : literal list list -> literal list list +val func_graph : string -> term list -> term array list + + (** {3 GDL translation helpers.} *) val blank : term Modified: trunk/Toss/GGP/GDLParser.mly =================================================================== --- trunk/Toss/GGP/GDLParser.mly 2011-07-26 19:50:54 UTC (rev 1517) +++ trunk/Toss/GGP/GDLParser.mly 2011-07-26 21:50:38 UTC (rev 1518) @@ -28,7 +28,7 @@ | c=WORD { Const c } | sexp=delimited (OPEN, list (term), CLOSE) { match sexp with - | Const c::args -> Func (c, args) + | Const c::args -> Func (c, Array.of_list args) | _ -> raise (Lexer.Parsing_error "GDL term: not a constant head") } | error { @@ -37,29 +37,29 @@ atom: | r=WORD { - if r="TERMINAL" then Rel ("terminal", []) - else Rel (r, []) } + if r="TERMINAL" then Rel ("terminal", [||]) + else Rel (r, [||]) } | sexp=delimited (OPEN, list (term), CLOSE) { match sexp with | (Const "distinct" | Const "DISTINCT")::args -> - Distinct args + Distinct (Array.of_list args) | [(Const "true" | Const "TRUE"); arg] -> True arg | [(Const "does" | Const "DOES"); player; action] -> Does (player, action) | (Const "role" | Const "ROLE")::player -> - Role player + Role (List.hd player) (* FIXME!!! *) | (Const "init" | Const "INIT")::state -> - Rel ("init", state) + Rel ("init", Array.of_list state) | (Const "next" | Const "NEXT")::state -> - Rel ("next", state) + Rel ("next", Array.of_list state) | (Const "terminal" | Const "TERMINAL")::no_arg -> - Rel ("terminal", no_arg) + Rel ("terminal", Array.of_list no_arg) | (Const "legal" | Const "LEGAL")::args -> - Rel ("legal", args) + Rel ("legal", Array.of_list args) | (Const "goal" | Const "GOAL")::args -> - Rel ("goal", args) - | Const r::args -> Rel (r, args) + Rel ("goal", Array.of_list args) + | Const r::args -> Rel (r, Array.of_list args) | _ -> raise (Lexer.Parsing_error "GDL atom: not a constant head") } | error { @@ -75,7 +75,7 @@ | OPEN REVIMPL head=atom body=list (literal) CLOSE { match head with | Rel rel_atom -> rel_atom, body - | Role player -> ("role", [player]), body + | Role player -> ("role", [|player|]), body | True _ -> raise (Lexer.Parsing_error "GDL rule: \"true\" in head") | Distinct _ -> @@ -85,7 +85,7 @@ } | a=atom { match a with - | Role player -> ("role", [player]), [] + | Role player -> ("role", [|player|]), [] | Rel rel_atom -> rel_atom, [] | _ -> raise (Lexer.Parsing_error Modified: trunk/Toss/GGP/GDLTest.ml =================================================================== --- trunk/Toss/GGP/GDLTest.ml 2011-07-26 19:50:54 UTC (rev 1517) +++ trunk/Toss/GGP/GDLTest.ml 2011-07-26 21:50:38 UTC (rev 1518) @@ -39,15 +39,14 @@ | _, [] -> true | [], _ -> aux players playout | player::turn, state::playout -> - if GDL.func_graph "control" state <> [[player]] - then false - else aux turn playout in + if GDL.func_graph "control" state <> [[|player|]] then false else + aux turn playout in aux players playout let tests = "GDL" >::: [ - "saturate" >:: +(* "saturate" >:: (fun () -> let descr = parse_game_descr " @@ -76,7 +75,7 @@ "(a 1) (a 2) (a 3) (two-of-three 1 2) (two-of-three 1 3) (two-of-three 2 1) (two-of-three 2 3) (two-of-three 3 1) (two-of-three 3 2)" (String.concat " " (List.map GDL.fact_str res)); - ); + ); "saturate recursive" >:: (fun () -> @@ -103,7 +102,7 @@ "(lte 0 0) (lte 0 1) (lte 0 2) (lte 0 3) (lte 0 4) (lte 0 5) (lte 0 6) (lte 0 7) (lte 0 8) (lte 1 1) (lte 1 2) (lte 1 3) (lte 1 4) (lte 1 5) (lte 1 6) (lte 1 7) (lte 1 8) (lte 2 2) (lte 2 3) (lte 2 4) (lte 2 5) (lte 2 6) (lte 2 7) (lte 2 8) (lte 3 3) (lte 3 4) (lte 3 5) (lte 3 6) (lte 3 7) (lte 3 8) (lte 4 4) (lte 4 5) (lte 4 6) (lte 4 7) (lte 4 8) (lte 5 5) (lte 5 6) (lte 5 7) (lte 5 8) (lte 6 6) (lte 6 7) (lte 6 8) (lte 7 7) (lte 7 8) (lte 8 8) (number 0) (number 1) (number 2) (number 3) (number 4) (number 5) (number 6) (number 7) (number 8) (succ 0 1) (succ 1 2) (succ 2 3) (succ 3 4) (succ 4 5) (succ 5 6) (succ 6 7) (succ 7 8)" (String.concat " " (List.map GDL.fact_str res)); - ); + ); *) ] let exec = Aux.run_test_if_target "GDLTest" tests Modified: trunk/Toss/GGP/TranslateFormula.ml =================================================================== --- trunk/Toss/GGP/TranslateFormula.ml 2011-07-26 19:50:54 UTC (rev 1517) +++ trunk/Toss/GGP/TranslateFormula.ml 2011-07-26 21:50:38 UTC (rev 1518) @@ -64,6 +64,16 @@ term_arities : (string * int) list; } +let empty_transl_data = { + f_paths = empty_path_set; + m_paths = empty_path_set; + all_paths = empty_path_set; + mask_reps = []; + defined_rels = []; + defrel_arg_type = ref []; + term_arities = []; +} + let blank_out data t = simult_subst data.f_paths blank t Modified: trunk/Toss/GGP/TranslateFormula.mli =================================================================== --- trunk/Toss/GGP/TranslateFormula.mli 2011-07-26 19:50:54 UTC (rev 1517) +++ trunk/Toss/GGP/TranslateFormula.mli 2011-07-26 21:50:38 UTC (rev 1518) @@ -13,5 +13,7 @@ term_arities : (string * int) list; } +val empty_transl_data : transl_data + val translate : transl_data -> GDL.literal list list -> Formula.formula Modified: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml 2011-07-26 19:50:54 UTC (rev 1517) +++ trunk/Toss/GGP/TranslateGame.ml 2011-07-26 21:50:38 UTC (rev 1518) @@ -64,6 +64,24 @@ (* term representatives of structure elements *) } +let empty_gdl_translation = { + elem_term_map = Aux.IntMap.empty; + f_paths = empty_path_set; + m_paths = empty_path_set; + masks = []; + tossrule_data = Aux.StrMap.empty; + turnbased_noops = None; + playing_as = 0; + is_concurrent = false; + transl_data = TranslateFormula.empty_transl_data; + element_terms = Aux.IntMap.empty; +} + +let our_turn gdl state = true + +let noop_move gdl state = "NOOP" + + (* [most_similar c ts] finds a term from [ts] most similar to [c], and the set of paths that merges the found term and [c]; as in the definition of $s_\calC$ and $t_\calC$ for a clause $\calC \in Modified: trunk/Toss/GGP/TranslateGame.mli =================================================================== --- trunk/Toss/GGP/TranslateGame.mli 2011-07-26 19:50:54 UTC (rev 1517) +++ trunk/Toss/GGP/TranslateGame.mli 2011-07-26 21:50:38 UTC (rev 1518) @@ -1,5 +1,5 @@ type tossrule_data = { - lead_legal : GDL.term; + legal_tuple : GDL.term; (* the "legal"/"does" term of the player that performs the move, we call its parameters "fixed variables" as they are provided externally *) precond : Formula.formula; @@ -8,26 +8,25 @@ (* the elements of LHS/RHS structures, corresponding to the "next" terms *) struc_elems : string list; - fixvar_elemvars : - (string * (GDL.term * (string * string list) list) list) list; - (* "state" terms indexed by variables that they contain, together - with the mask-path of the variable *) - elemvars : GDL.term Aux.StrMap.t; -(* "state" terms indexed by Toss variable names they generate *) + fixvar_terms : (string * (GDL.term * GDL.path) list) list; + rulevar_terms : GDL.term Aux.StrMap.t; } (** Data to be used when translating moves. *) -type gdl_translation = { - (* map between structure elements and their term representations; - the reverse direction is by using element names *) - elem_term_map : GDL.term Aux.IntMap.t; - f_paths : GDL.path_set; - m_paths : GDL.path_set; - masks : GDL.term list; - tossrule_data : tossrule_data Aux.StrMap.t; - (* rule name to rule translation data *) -} +type gdl_translation +val empty_gdl_translation : gdl_translation val translate_game : GDL.clause list -> gdl_translation * (Arena.game * Arena.game_state) + +val translate_incoming_move : + gdl_translation -> (Arena.game * Arena.game_state) -> GDL.term list -> + string * (int * int) list + +val translate_outgoing_move : gdl_translation -> + (Arena.game * Arena.game_state) -> string -> (int * int) list -> string + +val noop_move : gdl_translation -> Arena.game_state -> string + +val our_turn : gdl_translation -> (Arena.game * Arena.game_state) -> bool Modified: trunk/Toss/GGP/TranslateGameTest.ml =================================================================== --- trunk/Toss/GGP/TranslateGameTest.ml 2011-07-26 19:50:54 UTC (rev 1517) +++ trunk/Toss/GGP/TranslateGameTest.ml 2011-07-26 21:50:38 UTC (rev 1518) @@ -39,16 +39,15 @@ | _, [] -> true | [], _ -> aux players playout | player::turn, state::playout -> - if GDL.func_graph "control" state <> [[player]] - then false - else aux turn playout in + if GDL.func_graph "control" state <> [[|player|]] then false else + aux turn playout in aux players playout let game_test_case ~game_name ~player ~loc0_rule_name ~loc0_emb ~loc0_move ~loc0_noop ~loc1 ~loc1_rule_name ~loc1_emb ~loc1_noop ~loc1_move = let game = load_rules ("./GGP/examples/"^game_name^".gdl") in - let gdl, res = Translate.translate_game (Const player) game in + let gdl, res = TranslateGame.translate_game (*Const player*) game in let goal_name = (*if !GDL.prune_rulecands_at = GDL.Never then game_name^"-simpl-unpruned.toss" @@ -70,10 +69,10 @@ let emb = Arena.emb_of_names res rname loc0_emb in let transl = - Translate.translate_outgoing_move gdl res rname emb in + TranslateGame.translate_outgoing_move gdl res rname emb in assert_equal ~printer:(fun x->x) loc0_move transl; let move = - Translate.translate_incoming_move gdl res + TranslateGame.translate_incoming_move gdl res [pte loc0_move; pte loc0_noop] in assert_equal ~msg:"own incoming move" ~printer:(emb_str res) (norm_move (rname, emb)) (norm_move move); @@ -84,15 +83,15 @@ let emb = Arena.emb_of_names res rname loc1_emb in let move = - Translate.translate_incoming_move gdl res + TranslateGame.translate_incoming_move gdl res [pte loc1_noop; pte loc1_move] in assert_equal ~msg:"opponent incoming move" ~printer:(emb_str res) (norm_move (rname, emb)) (norm_move move) -let tests = "Translate" >::: [ - +let tests = "TranslateGame" >::: [ + (* "expand_def_rules" >:: (fun () -> let descr = parse_game_descr @@ -126,10 +125,10 @@ "cell_x71_y26__blank_", "cell_1_1_MV1"; "control__blank_", "control_MV1"] ~loc1_noop:"noop" ~loc1_move:"(mark 1 1)" - ); + ); *) ] -let bigtests = "TranslateBig" >::: [ +let bigtests = "TranslateGameBig" >::: [ "connect5" >:: (fun () -> @@ -186,10 +185,10 @@ let a = - Aux.run_test_if_target "TranslateTest" tests + Aux.run_test_if_target "TranslateGameTest" tests let a = - Aux.run_test_if_target "TranslateTest" bigtests + Aux.run_test_if_target "TranslateGameTest" bigtests let a () = GDL.debug_level := 4; @@ -205,10 +204,9 @@ | Some tests -> ignore (run_test_tt ~verbose:true tests) | None -> () -let regenerate ~debug ~game_name ~player = +(* let regenerate ~debug ~game_name ~player = Printf.printf "Regenerating %s...\n%!" game_name; if debug then ( - Translate.debug_level := 4; GameSimpl.debug_level := 4; DiscreteRule.debug_level := 4); Translate.generate_test_case := Some game_name; @@ -222,3 +220,4 @@ regenerate ~debug:false ~game_name:"breakthrough" ~player:"white"; (* regenerate ~debug:true ~game_name:"pawn_whopping" ~player:"x"; *) (* regen_with_debug ~game_name:"connect4" ~player:"white" *) +*) Modified: trunk/Toss/Server/ReqHandler.ml =================================================================== --- trunk/Toss/Server/ReqHandler.ml 2011-07-26 19:50:54 UTC (rev 1517) +++ trunk/Toss/Server/ReqHandler.ml 2011-07-26 21:50:38 UTC (rev 1518) @@ -17,11 +17,11 @@ Formula.real_expr array array option (** heuristic option *) * bool (** game modified *) * (Arena.game * Arena.game_state) (** game and state *) - * Translate.gdl_translation (** current gdl translation *) + * TranslateGame.gdl_translation (** current gdl translation *) * int (** playclock *) let init_state = - (None, true, Arena.empty_state, Translate.empty_gdl_translation, 0) + (None, true, Arena.empty_state, TranslateGame.empty_gdl_translation, 0) (* TODO; FIXME; remove the function below. *) @@ -83,12 +83,9 @@ Random.self_init (); let old_force_competitive = !Heuristic.force_competitive in Heuristic.force_competitive := true; - let new_state, params, new_gdl_transl = - Translate.initialize_game player game_descr startcl in - let effort, horizon, advr = - match params with - | Some (e,h,r) -> Some e, Some h, Some r - | None -> None, None, None in + let new_gdl_transl, new_state = + TranslateGame.translate_game game_descr in + let effort, horizon, advr = (None, None, None) in let new_heur = Heuristic.default_heuristic ~struc:(snd new_state).Arena.struc ?advr (fst new_state) in @@ -101,7 +98,7 @@ let time_started = Unix.gettimeofday () in let r_name, mtch = - Translate.translate_last_action gdl_transl state actions in + TranslateGame.translate_incoming_move gdl_transl state actions in let state = if r_name <> "" then ( @@ -136,7 +133,7 @@ else let mov_msg = let time_used = time_started -. Unix.gettimeofday () in - if Translate.our_turn gdl_transl state then ( + if TranslateGame.our_turn gdl_transl state then ( Play.set_timeout (float(playclock) -. time_used -. 0.07); let heur = match g_heur with | Some h -> h @@ -144,11 +141,11 @@ let (move, _) = Aux.random_elem (Play.maximax_unfold_choose 5500 (fst state) (snd state) heur) in - Translate.translate_move gdl_transl state + TranslateGame.translate_outgoing_move gdl_transl state move.Move.rule move.Move.embedding ) else ( Gc.compact (); - Translate.noop_move gdl_transl (snd state) + TranslateGame.noop_move gdl_transl (snd state) ) in let msg_len = String.length mov_msg in ("HTTP/1.0 200 OK\r\nContent-type: text/acl\r\nContent-length: " Modified: trunk/Toss/Server/Tests.ml =================================================================== --- trunk/Toss/Server/Tests.ml 2011-07-26 19:50:54 UTC (rev 1517) +++ trunk/Toss/Server/Tests.ml 2011-07-26 21:50:38 UTC (rev 1518) @@ -32,9 +32,9 @@ ] let ggp_tests = "GGP", [ - "GameSimplTest", [GameSimplTest.tests]; - "GDLTest", [GDLTest.tests]; - "TranslateTest", [TranslateTest.tests; TranslateTest.bigtests]; + "GameSimplTest", [GameSimplTest.tests]; + "GDLTest", [GDLTest.tests]; + "TranslateGameTest", [TranslateGameTest.tests; TranslateGameTest.bigtests]; ] let server_tests = "Server", [ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-26 19:51:02
|
Revision: 1517 http://toss.svn.sourceforge.net/toss/?rev=1517&view=rev Author: lukstafi Date: 2011-07-26 19:50:54 +0000 (Tue, 26 Jul 2011) Log Message: ----------- GDL translation work in progress (simple debugging). Does not compile yet. Modified Paths: -------------- trunk/Toss/GGP/GDL.ml trunk/Toss/GGP/GDL.mli trunk/Toss/GGP/TranslateFormula.ml trunk/Toss/GGP/TranslateFormula.mli trunk/Toss/GGP/TranslateGame.ml trunk/Toss/www/reference/reference.tex Modified: trunk/Toss/GGP/GDL.ml =================================================================== --- trunk/Toss/GGP/GDL.ml 2011-07-19 15:20:56 UTC (rev 1516) +++ trunk/Toss/GGP/GDL.ml 2011-07-26 19:50:54 UTC (rev 1517) @@ -18,20 +18,22 @@ | Var of string | Func of string * term array -type rel_atom = string * term list +type rel_atom = string * term array (** Positive and negative literals separated, disjunctions expanded-out. *) type gdl_rule = rel_atom * rel_atom list * rel_atom list (** Collect rules by relations. *) -type def_branch = term list * rel_atom list * rel_atom list +type def_branch = term array * rel_atom list * rel_atom list type gdl_defs = (string * def_branch list) list +type substitution = (string * term) list + module Terms = Set.Make ( struct type t = term let compare = Pervasives.compare end) module Atoms = Set.Make ( struct type t = rel_atom let compare = Pervasives.compare end) type atom = - | Distinct of term list + | Distinct of term array | Rel of rel_atom | Role of term | True of term @@ -58,15 +60,15 @@ | Var v -> "?"^v | Func (f, args) -> "(" ^ f ^ " " ^ - String.concat " " (List.map term_str (Array.to_list args)) ^ ")" + String.concat " " (Array.to_list (Array.map term_str args)) ^ ")" let rec term_to_name ?(nested=false) = function | Const c -> c | Var v -> v | Func (f, args) -> f ^ "_" ^ (if nested then "_S_" else "") ^ - String.concat "_" (List.map (term_to_name ~nested:true) - (Array.to_list args)) ^ + String.concat "_" + (Array.to_list (Array.map (term_to_name ~nested:true) args)) ^ (if nested then "_Z_" else "") let rec term_vars = function @@ -75,27 +77,36 @@ | Func (f, args) -> terms_vars args and terms_vars args = - List.fold_left Aux.Strings.union Aux.Strings.empty - (List.map term_vars (Array.to_list args)) + Array.fold_left Aux.Strings.union Aux.Strings.empty + (Array.map term_vars args) +let rec atoms_of_body body = + Aux.concat_map + (function Pos a -> [a] | Neg a -> [a] + | Disj ds -> atoms_of_body ds) body +let atoms_of_clause (rel_atom, body) = + Rel rel_atom :: atoms_of_body body + let rel_of_atom = function - | Distinct args -> "distinct", args (* not a proper relation -- avoid *) + | Distinct args -> "distinct", args + (* not a proper relation -- avoid *) | Rel (rel, args) -> rel, args - | Role arg -> "role", [arg] - | True arg -> "true", [arg] - | Does (arg1, arg2) -> "does", [arg1; arg2] + | Role arg -> "role", [|arg|] + | True arg -> "true", [|arg|] + | Does (arg1, arg2) -> "does", [|arg1; arg2|] let atom_of_rel = function - | "distinct", args -> Distinct args (* not a proper relation -- avoid *) - | "role", [arg] -> Role arg - | "true", [arg] -> True arg - | "does", [arg1; arg2] -> Does (arg1, arg2) + | "distinct", args -> Distinct args + (* not a proper relation -- avoid *) + | "role", [|arg|] -> Role arg + | "true", [|arg|] -> True arg + | "does", [|arg1; arg2|] -> Does (arg1, arg2) | rel, args -> Rel (rel, args) let rec body_of_literal = function | Pos (Distinct args) -> - [Aux.Right ("distinct", args)] (* not negated actually! *) + [Aux.Right ("distinct", args)] (* not negated actually! *) | Neg (Distinct _) -> assert false | Pos atom -> [Aux.Left (rel_of_atom atom)] | Neg atom -> [Aux.Right (rel_of_atom atom)] @@ -106,33 +117,31 @@ Aux.map_some (function Func (g, args) when f=g -> Some args | _-> None) terms -let gdl_rule_vars (head, body, neg_body) = +let gdl_rule_vars ((_,head_args), body, neg_body) = List.fold_left Aux.Strings.union Aux.Strings.empty (List.map terms_vars - (head::List.map snd (body @ neg_body))) + (head_args::List.map snd (body @ neg_body))) let gdl_rules_vars brs = List.fold_left Aux.Strings.union Aux.Strings.empty (List.map gdl_rule_vars brs) -let rels_vars body = +let rels_vars (body : (string * term array) list) = List.fold_left Aux.Strings.union Aux.Strings.empty (List.map (fun (_,args)->terms_vars args) body) let gdl_defs_vars defs = - List.fold_left - (fun acc rels -> Aux.Strings.union acc (rels_vars rels)) - Aux.Strings.empty - (Aux.concat_map (fun (hd,body,neg_body) -> - ("",hd)::body @ neg_body) (Aux.concat_map snd defs)) + rels_vars + (Aux.concat_map (fun (hd,body,neg_body) -> + ("",hd)::body @ neg_body) (Aux.concat_map snd defs)) -let rules_of_clause (head, body) = +let rule_of_clause (head, body) = let body, neg_body = Aux.partition_choice (Aux.concat_map body_of_literal body) in head, body, neg_body -let clause_vars cl = gdl_rule_vars (rules_of_clause cl) +let clause_vars cl = gdl_rule_vars (rule_of_clause cl) let defs_of_rules rules = Aux.map_reduce (fun ((rel, args), body, neg_body) -> @@ -191,7 +200,7 @@ | Var y when x=y -> term | (Const _ | Var _ as t) -> t | Func (f, args) -> - Func (f, List.map (subst_one sb) args) + Func (f, Array.map (subst_one sb) args) (* Eliminate [terms1] variables when possible. *) let rec unify sb terms1 terms2 = @@ -200,7 +209,7 @@ | Const a::terms1, Const b::terms2 when a=b -> unify sb terms1 terms2 | Func (f,args1)::terms1, Func (g,args2)::terms2 when f=g -> - unify sb (args1 @ terms1) (args2 @ terms2) + unify sb (Array.to_list args1 @ terms1) (Array.to_list args2 @ terms2) | Var x::terms1, Var y::terms2 when x=y -> unify sb terms1 terms2 | (Var x::terms1, (Var _ | Const _ as term)::terms2 @@ -219,13 +228,15 @@ (List.map (subst_one sb1) terms2) | _ -> raise Not_found +let unify_args args1 args2 = + unify [] (Array.to_list args1) (Array.to_list args2) let rec subst sb = function | Var y as t -> (try List.assoc y sb with Not_found -> t) | Const _ as t -> t | Func (f, args) -> - Func (f, List.map (subst sb) args) + Func (f, Array.map (subst sb) args) let rec unify_all sb = function | [] | [_] -> sb @@ -241,14 +252,14 @@ with Not_found -> false let unify_rels (rel1, args1) (rel2, args2) = - if rel1 = rel2 then unify [] args1 args2 + if rel1 = rel2 then unify_args args1 args2 else raise Not_found let rels_unify atom1 atom2 = try ignore (unify_rels atom1 atom2); true with Not_found -> false -let subst_rel sb (rel, args) = rel, List.map (subst sb) args +let subst_rel sb (rel, args) = rel, Array.map (subst sb) args let subst_rels sb body = List.map (subst_rel sb) body let compose_sb sb1 sb2 = @@ -258,13 +269,13 @@ unify [] var_terms (terms1 @ terms2) let subst_br sb (args, body, neg_body) = - List.map (subst sb) args, + Array.map (subst sb) args, subst_rels sb body, - List.map (fun (uni_vs,neg) -> uni_vs, subst_rels sb neg) neg_body + subst_rels sb neg_body let subst_atom sb = function - | Distinct args -> Distinct (List.map (subst sb) args) + | Distinct args -> Distinct (Array.map (subst sb) args) | Rel rel_atom -> Rel (subst_rel sb rel_atom) | Role arg -> Role (subst sb arg) | True arg -> True (subst sb arg) @@ -279,13 +290,9 @@ subst_rel sb head, List.map (subst_literal sb) body let rel_atom_str (rel, args) = - "(" ^ rel ^ " " ^ String.concat " " (List.map term_str args) ^ ")" + "(" ^ rel ^ " " ^ + String.concat " " (Array.to_list (Array.map term_str args)) ^ ")" -let tuples_str tups = - let tup_str tup = - "("^String.concat " " (List.map term_str tup) ^")" in - String.concat " " (List.map tup_str tups) - let terms_str facts = String.concat ", " (List.map term_str facts) @@ -309,7 +316,7 @@ String.concat ", " (List.map (fun (v,t)->v^":="^term_str t) sb) let proto_rel_str (rel, args) = - rel ^"(" ^ String.concat ", " (Array.to_list args) ^")" + rel ^"(" ^ String.concat ", " args ^")" (* TODO: optimize by using rel-indexing (also in [aggregate_playout]). @@ -317,16 +324,17 @@ (* Variables still left after saturation have universal interpretation! *) let saturate base rules = - let instantiate_one tot_base cur_base irules = + let instantiate_one (tot_base : rel_atom list) + (cur_base : rel_atom list) irules = Aux.concat_map (function | head, [], neg_body -> if List.mem head tot_base then [] else if List.exists (fun (rel,args as neg_atom) -> - rel = "distinct" && Aux.not_unique args || + rel = "distinct" && Aux.not_unique (Array.to_list args) || (* faster option: *) (* List.mem neg_atom tot_base *) (* accurate option: *) - List.exists (unifies neg_atom) tot_base + List.exists (rels_unify neg_atom) tot_base ) neg_body then [] else [Aux.Left head] | head, cond1::body, neg_body -> @@ -423,27 +431,28 @@ v, Aux.not_conflicting_name ~truncate:true !used_vars v) (Aux.Strings.elements br_vars) in used_vars := Aux.add_strings (List.map snd sb) !used_vars; + let sb = List.map (fun (v,t) -> v, Var t) sb in List.map (subst_br sb) brs in - let expand_atom (rel, args as atom) result = + (* FIXME: make sure it's OK!!! *) + let expand_atom (rel, args as atom) + (sb, (head, r_body, r_neg_body)) = (let try def_brs = freshen_brs (List.assoc rel defs) in - Aux.concat_map (fun (sb, (head, r_body, r_neg_body)) -> - let args = subst_terms sb args in - List.map (fun (params,d_body,d_neg_body) -> - let sb = unify sb params args in - let r_br = - head, d_body @ r_body, d_neg_body @ r_neg_body in - sb, subst_br sb r_br - ) def_brs - ) result + let args = Array.map (subst sb) args in + List.map (fun (params,d_body,d_neg_body) -> + let sb = unify sb (Array.to_list params) (Array.to_list args) in + let r_br = + head, d_body @ r_body, d_neg_body @ r_neg_body in + sb, subst_br sb r_br + ) def_brs with Not_found -> - List.map (fun (sb,(head,r_body,r_neg_body)) -> - sb, atom::r_body, r_neg_body) result) in + [sb, (head, atom::r_body, r_neg_body)]) in let expand_br (head, body, neg_body) = let init = [[], (head, [], neg_body)] in Aux.concat_foldr expand_atom body init in let rec fix n_brs brs i = let brs = Aux.concat_map expand_br brs in let new_n_brs = List.length brs in + let brs = List.map snd brs in if new_n_brs > n_brs && i > 0 then fix new_n_brs brs (i-1) else brs in fix (List.length brs) brs 5 @@ -454,19 +463,19 @@ let negate_bodies conjs = let placeholder = "", [] in let clauses = List.map (fun body -> placeholder, body) conjs in - let clauses = List.map rules_of_clause clauses in + let clauses = List.map rule_of_clause clauses in let clauses = List.map (fun (_,body,neg_body) -> - List.map (fun a -> Pos (atom_of_clause a)) body @ - List.map (fun a -> Neg (atom_of_clause a)) neg_body) clauses in + List.map (fun a -> Pos (atom_of_rel a)) body @ + List.map (fun a -> Neg (atom_of_rel a)) neg_body) clauses in let negated = Aux.product clauses in (* can raise [Not_found] in case of unsatisfiable "not distinct" *) let nclause body = let uniterms, lits = Aux.partition_map (function - | Neg (Distinct terms) -> Left terms - | Neg atom -> Pos atom - | Pos atom -> Neg atom - | Disjunction _ -> assert false) body in + | Neg (Distinct terms) -> Aux.Left (Array.to_list terms) + | Neg atom -> Aux.Right (Pos atom) + | Pos atom -> Aux.Right (Neg atom) + | Disj _ -> assert false) body in let sb = List.fold_left unify_all [] uniterms in List.map (subst_literal sb) lits in Aux.map_try nclause negated @@ -482,8 +491,8 @@ List.map (fun v -> let nv = Aux.not_conflicting_name ~truncate:true !used_vars v in used_vars := Aux.Strings.add nv !used_vars; - v, nv - ) cl_vars in + v, Var nv + ) (Aux.Strings.elements cl_vars) in subst_clause sb cl ) clauses in used_vars, clauses @@ -507,7 +516,7 @@ | Pos a -> Neg a | Neg a -> Pos a | _ -> assert false) lits - ) (List.map flatten_disjs body) + ) (flatten_disjs body) (* ************************************************************ *) @@ -522,7 +531,7 @@ let aggregate_ply players static current rules = let base = - Aux.map_prepend static (fun term -> "true", [term]) current in + Aux.map_prepend static (fun term -> "true", [|term|]) current in let base = saturate (base @ static) rules in (* {{{ log entry *) if !debug_level > 4 then ( @@ -535,15 +544,15 @@ if (* no move *) Aux.array_existsi (fun _ player -> List.for_all (function - |_, (Var _::_) -> false - | _, (actor::_) -> player <> actor | _ -> true) + |_, [|Var _; _ |] -> false + | _, [|actor; _ |] -> player <> actor | _ -> true) does) players then ( (* {{{ log entry *) if !debug_level > 0 then ( let players_nomove = Aux.array_find_all (fun player -> - List.for_all (function _, (actor::_) -> player <> actor + List.for_all (function _, [|actor; _|] -> player <> actor | _ -> true) does) players in Printf.printf @@ -554,11 +563,11 @@ raise Playout_over) else let step = saturate (does @ base) rules in - let step = Aux.map_some (function ("next", [arg]) -> Some arg + let step = Aux.map_some (function ("next", [|arg|]) -> Some arg | _ -> None) step in if !aggregate_fixpoint && (* fixpoint reached *) List.for_all (function - | Func (_,[arg]) when + | Func (_,[|arg|]) when Aux.array_existsi (fun _ player -> arg=player) players -> true | term -> List.mem term current ) step @@ -594,8 +603,8 @@ let static_base = saturate [] static_rules in let state_rules = List.map (function - | ("legal", [player; _] as head), body, neg_body -> - head, ("role", [player])::body, + | ("legal", [|player; _|] as head), body, neg_body -> + head, ("role", [|player|])::body, if !aggregate_drop_negative then [] else neg_body | ("does", _ (* as head *)), body, _ -> assert false (* head, body, [] *) @@ -624,7 +633,7 @@ (* FIXME: this is identity, right? remove *) let init_base = saturate static_base state_rules in let init_state = - Aux.map_some (function ("init", [arg]) -> Some arg + Aux.map_some (function ("init", [|arg|]) -> Some arg | _ -> None) init_base in (* {{{ log entry *) if !debug_level > 0 then ( @@ -664,18 +673,23 @@ loop [] [] [] [] cands +let player_vars_of rels = + Aux.map_some (function + | "does", [|Var v; _|] -> Some v + | "legal", [|Var v; _|] -> Some v + | _ -> None) rels + + let expand_players clauses = let players = Aux.map_some (function - | ("role", [player]), _ -> Some player + | ("role", [|player|]), _ -> Some player | _ -> None ) clauses in - let exp_clause (rel, _ as head, body as clause) = + let exp_clause clause = (* determine variables standing for players *) let plvars = - let head = if rel = "role" then [] else [head] in - Aux.concat_map player_vars_of - (head @ List.map rel_of_atom body) in + player_vars_of (List.map rel_of_atom (atoms_of_clause clause)) in if plvars = [] then [clause] else let sbs = List.map (fun v -> @@ -700,7 +714,7 @@ else aux (more @ nonstable) (List.filter (fun (rel,_) -> not (List.mem rel more)) remaining) in - aux [] remaining + aux [] defs let state_terms body = @@ -735,6 +749,8 @@ | Here_and_below of (string * path_set array) list (* Subtries are in sorted order. *) +let empty_path_set = Empty + let path_str p = String.concat "_" (List.map (fun (rel, arg) -> rel ^ "_" ^ string_of_int arg) p) @@ -742,7 +758,10 @@ let paths_union ps1 ps2 = let rec aux = function | Empty, p | p, Empty -> p - | Here, Below ps | Below ps, Here -> Here_and_below ps + | Here, Here -> Here + | Here, Below ps | Below ps, Here + | Here, Here_and_below ps + | Here_and_below ps, Here -> Here_and_below ps | Below ps1, Below ps2 -> Below (merge (ps1, ps2)) | Below ps1, Here_and_below ps2 | Here_and_below ps2, Below ps1 @@ -751,7 +770,7 @@ and merge = function | [], ps | ps, [] -> ps | ((rel1, args1)::ps1), ((rel2, args2)::ps2) when rel1 = rel2 -> - let args = Aux.array_map2 aux args1 args2 in + let args = Aux.array_map2 (fun x y->aux (x,y)) args1 args2 in (rel1, args)::merge (ps1, ps2) | ((rel1, _ as rel_ps)::ps1), ((rel2, _)::_ as ps2) when rel1 < rel2 -> rel_ps::merge (ps1, ps2) @@ -761,12 +780,16 @@ let add_path arities p ps = let rec aux = function - | [], Empty -> Here + | [], (Here | Empty) -> Here | [], (Below ps | Here_and_below ps) -> Here_and_below ps | (rel, pos)::suffix, Below ps -> Below (add suffix rel pos ps) | (rel, pos)::suffix, Here_and_below ps -> Here_and_below (add suffix rel pos ps) + | (rel, pos)::suffix, Empty -> + Below (add suffix rel pos []) + | (rel, pos)::suffix, Here -> + Here_and_below (add suffix rel pos []) and add p rel pos ps = (let try args, ps = Aux.pop_assoc rel ps in (* Keeping functional... *) @@ -806,7 +829,7 @@ aux (ps, t) (** Find the subterm at given path, if the term does not have the - path, return [Not_found]; [at_path p t] is $t \tpos p$. *) + path, raise [Not_found]; [at_path p t] is $t \tpos p$. *) let at_path t p = let rec aux = function | [], t -> t @@ -825,13 +848,13 @@ | Empty, t -> [] | Here, t -> [t] | Here_and_below subps, t -> t::(aux (Below subps, t)) - | Below subps, (Func (rel, args) as t) + | Below subps, (Func (rel, args)) when not fail_at_missing -> (let try argps = List.assoc rel subps in let res = Aux.array_map2 (fun ps t -> aux (ps,t)) argps args in List.concat (Array.to_list res) with Not_found -> []) - | Below [rel1, argps], (Func (rel2, args) as t) + | Below [rel1, argps], (Func (rel2, args)) when rel1 = rel2 (* && fail_at_missing *) -> let res = Aux.array_map2 (fun ps t -> aux (ps,t)) argps args in List.concat (Array.to_list res) @@ -845,8 +868,8 @@ | Empty, t -> [] | Here, t -> [f (List.rev revp) t] | Here_and_below subps, t -> - f (List.rev revp) t::(aux path (Below subps, t)) - | Below subps, (Func (rel, args) as t) -> + f (List.rev revp) t::(aux revp (Below subps, t)) + | Below subps, (Func (rel, args)) -> (let try argps = List.assoc rel subps in let res = Array.mapi (fun i ps -> aux ((rel,i)::revp) (ps,args.(i))) argps in @@ -860,13 +883,14 @@ that has been included, are not included. *) let rec term_paths ?(prefix_only=false) cond = function | Func (rel, args) as t -> - let subps = Array.map (term_paths p) args in - let no_sub = Array.for_all (fun subp -> subp = Empty) subps in + let subps = Array.map (term_paths ~prefix_only cond) args in + let no_sub = Aux.array_for_all (fun subp -> subp = Empty) subps in let here = cond t in if no_sub && not here then Empty - else if here && not no_sub && not prefix_only then Here_and_below subps + else if here && not no_sub && not prefix_only + then Here_and_below [rel, subps] else if here then Here - else Below subps + else Below [rel, subps] | t -> if cond t then Here else Empty (** The number of nodes in a term tree. *) @@ -894,10 +918,11 @@ let paths_to_list ps = let rec subpaths subps = Aux.concat_map (fun (rel, subps) -> - Array.to_list - (Array.mapi (fun i ps -> - let sub_res = aux ps in - List.map (fun p -> (rel, i)::p) sub_res) subps)) subps + List.concat + (Array.to_list + (Array.mapi (fun i ps -> + let sub_res = aux ps in + List.map (fun p -> (rel, i)::p) sub_res) subps))) subps and aux = function | Empty -> [] | Here -> [[]] Modified: trunk/Toss/GGP/GDL.mli =================================================================== --- trunk/Toss/GGP/GDL.mli 2011-07-19 15:20:56 UTC (rev 1516) +++ trunk/Toss/GGP/GDL.mli 2011-07-26 19:50:54 UTC (rev 1517) @@ -5,34 +5,16 @@ val aggregate_drop_negative : bool ref val aggregate_fixpoint : bool ref -(** Expand static relations that do not have ground facts and have - arity above the threshold. *) -val expand_arity_above : int ref +(** {3 Datalog programs: Type definitions and saturation.} *) -(** Treat "next" clauses which introduce metavariables only for - variable-variable mismatch, as non-erasing frame clauses (to be - ignored). ("Wave" refers to the process of "propagating the frame - condition" that these clauses are assumed to do, if - [nonerasing_frame_wave] is set to [true].) *) -val nonerasing_frame_wave : bool ref - type term = | Const of string | Var of string - | Func of string * term list + | Func of string * term array -type rel_atom = string * term list -(** Positive and negative literals separated, disjunctions expanded-out. *) -type gdl_rule = rel_atom * rel_atom list * rel_atom list -(** Collect rules by relations. *) -type def_branch = term list * rel_atom list * rel_atom list -type gdl_defs = (string * def_branch list) list - -module Terms : Set.S with type elt = term -module Atoms : Set.S with type elt = rel_atom - +type rel_atom = string * term array type atom = - | Distinct of term list + | Distinct of term array | Rel of rel_atom | Role of term | True of term @@ -43,8 +25,19 @@ | Neg of atom | Disj of literal list +(** Positive and negative literals separated, disjunctions expanded-out. *) +type gdl_rule = rel_atom * rel_atom list * rel_atom list +(** Collect rules by relations. *) +type def_branch = term array * rel_atom list * rel_atom list +type gdl_defs = (string * def_branch list) list + type clause = rel_atom * literal list +type path = (string * int) list + +type path_set + + type request = | Start of string * term * clause list * int * int (** prepare game: match id, role, game, startclock, playclock *) @@ -53,67 +46,102 @@ | Stop of string * term list (** game ends here: match id, actions on previous step *) -val term_str : term -> string -val terms_str : term list -> string -val sb_str : (string * term) list -> string -val rel_atom_str : rel_atom -> string -val rel_atoms_str : rel_atom list -> string -val def_str : - string * (term list * rel_atom list * rel_atom list) -> string -val tuples_str : term list list -> string -val proto_rel_str : string * string array -> string -val gdl_rule_vars : gdl_rule -> Aux.Strings.t -val gdl_rules_vars : gdl_rule list -> Aux.Strings.t +val atoms_of_body : literal list -> atom list +val rel_of_atom : atom -> rel_atom -val branch_str : string -> def_branch -> string +val term_vars : term -> Aux.Strings.t +val clause_vars : clause -> Aux.Strings.t -val func_graph : string -> term list -> term list list +val defs_of_rules : gdl_rule list -> gdl_defs +val rule_of_clause : clause -> gdl_rule -val rules_of_clause : clause -> gdl_rule list +val nnf_dnf : literal list -> literal list list -val terms_vars : term list -> Aux.Strings.t -val rels_vars : rel_atom list -> Aux.Strings.t +type substitution = (string * term) list +val unify : substitution -> term list -> term list -> substitution +val unify_all : substitution -> term list -> substitution +val subst : substitution -> term -> term +val subst_rels : substitution -> rel_atom list -> rel_atom list +val subst_clause : substitution -> clause -> clause + +(** {3 Transformations of GDL clauses: inlining, negation.} *) + +(** Expand branches of a definition inlining the provided definitions, + only expand positive literals. Iterate expansion to support + nesting of definitions. *) +val expand_positive_lits : gdl_defs -> def_branch list -> def_branch list + +(** Form clause bodies whose disjunction is equivalent to the + negation of disjunction of given clause bodies. *) +val negate_bodies : literal list list -> literal list list + +(** {3 GDL translation helpers.} *) + +val blank : term + val term_to_name : ?nested:bool -> term -> string -val term_vars : term -> Aux.Strings.t -val compose_sb : (string * term) list -> (string * term) list -> - (string * term) list +val state_terms : literal list -> term list -val subst_one : string * term -> term -> term -val subst : (string * term) list -> term -> term -val subst_rel : (string * term) list -> rel_atom -> rel_atom -val subst_rels : (string * term) list -> rel_atom list -> rel_atom list -val subst_br : (string * term) list -> def_branch -> def_branch -val defs_of_rules : gdl_rule list -> gdl_defs +(** {3 GDL whole-game operations.} -val unify : - (string * term) list -> term list -> term list -> (string * term) list + Aggregate playout, player-denoting variable elimination. *) -val unifies : term -> term -> bool +(** Partition relations into stable (not depending, even indirectly, + on "true") and remaining ones. *) +val stable_rels : gdl_defs -> string list * string list -val saturate : rel_atom list -> gdl_rule list -> rel_atom list -val stratify : gdl_defs list -> gdl_defs -> gdl_defs list - +(** Besides the aggregate playout, also return the separation of rules + into static and dynamic. Note that the list of playout states is + one longer than that of playout actions. *) val aggregate_playout : term array -> int -> gdl_rule list -> - gdl_rule list * gdl_rule list * (string * term list) list * - term list * (term list list list * term list list) + gdl_rule list * gdl_rule list * + rel_atom list * term list * + (term array list list * term list list) -val find_cycle : term option list -> term option list +(** {3 Paths and operations involving terms and paths.} *) +(** [simult_subst ps s t] substitutes [s] at all [t] paths that belong + to the set [ps], returns $t[ps \ot s]$. *) +val simult_subst : path_set -> term -> term -> term -(** A path is a position in a tree together with labels on nodes from - the root to that position (but excluding the position). *) -type path = (string * int) list +(** Find the list of results of a function applied to paths from the + given set that are in the term, and to subterms at these paths. *) +val map_paths : (path -> term -> 'a) -> path_set -> term -> 'a list -(** A trie representing a set of paths. *) -type path_set = - | Empty - | Here (** Singleton $\{\epsilon\}$. *) - | Below of (string * path_set array) list - | Here_and_below of (string * path_set array) list -(* Subtries are in sorted order. *) +(** Toss relations hold between subterms of GDL state terms: generate + Toss relation name. *) +val rel_on_paths : string -> path list -> string + +(** Some Toss predicates are generated from a path and an expected + subterm at that path. *) +val pred_on_path_subterm : path -> term -> string + +(** All paths in a term pointing to subterms that satisfy a + predicate. With [~prefix_only:true], paths that contain a path + that has been included, are not included. *) +val term_paths : ?prefix_only:bool -> (term -> bool) -> term -> path_set + +(** Find the subterm at given path, if the term does not have the + path, raise [Not_found]; [at_path p t] is $t \tpos p$. *) +val at_path : term -> path -> term + +(** The set of paths that merges two terms, the cardinality of this + set, and the size of the largest common subtree. *) +val merge_terms : term -> term -> path_set * int * int + +(** Find the list of subterms at paths from the given set, if the term + does not have some of the paths, ignore them if [~fail_at_missing:false], + raise [Not_found] if [~fail_at_missing:true]. *) +val at_paths : ?fail_at_missing:bool -> path_set -> term -> term list + +val empty_path_set : path_set +val paths_union : path_set -> path_set -> path_set + +(** List the paths in a set. *) +val paths_to_list : path_set -> path list Modified: trunk/Toss/GGP/TranslateFormula.ml =================================================================== --- trunk/Toss/GGP/TranslateFormula.ml 2011-07-19 15:20:56 UTC (rev 1516) +++ trunk/Toss/GGP/TranslateFormula.ml 2011-07-26 19:50:54 UTC (rev 1517) @@ -3,12 +3,8 @@ open GDL let rel_atoms body = - let rec aux = function - | Pos (Rel (rel, args)) -> [rel, args] - | Neg (Rel (rel, args)) -> [rel, args] - | Disj ls -> Aux.concat_map aux ls - | _ -> [] in - Aux.concat_map aux body + Aux.map_some (function Rel (rel, args) -> Some (rel, args) + | _ -> None) (atoms_of_body body) @@ -22,33 +18,33 @@ let aux conj = List.fold_right (fun lit acc -> match lit with | (Pos (True _) | Neg (True _)) as lit -> - List.map (fun conj -> Left lit::conj) acc + List.map (fun conj -> Aux.Left lit::conj) acc | Disj ls as lit -> if List.for_all (function Pos _ -> true | _ -> false) ls || List.for_all (function Neg _ -> true | _ -> false) ls then - List.map (fun conj -> Left lit::conj) acc + List.map (fun conj -> Aux.Left lit::conj) acc else Aux.concat_map (function | (Pos (True _) | Neg (True _)) as lit -> - List.map (fun conj -> Left lit::conj) acc - | lit -> List.map (fun conj -> Right lit::conj) acc + List.map (fun conj -> Aux.Left lit::conj) acc + | lit -> List.map (fun conj -> Aux.Right lit::conj) acc ) ls - | lit -> List.map (fun conj -> Right lit::conj) acc + | lit -> List.map (fun conj -> Aux.Right lit::conj) acc ) conj [[]] in let disj = Aux.concat_map aux disj in List.map (fun conj -> - let state_terms, other = Aux.split_choice conj in + let state_terms, other = Aux.partition_choice conj in let pos_terms, neg_terms = Aux.partition_map (function - | Pos _ as lit -> Left lit - | Neg _ as lit -> Right lit + | Pos _ as lit -> Aux.Left lit + | Neg _ as lit -> Aux.Right lit | Disj ls as lit when List.for_all (function Pos _ -> true | _ -> false) ls - -> Left lit + -> Aux.Left lit | Disj ls as lit when List.for_all (function Neg _ -> true | _ -> false) ls - -> Right lit + -> Aux.Right lit | _ -> assert false ) state_terms in other, pos_terms, neg_terms) disj @@ -72,7 +68,7 @@ simult_subst data.f_paths blank t let var_of_term data t = - Formula.fo_var_of_string (blank_out data t) + Formula.fo_var_of_string (term_to_name (blank_out data t)) let blank_outside_subterm data path subterm = let arities = data.term_arities in @@ -84,7 +80,8 @@ path subterm let var_of_subterm data path subt = - Formula.fo_var_of_string (blank_outside_subterm data path t) + Formula.fo_var_of_string + (term_to_name (blank_outside_subterm data path subt)) (* placeholder *) let translate_defrel = @@ -92,18 +89,20 @@ assert false) let transl_rels data rels_phi sterms_all sterms_in = - let s_subterms = List.map - (fun sterm -> sterm, - map_paths (fun path subt -> subt, (sterm, path)) data.f_paths sterm) + (* within-mask subterms to locate paths on which to generate relations *) + let s_subterms = Aux.concat_map + (fun sterm -> + map_paths (fun path subt -> subt, (sterm, path)) data.m_paths sterm) sterms_all in let s_subterms = List.filter (fun (subt, _) -> subt <> blank) s_subterms in let s_subterms = Aux.collect s_subterms in let transl_rel sign rel args = try - let stuples = - List.map (fun arg -> List.assoc arg s_subterms) args in - let stuples = Aux.product stuples in + let (stuples : (GDL.term * GDL.path) list list) = + List.map (fun arg -> List.assoc arg s_subterms) + (Array.to_list args) in + let (stuples : (GDL.term * GDL.path) list list) = Aux.product stuples in let stuples = List.filter (fun stup -> List.exists (fun (sterm,_) -> List.mem sterm sterms_in) stup) @@ -113,14 +112,15 @@ let vartup = List.map (fun (sterm,_) -> var_of_term data sterm) stup in let fact_rel = rel_on_paths rel (List.map snd stup) in - Formula.Rel (fact_rel, vartup)) stuples in + Formula.Rel (fact_rel, Array.of_list vartup)) stuples in if sign then atoms else List.map (fun a -> Formula.Not a) atoms with Not_found -> [] in let transl_defrel sign rel args = if List.mem rel data.defined_rels then - !translate_defrel data sterms_all sterms_in s_subterms sign rel args + [!translate_defrel data sterms_all sterms_in + s_subterms sign rel args] else transl_rel false rel args in let rec aux = function | Pos (Rel (rel, args)) -> transl_defrel true rel args @@ -128,7 +128,7 @@ | Pos (Does _ | Role _) | Neg (Does _ | Role _) -> [] | Disj lits -> - [Formula.Or (List.map (fun l -> [aux l]) lits)] + [Formula.Or (Aux.concat_map (fun l -> aux l) lits)] | _ -> assert false in (* FIXME: what about Distinct? *) Formula.And (Aux.concat_map aux rels_phi) @@ -149,15 +149,15 @@ else None) data.mask_reps in Formula.And (anchor_and_fluent_preds @ mask_preds) in let rec aux = function - | Pos (True sterm) -> transl_sterm sterm + | Pos (True sterm) -> [transl_sterm sterm] | Neg (True sterm) -> assert false | Pos (Does _ | Role _) | Neg (Does _ | Role _) -> [] | Disj lits -> [Formula.Or (Aux.map_some (fun l -> match aux l with - | [] -> None | [phi] -> phi - | conjs -> Formula.And conjs) lits)] + | [] -> None | [phi] -> Some phi + | conjs -> Some (Formula.And conjs)) lits)] | _ -> assert false in (* FIXME: what about Distinct? *) Formula.And (Aux.concat_map aux phi) @@ -172,22 +172,23 @@ let neg_vars = List.map (var_of_term data) neg_terms in let all_terms = pos_terms @ neg_terms in let phi_vars = clause_vars - (("", []), + (("", [| |]), rels_phi @ pos_state_phi @ neg_state_phi) in let eqs = - List.map (fun v -> Pos (Rel ("EQ_", [v; v]))) phi_vars in + List.map (fun v -> Pos (Rel ("EQ_", [|Var v; Var v|]))) + (Aux.Strings.elements phi_vars) in let rels_eqs = rels_phi @ eqs in let negated_neg_state_transl = (* negation-normal-form of "not neg_state_phi" *) Formula.Or ( - List.map (tranls_state data) (nnf_dnf neg_state_phi)) in - Formula.Ex (pos_vars, + List.map (transl_state data) (nnf_dnf neg_state_phi)) in + Formula.Ex ((pos_vars :> Formula.var list), Formula.And [ ext_phi; transl_rels data rels_eqs pos_terms pos_terms; transl_state data pos_state_phi; Formula.Not ( - Formula.Ex (neg_vars, + Formula.Ex ((neg_vars :> Formula.var list), Formula.And [ transl_rels data rels_eqs all_terms pos_terms; negated_neg_state_transl]))]) @@ -206,51 +207,59 @@ (* {3 Build and use defined relations.} *) let build_defrels data clauses = + (* let data = !data_ref in *) let all_branches = Aux.concat_map (fun ((rel,args),body) -> - List.map (fun phi -> rel, (args, phi)) separate_disj [body]) + List.map (fun phi -> rel, (args, phi)) (separate_disj [body])) clauses in let build_defrel rel = (* searching for ArgType = DefSide,S,p *) let branches = Aux.assoc_all rel all_branches in - (* first find the paths, we will find the state terms later *) + (* first find the common paths, we will find the state terms later *) let branch_paths = - List.map (fun (args, body) -> - let sterms = state_terms body - and args = Array.of_list args in + List.map (fun (args, (_, sterms_pos, sterms_neg)) -> + let sterms = state_terms (sterms_pos @ sterms_neg) in Array.map (fun arg -> Aux.concat_map (fun sterm -> - term_paths (fun subt -> subt = arg) data.m_paths sterm + Aux.map_some (fun x->x) + (map_paths (fun p subt -> + if subt = arg then Some p else None) data.m_paths sterm) ) sterms) args ) branches in let p_defside = List.fold_left - (Aux.array_map2 Aux.list_inter) branch_sterms in + (Aux.array_map2 Aux.list_inter) + (List.hd branch_paths) (List.tl branch_paths) in let p_defside = Array.map (function path::_ -> Some path | [] -> None) p_defside in (* now find the mapping $\calS_i$ for the DefSide result *) - let branch_sterms (args, phi) = - let sterms = state_terms phi in + let branch_sterms (args, (_, sterms_pos, sterms_neg)) = + let sterms = state_terms (sterms_pos @ sterms_neg) in Aux.array_map2 (fun arg -> function None -> None | Some path -> Some (List.find (fun sterm -> - List.mem path - (term_paths (fun subt -> subt = arg) - data.m_paths sterm)) sterms)) + List.mem (Some path) + (map_paths (fun p subt -> + if subt = arg then Some p else None) data.m_paths sterm) + ) sterms)) args p_defside in let s_defside = List.map branch_sterms branches in (* now computing the ArgType(R,i) = CallSide,p variant *) let call_branches = Aux.concat_map - (fun (_,(_, phi)) -> + (fun (_,(_, (phi, _, _ as body))) -> let calls = Aux.assoc_all rel (rel_atoms phi) in - List.map (fun args -> args, phi) calls + List.map (fun args -> args, body) calls ) all_branches in let callside_for_arg i = let call_paths = Aux.concat_map - (fun (args, phi) -> - let sterms = state_terms phi and subt = args.(i) in - let paths = - term_paths (fun subt -> subt = arg) data.m_paths sterm in + (fun (args, (_, sterms_pos, sterms_neg)) -> + let sterms = state_terms (sterms_pos @ sterms_neg) + and arg = args.(i) in + let paths = Aux.concat_map (fun sterm -> + Aux.map_some (fun x->x) + (map_paths (fun p subt -> + if subt = arg then Some p else None) data.m_paths sterm) + ) sterms in List.map (fun p -> p, ()) paths ) call_branches in let call_paths = List.map @@ -264,7 +273,7 @@ (fun i -> function Some _ -> None | None -> callside_for_arg i) p_defside in - let arg_paths = Array.map2 + let arg_paths = Aux.array_map2 (fun defside callside -> match defside, callside with | Some p, _ | None, Some p -> p @@ -279,7 +288,11 @@ (fun i v -> let in_I = p_defside.(i) <> None in if in_I - then Formula.Eq (v, s_defside.(i)) + then + let s_i = match s_defside.(i) with + | Some s -> var_of_term data s + | None -> assert false in + Formula.Eq (v, s_i) else Formula.Eq (v, var_of_subterm data arg_paths.(i) args.(i))) defvars in @@ -290,32 +303,34 @@ | Some path -> Some (blank_outside_subterm data path args.(i))) p_defside in + (* packing sterms back as a formula *) let callside_sterms = Array.to_list - (Array.map (fun sterm -> True sterm) callside_sterms) in + (Array.map (fun sterm -> Pos (True sterm)) callside_sterms) in transl_disjunct data rels_phi (callside_sterms @ pos_state) neg_state arg_eqs in let def_disjuncts = List.map2 defbody branches s_defside in - let defrel_arg_type = Array.map2 + let defrel_arg_type = Aux.array_map2 (fun defside path -> defside <> None, path) p_defside arg_paths in data.defrel_arg_type := - (rel, defrel_arg_type) :: !data.defrel_arg_type; + (rel, defrel_arg_type) :: !(data.defrel_arg_type); rel, (defvars, Formula.Or def_disjuncts) in List.map build_defrel data.defined_rels + let transl_defrel data sterms_all sterms_in s_subterms sign rel args = - let arg_type = List.assoc rel !data.defrel_arg_type in + let arg_type = List.assoc rel !(data.defrel_arg_type) in (* the $s \tpos_{p_{R,i}} = t_i$ state terms *) let arg_sterms = Array.mapi (fun i (defside, path) -> if defside then None else try Some ( - List.find (fun s -> at_path path s = args.(i)) sterms_all) + List.find (fun s -> at_path s path = args.(i)) sterms_all) with Not_found -> None) arg_type in let var_args = Array.mapi (fun i (_, path) -> match arg_sterms.(i) with - | None -> var_of_subterm data path arg (* in J *) + | None -> var_of_subterm data path args.(i) (* in J *) | Some sterm -> var_of_term data sterm) arg_type in let defrel_phi = Formula.Rel (rel, var_args) in @@ -329,13 +344,14 @@ let in_J_eq_transl i (_,path) = if arg_sterms.(i) = None then - let eq_phi = [Pos (Rel ("EQ_", [args.(i); args.(i)]))] in + let eq_phi = [Pos (Rel ("EQ_", [|args.(i); args.(i)|]))] in let v = blank_outside_subterm data path args.(i) in Some (transl_rels data eq_phi (v::sterms_all) [v]) else None in let eqs_phi = Array.to_list (Aux.array_mapi_some in_J_eq_transl arg_type) in - Formula.Ex (ex_vars, Formula.And (defrel_phi::eqs_phi)) + Formula.Ex ((ex_vars :> Formula.var list), + Formula.And (defrel_phi::eqs_phi)) let _ = translate_defrel := transl_defrel Modified: trunk/Toss/GGP/TranslateFormula.mli =================================================================== --- trunk/Toss/GGP/TranslateFormula.mli 2011-07-19 15:20:56 UTC (rev 1516) +++ trunk/Toss/GGP/TranslateFormula.mli 2011-07-26 19:50:54 UTC (rev 1517) @@ -1,17 +1,17 @@ +(* Whether $i$th argument is a $\mathrm{DefSide}$ or a + $\mathrm{CallSide}$, and the $p_{R,i}$ path for a relation $R$. *) +type defrel_arg_type = (bool * GDL.path) array type transl_data = { - f_paths : path_set; (* fluent paths *) - m_paths : path_set; (* within-mask paths *) - all_paths : path_set; (* sum of f_paths and m_paths *) - mask_reps : term list; (* mask terms *) + f_paths : GDL.path_set; (** fluent paths *) + m_paths : GDL.path_set; (** within-mask paths *) + all_paths : GDL.path_set; (** sum of f_paths and m_paths *) + mask_reps : GDL.term list; (** mask terms *) defined_rels : string list; defrel_arg_type : (string * defrel_arg_type) list ref; - (* late binding to store $ArgType# data *) + (** late binding to store $ArgType$ data *) term_arities : (string * int) list; } val translate : transl_data -> GDL.literal list list -> Formula.formula - -val build_defrels : - transl_data -> clause list -> (string * (string list * formula)) list Modified: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml 2011-07-19 15:20:56 UTC (rev 1516) +++ trunk/Toss/GGP/TranslateGame.ml 2011-07-26 19:50:54 UTC (rev 1517) @@ -31,13 +31,14 @@ precond : Formula.formula; (* the LHS match condition (the LHS structure and the precondition) *) rhs_add : (string * string array) list; + struc_elems : string list; (* the elements of LHS/RHS structures, corresponding to the "next" terms *) - struc_elems : string list; - fixvar_elemvars : (string * (term * path)) list; - (* "state" terms indexed by variables that they contain, together - with the path to the variable *) - elemvars : term Aux.StrMap.t; + fixvar_terms : (string * (term * path) list) list; + (* "state" terms indexed by GDL variables that they contain, together + with the path to the variable; in [(term * path) list], terms + can repeat *) + rulevar_terms : term Aux.StrMap.t; (* "state" terms indexed by Toss variable names they generate *) } @@ -57,6 +58,10 @@ playing_as : int; (* "active" player *) is_concurrent : bool; + transl_data : TranslateFormula.transl_data; + (* mostly the same data as above, but packed for formula translation *) + element_terms : term Aux.IntMap.t; + (* term representatives of structure elements *) } (* [most_similar c ts] finds a term from [ts] most similar to [c], and @@ -93,7 +98,7 @@ (as in definition of $\calP_f$). *) let fluent_paths_and_frames clauses = let defs = - defs_of_rules (Aux.concat_map rules_of_clause clauses) in + defs_of_rules (List.map rule_of_clause clauses) in let stable, nonstable = stable_rels defs in let inline_defs = List.filter (fun (rel,_) -> List.mem rel nonstable) defs in @@ -106,19 +111,25 @@ List.filter (fun ((rel,_),_) -> rel="next") clauses in let next_e = List.map (fun c -> - c, expand_positive_lits inline_defs [c]) next_clauses in + (* it should actually be a single element association *) + let brs_c = + List.assoc "next" (defs_of_rules [rule_of_clause c]) in + c, expand_positive_lits inline_defs brs_c) next_clauses in let find_br_fluents s_C (_,body,neg_body) = - let p_ts = Aux.assoc_all "true" body in - let n_ts = Aux.assoc_all "true" neg_body in - let t_C, ps = most_similar t_C (p_ts @ n_ts) in + let true_args body = List.map + (function [|t|] -> t | _ -> assert false) + (Aux.assoc_all "true" body) in + let p_ts = true_args body in + let n_ts = true_args neg_body in + let t_C, ps = most_similar s_C (p_ts @ n_ts) in (* "negative true" check *) t_C, ps, List.mem t_C p_ts in let is_frame s_C (t_C, _, neg_true) = not neg_true && s_C = t_C in let find_fluents (c, c_e) = - let s_C = snd (fst c) in + let s_C = (snd (fst c)).(0) in let res = List.map (find_br_fluents s_C) c_e in - if List.for_all is_frame res + if List.for_all (is_frame s_C) res then Aux.Left c else let f_paths = @@ -127,17 +138,17 @@ then term_paths (function Const _ -> true | _ -> false) t_C else ps) res in - Aux.Right (c, List.fold_left paths_union GDL.Empty f_paths) in + Aux.Right (c, List.fold_left paths_union empty_path_set f_paths) in let res = Aux.map_try find_fluents next_e in let frames, fluents = Aux.partition_choice res in let move_clauses, f_paths = List.split fluents in frames, move_clauses, - List.fold_left paths_union GDL.Empty f_paths + List.fold_left paths_union empty_path_set f_paths let rec contains_blank = function | Const "_BLANK_" -> true - | Func args -> Aux.array_existsi (fun _ -> contains_blank) args + | Func (f,args) -> Aux.array_existsi (fun _ -> contains_blank) args | _ -> false @@ -146,12 +157,18 @@ let create_init_struc clauses = let players = Aux.map_some (function - | ("role", [player]), _ -> Some player + | ("role", [|player|]), _ -> Some player | _ -> None ) clauses in - let stable_rels, nonstable_rels, + let players = Array.of_list players in + let rules = List.map rule_of_clause clauses in + let stable_rel_defs, nonstable_rel_defs, stable_base, init_state, (agg_actions, agg_states) = aggregate_playout players !agg_playout_horizon rules in + let stable_rels = Aux.unique_sorted + (List.map (fun ((rel,_),_,_)->rel) stable_rel_defs) in + let nonstable_rels = Aux.unique_sorted + (List.map (fun ((rel,_),_,_)->rel) nonstable_rel_defs) in let frame_clauses, move_clauses, f_paths = fluent_paths_and_frames clauses in let next_clauses = @@ -161,7 +178,7 @@ let arities = ("EQ_", 2):: Aux.unique_sorted - (List.map (fun ((rel, args),_) -> rel, List.length args) + (List.map (fun ((rel, args),_) -> rel, Array.length args) clauses) in let element_terms = List.fold_left (fun acc st -> Aux.unique_sorted (st @ acc)) [] @@ -170,9 +187,9 @@ Aux.unique_sorted (List.map (fun t -> simult_subst f_paths blank t) element_terms) in let m_paths = List.map - (term_paths ~prefix_only:true (neg contains_blank)) element_reps in + (term_paths ~prefix_only:true (Aux.neg contains_blank)) element_reps in let m_paths = - List.fold_left paths_union GDL.Empty m_paths in + List.fold_left paths_union empty_path_set m_paths in let mask_reps = Aux.unique_sorted (List.map (fun t -> simult_subst m_paths blank t) element_reps) in @@ -185,36 +202,35 @@ let struc_rels = "EQ_"::struc_rels in let defined_rels = defined_rels @ nonstable_rels in let elem_term_map = Aux.strmap_of_assoc - (List.map (fun e -> name_of_term e, e) elem_reps) in + (List.map (fun e -> term_to_name e, e) element_reps) in let struc = List.fold_left (fun struc rel -> let arity = List.assoc rel arities in - let elem_tups = Aux.all_ntuples elem_reps arity in + let elem_tups = Aux.all_ntuples element_reps arity in let path_tups = Aux.all_ntuples m_pathl arity in - List.fold_left (fun ptup -> + List.fold_left (fun struc ptup -> let fact_rel = rel_on_paths rel ptup in - Aux.fold_left_try (fun etup -> - let tup = List.map2 at_path etup ptup in - if rel = "EQ_" && arity = 2 && - List.hd tup = List.hd (List.tl tup) + Aux.fold_left_try (fun struc etup -> + let tup = Array.of_list (List.map2 at_path etup ptup) in + if rel = "EQ_" && arity = 2 && tup.(0) = tup.(1) || List.mem (rel, tup) stable_base then Structure.add_rel_named_elems struc fact_rel - (Aux.array_map_of_list name_of_term tup) + (Array.map term_to_name tup) else struc ) struc elem_tups ) struc path_tups - ) (Structure.empty ()) struc_rels in + ) (Structure.empty_structure ()) struc_rels in (* adding anchor and fluent predicates *) let add_pred rels struc paths elements = - List.fold_left (fun path -> - Aux.fold_left_try (fun elem -> + List.fold_left (fun struc path -> + Aux.fold_left_try (fun struc elem -> let pred = pred_on_path_subterm path (at_path elem path) in rels := pred :: !rels; let tup = [|elem|] in Structure.add_rel_named_elems struc pred - (Aux.array_map_of_list name_of_term tup) + (Array.map term_to_name tup) ) struc elements ) struc paths in let stable_rels = ref [] in @@ -231,10 +247,10 @@ then ( stable_rels := pred :: !stable_rels; Structure.add_rel_named_elems struc pred - [|name_of_term elem|]) + [|term_to_name elem|]) else struc ) struc element_reps - ) struc maks_reps in + ) struc mask_reps in next_clauses, f_paths, m_paths, mask_reps, defined_rels, !stable_rels, !fluents, stable_base, init_state, struc, agg_actions, elem_term_map @@ -250,12 +266,13 @@ let fresh_x_f () = let x_f = Aux.not_conflicting_name !used_vars "x_f" in used_vars := Aux.Strings.add x_f !used_vars; - x_f in - let does_facts (_,body as cl) = + Var x_f in + let does_facts (_,body) = List.fold_right (fun p (sb, dis) -> let djs = + (* FIXME: check if "negative true" is properly handled *) Aux.map_some (function - | Does (dp, d) when dp = p -> Some d + | (Pos (Does (dp, d)) | Neg (Does (dp, d))) when dp = p -> Some d | _ -> None) body in let sb = unify_all sb djs in let d = @@ -269,8 +286,9 @@ let next_cls = if mode = `Environment then - List.map_some (fun (_,body as cl) -> - if List.mem (function Does _ -> true | _ -> false) body + Aux.map_some (fun (_,body as cl) -> + if List.exists + (function Pos (Does _) | Neg (Does _) -> true | _ -> false) body then None else Some (cl, []) ) next_cls @@ -281,7 +299,7 @@ (* selecting $\ol{\calC},\ol{\calN}$ clauses with $\sigma_{\ol{\calC},\ol{\calN}}$ applied *) let tup_unifies ts1 ts2 = - try unify [] ts1 ts2; true + try ignore (unify [] ts1 ts2); true with Not_found -> false in let move_clauses cs = (* bag of next clauses for each legal tuple *) @@ -324,7 +342,7 @@ let add_erasure_clauses (legal_tup, next_cls) = - let fixed_vars = terms_vars legal_tup in + (* let fixed_vars = terms_vars legal_tup in *) let frame_cls = Aux.map_some (fun (s, frame, body) -> if frame then Some (s, body) else None) next_cls in @@ -359,7 +377,7 @@ let frames = List.map maximality frames in let frames = List.map (fun (sb, s, bodies) -> - s, List.map (subst_rels sb) bodies) in + s, List.map (subst_rels sb) bodies) frames in let erasure_cls = Aux.concat_map (fun (s, bodies) -> let nbodies = negate_bodies bodies in @@ -447,8 +465,9 @@ The "concurrent games" case is handled specifically. Instead of rules for tuples of "legal" terms, rules for a single legal term - are built. The rules are partitioned among players. The first - player is the environment, [env_player]. *) + are built. The rules are partitioned among players. The last + player is the environment, [env_player] (this way, the numbering of + players can be the same as in turn-based case). *) let create_rule_cands is_turn_based used_vars next_cls clauses = let players = (* Array.of_list *) Aux.map_some (function @@ -485,11 +504,12 @@ let legal_tuples = List.map (fun cl -> [cl]) legal_cls in let move_tups = process_rule_cands `Concurrent [player] legal_tuples in - player, Aux.concat_map nonint_rule_cases (move_tups @ env_tups) + player, Aux.concat_map nonint_rule_cases (move_tups @ env_tups) in if is_concurrent then let env_tups = env_player, process_rule_cands `Environment [] [[]] in - Right (env_tups @ List.map2 concurrent_rule_cands players legal_by_player) + Right + (List.map2 concurrent_rule_cands players legal_by_player @ env_tups) else let legal_tuples = Aux.product legal_by_player in let move_tups = process_rule_cands `General players legal_tuples in @@ -565,8 +585,6 @@ (List.map (function Some p -> p | None -> players.(0)) loc_players) in let loc_n = Array.length loc_players in - let find_player_locs player = - Aux.array_argfind_all (fun p->p=player) loc_players in (* noop actions of a player in a location *) let loc_noops = let i = ref 0 in @@ -629,7 +647,7 @@ struc_elem_terms in let elemvars = Aux.strmap_of_assoc (List.combine struc_elems struc_elem_terms) in - let fixvar_elemvars = List.map + let fixvar_terms = List.map (fun sterm -> map_paths (fun path -> function Var v -> v, (sterm, path) | _ -> assert false) @@ -640,7 +658,7 @@ precond = precond; rhs_add = rhs_add; struc_elems = struc_elems; - fixvar_elemvars = fixvar_elemvars; + fixvar_terms = fixvar_terms; elemvars = elemvars; } in ((rname, tossrule_data), label), (rname, rule) @@ -651,7 +669,6 @@ let rules = ref [] in let tossr_data = ref [] in let loc_n = Array.length loc_players in - let player_rules = Aux.collect player_rules in let graph = Array.mapi (fun loc player -> let player_num = List.assoc (term_to_name player) player_nums in @@ -688,7 +705,7 @@ let loc_graph_general_int = failwith "GDL: General Interaction Games not implemented yet" -(* Remember that "environment" is the 0th player -- also in payoffs +(* Remember that "environment" is the last player -- also in payoffs list. [rule_cands] is a player-indexed array. [players] are all player terms, excluding "environment". *) let loc_graph_concurrent players @@ -727,7 +744,7 @@ (fun pl_num (pl, p_rules) -> let p_rules = List.map (fun rcand -> - if pl_num = 0 then (* environment *) + if pl_num = num_players then (* environment *) build_rule struc fluents all_players_precond [] rcand else build_rule struc fluents [] (player_marker pl) rcand) @@ -798,7 +815,7 @@ cands, struc | None, Left cands -> loc_graph_general_int - | None, Right cands + | None, Right cands -> let build_rule = build_toss_rule transl_data rule_names in loc_graph_concurrent players player_payoffs struc build_rule @@ -832,70 +849,74 @@ (* ************************************************************ *) (** {3 Translating Moves.} *) -(* The common part between turn-based and concurrent case -- - translate a non-noop action. *) -let translate_incoming_single_action gdl state action rname = +(* The common part between turn-based and concurrent case -- translate + a non-noop action. [move] is the instance of a "legal" term, + performed by [player] (a number). Returns an option, since it can + be called for multiple candidate rules. *) +let translate_incoming_single_action data rdata state player move rname = + let fixed_inst, _ = + unify [] [move] [rdata.legal_tuple.(player)] in + let anchors = Aux.concat_map (fun (v,t) -> + let state_terms = List.assoc v rdata.fixvar_terms in + Aux.concat_map + (fun (sterm, path) -> + let pred = pred_on_path_subterm path t in + Formula.Rel (pred, [|TranslateFormula.var_of_term data sterm|])) + state_terms + ) fixed_inst in + let precond = Formula.And (anchors @ [rdata.precond]) in + (* {{{ log entry *) + if !debug_level > 2 then ( + Printf.printf + "GDL.translate_incoming_move: rule=%s; trying precond=\n%s\n...%!" + rname (Formula.sprint precond) + ); + + (* }}} *) + let signat = Structure.rel_signature struc in + let rule = + DiscreteRule.translate_from_precond ~precond ~add:rdata.rhs_add + ~emb_rels:gdl.fluents ~signat ~struc_elems:rdata.struc_elems in + let lhs_struc = rule.DiscreteRule.lhs_struc in + let rule = DiscreteRule.compile_rule signat [] rule in + let asgns = + DiscreteRule.find_matchings struc rule in + (* {{{ log entry *) + if !debug_level > 2 then ( + Printf.printf "found %s\n%!" (AssignmentSet.str asgns) + ); + (* }}} *) + (* faster *) + (* let emb = + DiscreteRule.choose_match (snd state).Arena.struc rule asgns in *) + (* but we should check whether there's no ambiguity... *) + match + DiscreteRule.enumerate_matchings struc rule asgns + with + | [] -> None + | [emb] -> Some (rname, emb, lhs_struc) + | _ -> failwith + ("GDL.translate_incoming_move: match ambiguity for rule "^rname) + + let translate_incoming_move_turnbased gdl state actions noops = let loc = (snd state).Arena.cur_loc in let actions = Array.of_list actions in let location = (fst state).Arena.graph.(loc) in - let player_action = actions.(Aux.array_argfind (fun l -> l.Arena.moves <> []) - location) in + let loc_player = + Aux.array_argfind (fun l -> l.Arena.moves <> []) location in + let move = actions.(loc_player) in let struc = (snd state).Arena.struc in let tossrules = Aux.strmap_filter (fun _ rdata -> - try ignore (match_meta [] [] [player_action] [rdata.legal_tuple.(loc_player)]); true + try ignore (match_meta [] [] [move] + [rdata.legal_tuple.(loc_player)]); true with Not_found -> false ) gdl.tossrule_data in let candidates = Aux.map_so... [truncated message content] |
From: <luk...@us...> - 2011-07-19 15:21:02
|
Revision: 1516 http://toss.svn.sourceforge.net/toss/?rev=1516&view=rev Author: lukstafi Date: 2011-07-19 15:20:56 +0000 (Tue, 19 Jul 2011) Log Message: ----------- Reference specification: expanding the scope of translation (wave clauses). Modified Paths: -------------- trunk/Toss/www/reference/reference.tex Modified: trunk/Toss/www/reference/reference.tex =================================================================== --- trunk/Toss/www/reference/reference.tex 2011-07-16 21:54:34 UTC (rev 1515) +++ trunk/Toss/www/reference/reference.tex 2011-07-19 15:20:56 UTC (rev 1516) @@ -1326,8 +1326,8 @@ state. Since an approximation is sufficient, we check only the positive part of the legality condition of each move. -%In the future, instead of an aggregate playout we -%might use a form of type inference to approximate $\calS$. +In the future, instead of an aggregate playout we +might use a form of type inference to approximate $\calS$. To construct the elements of the structure from state terms, and to make that structure a good representation of the game in Toss, @@ -1359,15 +1359,29 @@ Definition~\ref{def-merge}, and of equally similar has smallest $d\calP(s,t)$ (if there are several, we pick one arbitrarily). + +\paragraph{Wave Clauses} + +Let \emph{wave clauses} $\mathrm{Next}_{W}$ be defined as follows: +$\calC \in \mathrm{Next}_{W}$ if there is $\calC' \in +\mathrm{Next}_{e}$ derived from $\calC$ such that the set of subterms +$s_{\calC'} \tpos d\calP(s_\calC, t_\calC)$ contains a variable. Let +the remaining expanded clauses be $\mathrm{Next}_{f} = \{\calC \in +\mathrm{Next}_{e} | FV(s_{\calC} \tpos d\calP(s_\calC, t_\calC)) = +\emptyset \}$. Wave clauses propagate information across terms rather +than describing a change of a term. + +\paragraph{Fluent Paths and Structure Elements} + We often use the word \emph{fluent} for changing objects, and so we define the set of \emph{fluent paths}, $\calP_f$, in the following way. We say that a term $t$ is a \emph{negative true} in a clause $\calC$ if it is the argument of a negative occurrence of \texttt{true} in $\calC$. -We write $\calL(t)$ for the set of path to all constant leaves in $t$. +We write $\calL(t)$ for the set of paths to all constant leaves in $t$. The set \[ \calP_f \ = \ - \bigcup_{\calC \in \mathrm{Next}_{e}} d\calP(s_\calC, t_\calC) \ \cup \ - \bigcup_{\calC \in \mathrm{Next}_{e},\ + \bigcup_{\calC \in \mathrm{Next}_{f}} d\calP(s_\calC, t_\calC) \ \cup \ + \bigcup_{\calC \in \mathrm{Next}_{f},\ t_\calC \text{ negative true in } \calC} \calL(t_\calC). \] Note that $\calP_f$ contains all merge sets for the selected terms in @@ -1618,6 +1632,12 @@ be the players in $G$, \ie let there be \texttt{(role $p_1$)} up to \texttt{(role $p_n$)} facts in $G$, in this order. +Prior to further processing, we modify the wave clauses of the +game. Let $\calN \in \mathrm{Next}_{W}$, we add to the body of $\calN$ +a \texttt{true} atom $(\mathtt{true} \ BL(s_\calN)$ (where +$\mathtt{BL}(t)=t\big[\calP_f \ot \mathtt{BLANK}\big]$). The added +state term will be the corresponding LHS element of the RHS element +introduced by the clause. \subsubsection{Move Clauses} @@ -1744,7 +1764,11 @@ We determine which clauses are frame clauses prior to partitioning into the rule clauses and computing the substitution $\sigma_{\ol{\calC},\ol{\calN}}$ -- at the point where fluent paths -are computed. +are computed. It is unclear which wave clauses should be considered +frame clauses -- we optimistically assume that all wave clauses not +depending on player actions (\ie not containing \texttt{does}) are +frame clauses (and in the current implementation we ignore frame-wave +clauses as they do not provide useful erasure clauses). From the frame clauses in $\sigma_{\ol{\calC}, \ol{\calN}}(\calN_1), \dots, \sigma_{\ol{\calC}, \ol{\calN}}(\calN_m)$, we select subsets $J$ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-16 21:54:40
|
Revision: 1515 http://toss.svn.sourceforge.net/toss/?rev=1515&view=rev Author: lukstafi Date: 2011-07-16 21:54:34 +0000 (Sat, 16 Jul 2011) Log Message: ----------- GDL translation work in progress (minor edits). Does not compile yet. Modified Paths: -------------- trunk/Toss/GGP/TranslateGame.ml Modified: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml 2011-07-15 18:21:05 UTC (rev 1514) +++ trunk/Toss/GGP/TranslateGame.ml 2011-07-16 21:54:34 UTC (rev 1515) @@ -56,6 +56,7 @@ player, the player's noop move (if any) for the location *) playing_as : int; (* "active" player *) + is_concurrent : bool; } (* [most_similar c ts] finds a term from [ts] most similar to [c], and @@ -831,7 +832,11 @@ (* ************************************************************ *) (** {3 Translating Moves.} *) -let translate_incoming_move_turnbased gdl state actions = +(* The common part between turn-based and concurrent case -- + translate a non-noop action. *) +let translate_incoming_single_action gdl state action rname = + +let translate_incoming_move_turnbased gdl state actions noops = let loc = (snd state).Arena.cur_loc in let actions = Array.of_list actions in let location = (fst state).Arena.graph.(loc) in @@ -924,17 +929,31 @@ String.concat ", " (List.map Aux.fst3 candidates)) +(* We translate as a suite of moves, one for each player; after these + rules have been applied, the server should apply the environment rule. *) let translate_incoming_move_concurrent gdl state actions = - failwith "TODO" + + let translate_incoming_move_general_int gdl state actions = failwith "translate_incoming_move: general interaction games not supported yet" + let translate_incoming_move gdl state actions = - failwith "TODO" + if actions = [] (* start of game -- do nothing *) + then "", [] + else + match gdl.turnbased_noops with + | Some noops -> + translate_incoming_move_turnbased gdl state actions noops + | None -> + if gdl.is_concurrent then + translate_incoming_move_concurrent gdl state actions + else + translate_incoming_move_general_int gdl state actions - + (* (10a) associate the rule with its corresponding data: the "lead legal" term, the fixed variables corresponding to rule elements, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-15 18:21:16
|
Revision: 1514 http://toss.svn.sourceforge.net/toss/?rev=1514&view=rev Author: lukstafi Date: 2011-07-15 18:21:05 +0000 (Fri, 15 Jul 2011) Log Message: ----------- GDL translation work in progress: preparing move translation data. Does not compile yet. Modified Paths: -------------- trunk/Toss/GGP/TranslateGame.ml Modified: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml 2011-07-14 22:56:38 UTC (rev 1513) +++ trunk/Toss/GGP/TranslateGame.ml 2011-07-15 18:21:05 UTC (rev 1514) @@ -25,7 +25,7 @@ let env_player = Const "ENVIRONMENT" type tossrule_data = { - lead_legal : term; + legal_tuple : term; (* the "legal"/"does" term of the player that performs the move, we call its parameters "fixed variables" as they are provided externally *) precond : Formula.formula; @@ -34,10 +34,9 @@ (* the elements of LHS/RHS structures, corresponding to the "next" terms *) struc_elems : string list; - fixvar_elemvars : - (string * (term * (string * string list) list) list) list; + fixvar_elemvars : (string * (term * path)) list; (* "state" terms indexed by variables that they contain, together - with the mask-path of the variable *) + with the path to the variable *) elemvars : term Aux.StrMap.t; (* "state" terms indexed by Toss variable names they generate *) } @@ -52,9 +51,11 @@ masks : term list; tossrule_data : tossrule_data Aux.StrMap.t; (* rule name to rule translation data *) - turnbased_noops : term array array option; + turnbased_noops : term option array array option; (* in case of a turn-based translation, for each location and each player, the player's noop move (if any) for the location *) + playing_as : int; + (* "active" player *) } (* [most_similar c ts] finds a term from [ts] most similar to [c], and @@ -204,18 +205,21 @@ ) struc path_tups ) (Structure.empty ()) struc_rels in (* adding anchor and fluent predicates *) - let add_pred struc paths elements = + let add_pred rels struc paths elements = List.fold_left (fun path -> Aux.fold_left_try (fun elem -> let pred = pred_on_path_subterm path (at_path elem path) in + rels := pred :: !rels; let tup = [|elem|] in Structure.add_rel_named_elems struc pred (Aux.array_map_of_list name_of_term tup) ) struc elements ) struc paths in - let struc = add_pred struc m_pathl element_reps in - let struc = add_pred struc f_pathl init_state in + let stable_rels = ref [] in + let fluents = ref [] in + let struc = add_pred stable_rels struc m_pathl element_reps in + let struc = add_pred fluents struc f_pathl init_state in (* adding mask predicates *) let all_paths = paths_union m_paths f_paths in let struc = @@ -223,13 +227,15 @@ let pred = term_to_name m in List.fold_left (fun struc elem -> if simult_subst all_paths blank elem = m - then + then ( + stable_rels := pred :: !stable_rels; Structure.add_rel_named_elems struc pred - [|name_of_term elem|] + [|name_of_term elem|]) else struc ) struc element_reps ) struc maks_reps in next_clauses, f_paths, m_paths, mask_reps, defined_rels, + !stable_rels, !fluents, stable_base, init_state, struc, agg_actions, elem_term_map @@ -585,41 +591,64 @@ let build_toss_rule transl_data rule_names struc fluents - synch_precond synch_postcond (legal_tup, case_rhs, case_cond) = + synch_precond synch_postcond (legal_tuple, case_rhs, case_cond) = let rname = Aux.not_conflicting_name rule_names - (String.concat "_" (List.map term_to_name legal_tup)) in + (String.concat "_" (List.map term_to_name legal_tuple)) in rule_names := Aux.Strings.add rname !rule_names; let label = {Arena.rule = rname; time_in = 0.1, 0.1; parameters_in = []} in let precond = synch_precond @ TranslateFormula.translate transl_data case_cond in - let rhs_pos = Aux.concat_map + let rhs_add = Aux.concat_map (function _, [sterm] -> let s_subterms = map_paths (fun path subt -> subt, path) transl_data.f_paths sterm in let s_subterms = List.filter (fun (subt, _) -> subt <> blank) s_subterms in - let vartup = [|var_of_term data sterm|] in + let vartup = [|TranslateFormula.var_of_term data sterm|] in List.map (fun (subt, path) -> pred_on_path_subterm path subt, vartup) s_subterms | _ -> assert false) case_rhs in - let rhs_pos = synch_postcond @ rhs_pos in + let rhs_add = synch_postcond @ rhs_add in let signat = Structure.rel_signature struc in let discrete = DiscreteRule.translate_from_precond ~precond - ~add:rhs_pos ~emb_rels:fluents ~signat ~struc_elems in + ~add:rhs_add ~emb_rels:fluents ~signat ~struc_elems in let rule = ContinuousRule.make_rule signature [] discrete [] [] ~pre:discrete.DiscreteRule.pre () in - label, (rname, rule) + let struc_elem_terms = List.map + (function _, [sterm] -> sterm | _ -> assert false) + case_rhs in + let struc_elems = List.map + (fun sterm -> Formula.var_str (TranslateFormula.var_of_term data sterm)) + struc_elem_terms in + let elemvars = Aux.strmap_of_assoc + (List.combine struc_elems struc_elem_terms) in + let fixvar_elemvars = List.map + (fun sterm -> map_paths + (fun path -> function Var v -> v, (sterm, path) + | _ -> assert false) + (term_paths (function Var _ -> true | _ -> false) sterm)) + struc_elem_terms in + let tossrule_data = { + legal_tuple = legal_tuple; + precond = precond; + rhs_add = rhs_add; + struc_elems = struc_elems; + fixvar_elemvars = fixvar_elemvars; + elemvars = elemvars; + } in + ((rname, tossrule_data), label), (rname, rule) let loc_graph_turn_based player_nums player_payoffs loc_players loc_noops build_rule rule_cands = let rules = ref [] in + let tossr_data = ref [] in let loc_n = Array.length loc_players in let player_rules = Aux.collect player_rules in let graph = Array.mapi @@ -637,8 +666,10 @@ then Some (build_rule rcand) else None ) rule_cands in - let labels, loc_rules = List.split loc_rules in + let loc_rdata, loc_rules = List.split loc_rules in + let loc_rdata, labels = List.split loc_rdata in rules := !rules @ loc_rules; + tossr_data := !tossr_data @ loc_rdata; let pl_moves = List.map (fun l -> l, (loc + 1) mod loc_n) labels in Array.mapi @@ -649,7 +680,7 @@ moves = if pl_num = player_num then pl_moves else []}) player_payoffs) loc_players in - graph, !rules + graph, !rules, !tossr_data let sControl = "CONTROL__" @@ -660,7 +691,7 @@ list. [rule_cands] is a player-indexed array. [players] are all player terms, excluding "environment". *) let loc_graph_concurrent players - player_payoffs struc build_rule rule_cands = + player_payoffs struc build_rule fluents rule_cands = (* finding or creating the control predicate *) let control_pred, control_e, struc = try @@ -685,10 +716,12 @@ Formula.fo_var_of_string (Structure.elem_name struc control_e) in let player_marker pl = [player_pred pl, [|control_v|]; control_pred, [|control_v|]] in + let fluents = List.map player_pred players @ fluents in let all_players_precond = (List.map (fun (rel,tup) -> Formula.Rel (rel,tup))) (Aux.concat_map player_marker players) in let rules = ref [] in + let tossr_data = ref [] in let player_moves = Array.mapi (fun pl_num (pl, p_rules) -> let p_rules = List.map @@ -700,8 +733,10 @@ p_rules in (* we need to build first before adding [player_cond] because of how formula translation works *) - let labels, p_rules = List.split p_rules in + let p_rdata, p_rules = List.split p_rules in + let p_rdata, labels = List.split p_rdata in rules := !rules @ p_rules; + tossr_data := !tossr_data @ p_rdata; List.map (fun l -> l, (loc + 1) mod loc_n)) rule_cands in let graph = @@ -714,7 +749,7 @@ moves = moves}) player_payoffs player_moves |] in - (graph, !rules), struc + (graph, !rules, !tossr_data), struc @@ -722,6 +757,7 @@ let clauses = expand_players clauses in let used_vars, clauses = rename_clauses clauses in let next_cls, f_paths, m_paths, mask_reps, defined_rels, + stable_rels, fluents, stable_base, init_state, struc, agg_actions, elem_term_map = create_init_struc clauses in let turn_data = @@ -752,7 +788,7 @@ let player_names = Array.to_list (Array.mapi (fun i p -> term_to_name p, i) players) in (* possibly update the structure with a control element and predicate *) - let (graph, rules), struc = + let (graph, rules, tossrule_data), struc = match turn_data, rule_cands with | Some (loc_players, loc_noops), Left cands -> let build_rule = @@ -765,7 +801,7 @@ let build_rule = build_toss_rule transl_data rule_names in loc_graph_concurrent players player_payoffs struc build_rule - rule_cands + fluents rule_cands | _ -> assert false in let game = { @@ -777,6 +813,7 @@ data = []; defined_rels = defined_rels; } in + let tossrule_data = Aux.strmap_of_assoc tossrule_data in let gdl_translation = { (* map between structure elements and their term representations; the reverse direction is by using element names *) @@ -785,7 +822,6 @@ m_paths = m_paths; masks = mask_reps; tossrule_data = tossrule_data; - (* rule name to rule translation data *) } in gdl_translation, (game, {Arena.struc = struc; time = 0.; cur_loc = 0}) @@ -795,23 +831,172 @@ (* ************************************************************ *) (** {3 Translating Moves.} *) +let translate_incoming_move_turnbased gdl state actions = + let loc = (snd state).Arena.cur_loc in + let actions = Array.of_list actions in + let location = (fst state).Arena.graph.(loc) in + let player_action = actions.(Aux.array_argfind (fun l -> l.Arena.moves <> []) + location) in + let struc = (snd state).Arena.struc in + let tossrules = + Aux.strmap_filter (fun _ rdata -> + try ignore (match_meta [] [] [player_action] [rdata.legal_tuple.(loc_player)]); true + with Not_found -> false + ) gdl.tossrule_data in + let candidates = Aux.map_some (fun (rname, rdata) -> + let fixed_inst, _ = + match_meta [] [] [player_action] [rdata.legal_tuple.(loc_player)] in + (* FIXME: rethink how elemvars are used and adjust how they're + created *) + let anchors = Aux.concat_map (fun (v,t) -> + let elemvars = List.assoc v rdata.fixvar_elemvars in + Aux.concat_map (fun (mask, pevs) -> + Aux.concat_map (fun (path, evs) -> + let pred = List.assoc t + (List.assoc path (List.assoc mask gdl.anchor_terms)) in + List.map (fun ev-> + Formula.Rel (pred, [|Formula.fo_var_of_string + (String.lowercase ev)|])) evs) + pevs) elemvars + ) fixed_inst in + let precond = Formula.And (anchors @ [rdata.precond]) in + (* {{{ log entry *) + if !debug_level > 2 then ( + Printf.printf + "GDL.translate_incoming_move: rule=%s; trying precond=\n%s\n...%!" + rname (Formula.sprint precond) + ); + (* }}} *) + let signat = Structure.rel_signature struc in + let rule = + DiscreteRule.translate_from_precond ~precond ~add:rdata.rhs_add + ~emb_rels:gdl.fluents ~signat ~struc_elems:rdata.struc_elems in + let lhs_struc = rule.DiscreteRule.lhs_struc in + let rule = DiscreteRule.compile_rule signat [] rule in + let asgns = + DiscreteRule.find_matchings struc rule in + (* {{{ log entry *) + if !debug_level > 2 then ( + Printf.printf "found %s\n%!" (AssignmentSet.str asgns) + ); + (* }}} *) + (* faster *) + (* let emb = + DiscreteRule.choose_match (snd state).Arena.struc rule asgns in *) + (* but we should check whether there's no ambiguity... *) + match + DiscreteRule.enumerate_matchings struc rule asgns + with + | [] -> None + | [emb] -> Some (rname, emb, lhs_struc) + | _ -> failwith + ("GDL.translate_incoming_move: match ambiguity for rule "^rname) + ) tossrules in + match candidates with + | [] -> + failwith + "GDL.translate_incoming_move: no matching rule found" + | [rname, emb, lhs_struc] -> + (* {{{ log entry *) + if !debug_level > 0 then ( + Printf.printf "GDL.translate_incoming_move: rname=%s; emb=%s\n...%!" + rname + (String.concat ", " (List.map (fun (v,e) -> + Structure.elem_str lhs_struc v ^ ": " ^ + Structure.elem_str struc e) emb)) + ); + (* }}} *) + rname, emb + | _ -> + (* {{{ log entry *) + if !debug_level > 0 then ( + Printf.printf "GDL.translate_incoming_move: ambiguity\n%!"; + List.iter (fun (rname, emb, lhs_struc) -> + Printf.printf "rname=%s; emb=%s\n%!" + rname + (String.concat ", " (List.map (fun (v,e) -> + Structure.elem_str lhs_struc v ^ ": " ^ + Structure.elem_str struc e) emb))) candidates + ); + (* }}} *) + failwith + ("GDL.translate_incoming_move: ambiguity among rules "^ + String.concat ", " (List.map Aux.fst3 candidates)) -let initialize_game player game_descr startcl = - let gdl_transl, state = translate_game player game_descr in - state, None, gdl_transl - - -let translate_last_action gdl_translation state actions = - if actions = [] then (* start of game -- Server will not perform a move *) - "", [] - else translate_incoming_move gdl_translation state actions +let translate_incoming_move_concurrent gdl state actions = + failwith "TODO" -let translate_move gdl_translation new_state rule emb = - let res = translate_outgoing_move gdl_translation new_state rule emb in +let translate_incoming_move_general_int gdl state actions = + failwith + "translate_incoming_move: general interaction games not supported yet" + +let translate_incoming_move gdl state actions = + failwith "TODO" + + +(* + (10a) associate the rule with its corresponding data: the "lead + legal" term, the fixed variables corresponding to rule elements, + ... + + (10b) earlier, return/store the mapping from an element to the + mask and subsitution that define the element; + + (10c) earlier, for each rule store a mapping from fixed variables + to rule variables and the mask variables that in the rule variable + are instantiated by the fixed variables; + + (10d) to determine how to instantiate the fixed variables in the + "lead legal" term, find the (10b) substitutions of assigned + elements and (10c) mask variables for fixed variables; compose the + maps to get fixed variable to GDL ground term mapping, each + "route" should give the same term. + *) +let translate_outgoing_move gdl state rname emb = + (* let loc = (snd state).Arena.cur_loc in *) + (* let location = (fst state).Arena.graph.(loc) in *) + let tossrule = Aux.StrMap.find rname gdl.tossrule_data in + let rule = List.assoc rname (fst state).Arena.rules in (* {{{ log entry *) if !debug_level > 0 then ( - Printf.printf "GDL.translate_move: %s\n%!" res + Printf.printf "GDL.translate_outgoing_move: rname=%s; emb={%s}\n%!" + rname (String.concat ", "(List.map (fun (v, e)-> + let vname = + DiscreteRule.elemvar_of_elem + rule.ContinuousRule.compiled.DiscreteRule.lhs_elem_inv_names v in + let ename = Structure.elem_str (snd state).Arena.struc e in + if ename = "control__blank_" then + Structure.print (snd state).Arena.struc; + vname ^ ": " ^ ename + ) emb)) ); (* }}} *) + (* 10d *) + let emb = List.map (fun (v, e) -> + let vterm = + DiscreteRule.elemvar_of_elem + rule.ContinuousRule.compiled.DiscreteRule.lhs_elem_inv_names v in + Aux.StrMap.find vterm tossrule.elemvars, + Aux.IntMap.find e gdl.t_elements) emb in + (* {{{ log entry *) + if !debug_level > 2 then ( + Printf.printf "outgoing-emb={%s}\n%!" + (String.concat ", "(List.map (fun (vt, et)-> + term_str vt ^ ": " ^ term_str et) emb)) + ); + (* }}} *) + let sb = + try + List.fold_left (fun sb (v_term, e_term) -> + fst (match_meta ~ignore_meta:true sb [] [e_term] [v_term])) [] emb + with Not_found -> failwith + ("GDL.translate_outgoing_move: inconsistent match for rule " + ^rname) in + let res = term_str (subst sb tossrule.legal_tuple.(gdl.playing_as)) in + (* {{{ log entry *) + if !debug_level > 0 then ( + Printf.printf "GDL.translate_outgoing_move: result = %s\n%!" res + ); + (* }}} *) res This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-14 22:56:50
|
Revision: 1513 http://toss.svn.sourceforge.net/toss/?rev=1513&view=rev Author: lukstafi Date: 2011-07-14 22:56:38 +0000 (Thu, 14 Jul 2011) Log Message: ----------- GDL translation work in progress. Does not compile yet. Modified Paths: -------------- trunk/Toss/Formula/Aux.ml trunk/Toss/Formula/Aux.mli trunk/Toss/GGP/TranslateGame.ml Modified: trunk/Toss/Formula/Aux.ml =================================================================== --- trunk/Toss/Formula/Aux.ml 2011-07-14 15:51:48 UTC (rev 1512) +++ trunk/Toss/Formula/Aux.ml 2011-07-14 22:56:38 UTC (rev 1513) @@ -441,6 +441,15 @@ done; true with Not_found -> false + +let array_for_alli f a = + try + for i = 0 to Array.length a - 1 do + if not (f i (Array.unsafe_get a i)) then + raise Not_found + done; + true + with Not_found -> false let array_for_all2 f a b = let len = Array.length a in Modified: trunk/Toss/Formula/Aux.mli =================================================================== --- trunk/Toss/Formula/Aux.mli 2011-07-14 15:51:48 UTC (rev 1512) +++ trunk/Toss/Formula/Aux.mli 2011-07-14 22:56:38 UTC (rev 1513) @@ -216,6 +216,9 @@ (** Find if a predicate holds for all elements. *) val array_for_all : ('a -> bool) -> 'a array -> bool +(** Find if a position-dependent predicate holds for all elements. *) +val array_for_alli : (int -> 'a -> bool) -> 'a array -> bool + (** Find if a predicate holds for all elements of two arrays pointwise. Raises [Invalid_argument "Aux.array_for_all2"] if arrays are of different lengths. *) Modified: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml 2011-07-14 15:51:48 UTC (rev 1512) +++ trunk/Toss/GGP/TranslateGame.ml 2011-07-14 22:56:38 UTC (rev 1513) @@ -22,6 +22,7 @@ (** Use "true" atoms while computing rule cases. *) let split_on_state_atoms = ref false +let env_player = Const "ENVIRONMENT" type tossrule_data = { lead_legal : term; @@ -51,6 +52,9 @@ masks : term list; tossrule_data : tossrule_data Aux.StrMap.t; (* rule name to rule translation data *) + turnbased_noops : term array array option; + (* in case of a turn-based translation, for each location and each + player, the player's noop move (if any) for the location *) } (* [most_similar c ts] finds a term from [ts] most similar to [c], and @@ -230,8 +234,11 @@ (* Find the rule clauses $\ol{\calC},\ol{\calN}$. Do not remove the - "does" atoms from clauses. *) -let move_tuples used_vars next_cls legal_tuples = + "does" atoms from clauses. Also handles as special cases: + "concurrent" case with selecting clauses for only one player, and + "environment" case for selecting clauses not dependent on any + player. *) +let move_tuples used_vars next_cls mode players legal_tuples = (* computing the $d_i(\calN)$ for each $\calN$ *) let fresh_x_f () = let x_f = Aux.not_conflicting_name !used_vars "x_f" in @@ -246,14 +253,24 @@ let sb = unify_all sb djs in let d = match djs with - | [] -> fresh_x_f () + | [] -> + if mode = `Concurrent then raise Not_found + else fresh_x_f () | d::_ -> subst sb d in sb, d::dis ) players ([], []) in let next_cls = - Aux.map_try (fun cl -> - let sb, ds = does_facts cl in - subst_clause sb cl, ds) next_cls in + if mode = `Environment + then + List.map_some (fun (_,body as cl) -> + if List.mem (function Does _ -> true | _ -> false) body + then None + else Some (cl, []) + ) next_cls + else + Aux.map_try (fun cl -> + let sb, ds = does_facts cl in + subst_clause sb cl, ds) next_cls in (* selecting $\ol{\calC},\ol{\calN}$ clauses with $\sigma_{\ol{\calC},\ol{\calN}}$ applied *) let tup_unifies ts1 ts2 = @@ -416,8 +433,15 @@ let general_int_rule_cases (legal_tup, next_cls) = failwith "General Interaction Games not implemented yet" -(* The candidates need to be filtered before finishing the - translation of Toss rules. *) +(* Generate rule candidates (they need to be filtered before finishing + the translation of Toss rules): returns the "legal" terms tuple + (ordered by players), the right-hand-sides, and the conditions + (concatenated bodies of the selected "legal" and "next" clauses). + + The "concurrent games" case is handled specifically. Instead of + rules for tuples of "legal" terms, rules for a single legal term + are built. The rules are partitioned among players. The first + player is the environment, [env_player]. *) let create_rule_cands is_turn_based used_vars next_cls clauses = let players = (* Array.of_list *) Aux.map_some (function @@ -442,22 +466,26 @@ | ("legal",[lp; l]), body when lp = p -> Some (l, body) | _ -> None) legal_cls ) players in - let process_rule_cands legal_tuples = - let move_tups = move_tuples used_vars next_cls legal_tuples in + let process_rule_cands mode players legal_tuples = let move_tups = + move_tuples used_vars next_cls mode players legal_tuples in + let move_tups = List.map (fun (sb, legal_tup, n_cls) -> List.map (subst sb) legal_tup, List.map (subst_clause sb) n_cls) move_tups in List.map add_erasure_clauses move_tups in let concurrent_rule_cands player legal_cls = let legal_tuples = List.map (fun cl -> [cl]) legal_cls in - let move_tups = process_rule_cands legal_tuples in - player, Aux.concat_map nonint_rule_cases move_tups + let move_tups = + process_rule_cands `Concurrent [player] legal_tuples in + player, Aux.concat_map nonint_rule_cases (move_tups @ env_tups) if is_concurrent then - Right (List.map2 concurrent_rule_cands players legal_by_player) + let env_tups = + env_player, process_rule_cands `Environment [] [[]] in + Right (env_tups @ List.map2 concurrent_rule_cands players legal_by_player) else let legal_tuples = Aux.product legal_by_player in - let move_tups = process_rule_cands legal_tuples in + let move_tups = process_rule_cands `General players legal_tuples in if is_turn_based then Left (Aux.concat_map nonint_rule_cases move_tups) else @@ -556,27 +584,140 @@ loc_players, loc_noops +let build_toss_rule transl_data rule_names struc fluents + synch_precond synch_postcond (legal_tup, case_rhs, case_cond) = + let rname = + Aux.not_conflicting_name rule_names + (String.concat "_" (List.map term_to_name legal_tup)) in + rule_names := Aux.Strings.add rname !rule_names; + let label = + {Arena.rule = rname; time_in = 0.1, 0.1; parameters_in = []} in + let precond = + synch_precond @ TranslateFormula.translate transl_data case_cond in + let rhs_pos = Aux.concat_map + (function _, [sterm] -> + let s_subterms = + map_paths (fun path subt -> subt, path) transl_data.f_paths sterm in + let s_subterms = List.filter + (fun (subt, _) -> subt <> blank) s_subterms in + let vartup = [|var_of_term data sterm|] in + List.map (fun (subt, path) -> + pred_on_path_subterm path subt, vartup) + s_subterms + | _ -> assert false) + case_rhs in + let rhs_pos = synch_postcond @ rhs_pos in + let signat = Structure.rel_signature struc in + let discrete = + DiscreteRule.translate_from_precond ~precond + ~add:rhs_pos ~emb_rels:fluents ~signat ~struc_elems in + let rule = + ContinuousRule.make_rule signature [] discrete + [] [] ~pre:discrete.DiscreteRule.pre () in + label, (rname, rule) + + let loc_graph_turn_based player_nums - player_payoffs loc_players loc_noops rule_cands = + player_payoffs loc_players loc_noops build_rule rule_cands = + let rules = ref [] in + let loc_n = Array.length loc_players in + let player_rules = Aux.collect player_rules in let graph = Array.mapi (fun loc player -> let player_num = List.assoc (term_to_name player) player_nums in + (* a rule belongs to a player if other players' legal terms + in the legal tuple are their noop terms for current location *) + let loc_rules = Aux.map_some + (fun (legal_tup, _, _ as rcand) -> + let legal_tup = Array.of_list legal_tup in + if Array.for_alli + (fun pl noop -> pl = player_num || + Some legal_tup.(pl) = noop) + loc_noops.(loc) + then Some (build_rule rcand) + else None + ) rule_cands in + let labels, loc_rules = List.split loc_rules in + rules := !rules @ loc_rules; let pl_moves = + List.map (fun l -> l, (loc + 1) mod loc_n) labels in Array.mapi (fun pl_num payoff -> {Arena.payoff = payoff; view = []; heur = []; moves = if pl_num = player_num then pl_moves else []}) - players) + player_payoffs) loc_players in + graph, !rules + +let sControl = "CONTROL__" let loc_graph_general_int = failwith "GDL: General Interaction Games not implemented yet" -let loc_graph_concurrent = -() +(* Remember that "environment" is the 0th player -- also in payoffs + list. [rule_cands] is a player-indexed array. [players] are all + player terms, excluding "environment". *) +let loc_graph_concurrent players + player_payoffs struc build_rule rule_cands = + (* finding or creating the control predicate *) + let control_pred, control_e, struc = + try + let control_pred, _ = + List.find (fun (rel, ar) -> ar = 1 && + Structure.Tuples.cardinal (Structure.find_rel rel struc) = 1) + (Structure.rel_signature struc) in + let etup = Structure.Tuples.choose_elem + (Structure.find_rel control_pred struc) in + control_pred, etup.(0), struc + with Not_found -> + let struc, control_e = + Structure.add_new_elem struc ~name:sControl () in + let struc = Structure.add_rel struc [|control_e|] in + sControl, control_e, struc in + (* adding synchronization to rules and putting it all together *) + let player_pred pl = term_to_name pl ^ "__SYNC" in + let struc = List.fold_left + (fun struc player -> + Structure.add_rel_name (player_pred player) 1) players in + let control_v = + Formula.fo_var_of_string (Structure.elem_name struc control_e) in + let player_marker pl = + [player_pred pl, [|control_v|]; control_pred, [|control_v|]] in + let all_players_precond = + (List.map (fun (rel,tup) -> Formula.Rel (rel,tup))) + (Aux.concat_map player_marker players) in + let rules = ref [] in + let player_moves = Array.mapi + (fun pl_num (pl, p_rules) -> + let p_rules = List.map + (fun rcand -> + if pl_num = 0 then (* environment *) + build_rule struc fluents all_players_precond [] rcand + else + build_rule struc fluents [] (player_marker pl) rcand) + p_rules in + (* we need to build first before adding [player_cond] because + of how formula translation works *) + let labels, p_rules = List.split p_rules in + rules := !rules @ p_rules; + List.map (fun l -> l, (loc + 1) mod loc_n)) + rule_cands in + let graph = + [| + Aux.array_map2 + (fun payoff moves -> + {Arena.payoff = payoff; + view = []; + heur = []; + moves = moves}) + player_payoffs player_moves + |] in + (graph, !rules), struc + + let translate_game clauses = let clauses = expand_players clauses in let used_vars, clauses = rename_clauses clauses in @@ -610,14 +751,21 @@ ) clauses) in let player_names = Array.to_list (Array.mapi (fun i p -> term_to_name p, i) players) in - let graph (*: player_loc array array*) = + (* possibly update the structure with a control element and predicate *) + let (graph, rules), struc = match turn_data, rule_cands with | Some (loc_players, loc_noops), Left cands -> - loc_graph_turn_based players loc_players loc_noops cands + let build_rule = + build_toss_rule transl_data rule_names struc fluents [] [] in + loc_graph_turn_based players loc_players loc_noops build_rule + cands, struc | None, Left cands -> loc_graph_general_int | None, Right cands - loc_graph_concurrent + let build_rule = + build_toss_rule transl_data rule_names in + loc_graph_concurrent players player_payoffs struc build_rule + rule_cands | _ -> assert false in let game = { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-14 15:52:00
|
Revision: 1512 http://toss.svn.sourceforge.net/toss/?rev=1512&view=rev Author: lukaszkaiser Date: 2011-07-14 15:51:48 +0000 (Thu, 14 Jul 2011) Log Message: ----------- Small changes to sync compile stuff. Modified Paths: -------------- trunk/Toss/GGP/GDL.ml trunk/Toss/GGP/GDL.mli trunk/Toss/GGP/TranslateGame.mli trunk/Toss/Server/ReqHandler.mli trunk/Toss/Solver/Structure.ml Modified: trunk/Toss/GGP/GDL.ml =================================================================== --- trunk/Toss/GGP/GDL.ml 2011-07-13 09:55:22 UTC (rev 1511) +++ trunk/Toss/GGP/GDL.ml 2011-07-14 15:51:48 UTC (rev 1512) @@ -57,14 +57,16 @@ | Const c -> c | Var v -> "?"^v | Func (f, args) -> - "(" ^ f ^ " " ^ String.concat " " (List.map term_str args) ^ ")" + "(" ^ f ^ " " ^ + String.concat " " (List.map term_str (Array.to_list args)) ^ ")" let rec term_to_name ?(nested=false) = function | Const c -> c | Var v -> v | Func (f, args) -> f ^ "_" ^ (if nested then "_S_" else "") ^ - String.concat "_" (List.map (term_to_name ~nested:true) args) ^ + String.concat "_" (List.map (term_to_name ~nested:true) + (Array.to_list args)) ^ (if nested then "_Z_" else "") let rec term_vars = function @@ -74,7 +76,7 @@ and terms_vars args = List.fold_left Aux.Strings.union Aux.Strings.empty - (List.map term_vars args) + (List.map term_vars (Array.to_list args)) let rel_of_atom = function Modified: trunk/Toss/GGP/GDL.mli =================================================================== --- trunk/Toss/GGP/GDL.mli 2011-07-13 09:55:22 UTC (rev 1511) +++ trunk/Toss/GGP/GDL.mli 2011-07-14 15:51:48 UTC (rev 1512) @@ -104,3 +104,16 @@ term list * (term list list list * term list list) val find_cycle : term option list -> term option list + + +(** A path is a position in a tree together with labels on nodes from + the root to that position (but excluding the position). *) +type path = (string * int) list + +(** A trie representing a set of paths. *) +type path_set = + | Empty + | Here (** Singleton $\{\epsilon\}$. *) + | Below of (string * path_set array) list + | Here_and_below of (string * path_set array) list +(* Subtries are in sorted order. *) Modified: trunk/Toss/GGP/TranslateGame.mli =================================================================== --- trunk/Toss/GGP/TranslateGame.mli 2011-07-13 09:55:22 UTC (rev 1511) +++ trunk/Toss/GGP/TranslateGame.mli 2011-07-14 15:51:48 UTC (rev 1512) @@ -1,4 +1,3 @@ - type tossrule_data = { lead_legal : GDL.term; (* the "legal"/"does" term of the player that performs the move, we @@ -10,7 +9,7 @@ terms *) struc_elems : string list; fixvar_elemvars : - (string * (term * (string * string list) list) list) list; + (string * (GDL.term * (string * string list) list) list) list; (* "state" terms indexed by variables that they contain, together with the mask-path of the variable *) elemvars : GDL.term Aux.StrMap.t; @@ -21,7 +20,7 @@ type gdl_translation = { (* map between structure elements and their term representations; the reverse direction is by using element names *) - elem_term_map : term Aux.IntMap.t; + elem_term_map : GDL.term Aux.IntMap.t; f_paths : GDL.path_set; m_paths : GDL.path_set; masks : GDL.term list; @@ -31,4 +30,4 @@ val translate_game : - clause list -> gdl_translation * (Arena.game * Arena.game_state) + GDL.clause list -> gdl_translation * (Arena.game * Arena.game_state) Modified: trunk/Toss/Server/ReqHandler.mli =================================================================== --- trunk/Toss/Server/ReqHandler.mli 2011-07-13 09:55:22 UTC (rev 1511) +++ trunk/Toss/Server/ReqHandler.mli 2011-07-14 15:51:48 UTC (rev 1512) @@ -18,7 +18,7 @@ Formula.real_expr array array option (** heuristic option *) * bool (** game modified *) * (Arena.game * Arena.game_state) (** game and state *) - * Translate.gdl_translation (** current gdl translation *) + * TranslateGame.gdl_translation (** current gdl translation *) * int (** playclock *) val init_state : req_state Modified: trunk/Toss/Solver/Structure.ml =================================================================== --- trunk/Toss/Solver/Structure.ml 2011-07-13 09:55:22 UTC (rev 1511) +++ trunk/Toss/Solver/Structure.ml 2011-07-14 15:51:48 UTC (rev 1512) @@ -264,10 +264,10 @@ (* Add tuple [tp] to relation [rn] in structure [struc]. *) let add_rel_named_elems struc rn tp = let new_struc, tp = - Array.fold_right (fun (struc, tp) e -> + Array.fold_right (fun e (struc, tp) -> let struc, e = find_or_new_elem struc e in - struc, e::tp) - (add_rel_name rn (Array.length tp) struc) tp in + struc, e::tp) tp + ((add_rel_name rn (Array.length tp) struc), []) in let tp = Array.of_list tp in let add_to_relmap rmap = let tps = StringMap.find rn rmap in @@ -275,14 +275,14 @@ let new_rel = add_to_relmap new_struc.relations in let add_to_imap imap e = try - IntMap.add e (Tuples.add tp (IntMap.find e imap)) imap + TIntMap.add e (Tuples.add tp (TIntMap.find e imap)) imap with Not_found -> - IntMap.add e (Tuples.singleton tp) imap in + TIntMap.add e (Tuples.singleton tp) imap in let new_incidence_imap = try Array.fold_left add_to_imap (StringMap.find rn new_struc.incidence) tp with Not_found -> - Array.fold_left add_to_imap IntMap.empty tp in + Array.fold_left add_to_imap TIntMap.empty tp in let new_incidence = StringMap.add rn new_incidence_imap new_struc.incidence in { new_struc with relations = new_rel ; incidence = new_incidence } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-13 09:55:34
|
Revision: 1511 http://toss.svn.sourceforge.net/toss/?rev=1511&view=rev Author: lukstafi Date: 2011-07-13 09:55:22 +0000 (Wed, 13 Jul 2011) Log Message: ----------- GDL translation work in progress. Does not compile yet. Modified Paths: -------------- trunk/Toss/GGP/TranslateGame.ml trunk/Toss/www/reference/reference.tex Modified: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml 2011-07-13 09:54:19 UTC (rev 1510) +++ trunk/Toss/GGP/TranslateGame.ml 2011-07-13 09:55:22 UTC (rev 1511) @@ -556,8 +556,20 @@ loc_players, loc_noops -let loc_graph_turn_based loc_players loc_noops rule_cands = - +let loc_graph_turn_based player_nums + player_payoffs loc_players loc_noops rule_cands = + let graph = Array.mapi + (fun loc player -> + let player_num = List.assoc (term_to_name player) player_nums in + let pl_moves = + Array.mapi + (fun pl_num payoff -> + {Arena.payoff = payoff; + view = []; + heur = []; + moves = if pl_num = player_num then pl_moves else []}) + players) + loc_players in let loc_graph_general_int = failwith "GDL: General Interaction Games not implemented yet" @@ -601,7 +613,7 @@ let graph (*: player_loc array array*) = match turn_data, rule_cands with | Some (loc_players, loc_noops), Left cands -> - loc_graph_turn_based loc_players loc_noops cands + loc_graph_turn_based players loc_players loc_noops cands | None, Left cands -> loc_graph_general_int | None, Right cands Modified: trunk/Toss/www/reference/reference.tex =================================================================== --- trunk/Toss/www/reference/reference.tex 2011-07-13 09:54:19 UTC (rev 1510) +++ trunk/Toss/www/reference/reference.tex 2011-07-13 09:55:22 UTC (rev 1511) @@ -1719,7 +1719,16 @@ we first need to compute erasure clauses to prevent constructing too general rules in the end. +\paragraph{Concurrent Moves Games} Introduced in +Section~\ref{subsec-concurrency}, concurrent moves games use a +factored approach: since the $d_i$ never share variables, +\texttt{legal} and \texttt{next} clauses are assigned to players and +the whole construction of structure rewriting rules is done separately +for each player. Clauses without a \texttt{does} atom are assigned to +the ``environment''. (In the interpretation, to reuse code, we simply +build single-term \texttt{legal} tuples for concurrent moves games.) + \subsubsection{Erasure Clauses} So far, we have not accounted for the fact that rewrite rules of Toss @@ -1794,11 +1803,8 @@ For each suitable tuple $\ol{\calC}, \ol{\calN}$ we have now created the unifier $\sigma_{\ol{\calC}, \ol{\calN}}$ and computed the erasure -clauses $\calE_{\ol{\calC}, \ol{\calN}}$. At this point, clauses -$\ol{\calC}, \ol{\calN}$ are optionally divided according to the -player of the \texttt{does} relation atom in them, see -Section~\ref{subsec-concurrency}. To create the rules, we need to -further partition the \emph{rule clauses} $\sigma_{\ol{\calC}, +clauses $\calE_{\ol{\calC}, \ol{\calN}}$. To create the rules, we need +to further partition the \emph{rule clauses} $\sigma_{\ol{\calC}, \ol{\calN}}(\calC_i), \sigma_{\ol{\calC}, \ol{\calN}}(\calN_i)$ and $\calE_{\ol{\calC}, \ol{\calN}}$, and augment them with further conditions. The reason is that the prepared rule clauses may have @@ -2071,8 +2077,8 @@ default way of defining simultaneous moves in Toss. We now elaborate on three modes of building the game graph in the translated game. -\subsubsection{Turn-based Games} are games where in any game state there -is at most a single player having genuine choice. Rather than +\subsubsection{Turn-based Games} are games where in any game state +there is at most a single player having genuine choice. Rather than attempting a complex analysis to detect as many turn-based games as possible, we recognize some cases where in all states, all players but one have a single legal move that is a constant (term of size @@ -2084,7 +2090,9 @@ single-player game is also a turn-based game, as another example in a three-player game the first player may intersperse the moves of second and third player). We build a corresponding cyclic graph of Toss -locations. +locations. We limit the turn-based translation to the case where all +rule clauses have exactly one \texttt{does} atom (\ie can be +attributed to exactly one of the players). \subsubsection{Concurrent Moves Games} \label{par-concurrent-moves} When translation as a turn-based game fails, but all rule clauses have This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-13 09:54:31
|
Revision: 1510 http://toss.svn.sourceforge.net/toss/?rev=1510&view=rev Author: lukstafi Date: 2011-07-13 09:54:19 +0000 (Wed, 13 Jul 2011) Log Message: ----------- GDL translation work in progress. Does not compile yet. Modified Paths: -------------- trunk/Toss/GGP/TranslateGame.ml Modified: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml 2011-07-10 19:47:57 UTC (rev 1509) +++ trunk/Toss/GGP/TranslateGame.ml 2011-07-13 09:54:19 UTC (rev 1510) @@ -226,10 +226,11 @@ ) struc element_reps ) struc maks_reps in next_clauses, f_paths, m_paths, mask_reps, defined_rels, - stable_base, init_state, struc, elem_term_map + stable_base, init_state, struc, agg_actions, elem_term_map -(* Find the rule clauses $\ol{\calC},\ol{\calN}$. *) +(* Find the rule clauses $\ol{\calC},\ol{\calN}$. Do not remove the + "does" atoms from clauses. *) let move_tuples used_vars next_cls legal_tuples = (* computing the $d_i(\calN)$ for each $\calN$ *) let fresh_x_f () = @@ -346,9 +347,9 @@ legal_tup, next_cls @ erasure_cls -(* Assign rule clauses to rule cases, i.e. candidates for Toss - rules. Collect the conditions and RHS state terms together. *) -let rule_cases (legal_tup, next_cls) = +(* Assign rule clauses to rule cases, i.e. candidates for + Toss rules. Collect the conditions and RHS state terms together. *) +let rule_cases next_cls = let atoms = Aux.concat_map (fun (_, body) -> Aux.map_some (function | Pos (Rel _ as a) | Neg (Rel _ as a) -> Some a @@ -387,18 +388,37 @@ ) choice patterns ) next_cls in let case_rhs, case_conds = List.split case_cls in - case_rhs, separation_cond @ case_conds in - let legal_tup, legal_cond = List.split legal_tup in - let legal_cond = List.concat legal_cond in - List.map (fun choice -> - let case_rhs, case_conds = rule_case choice in - let case_conds = case_conds @ legal_cond in - legal_tup, case_rhs, case_conds) choices + case_cls, case_rhs, separation_cond @ case_conds in + List.map rule_case choices +let nonint_rule_cases (legal_tup, next_cls) = + let legal_tup, legal_cond = List.split legal_tup in + let legal_cond = List.combine legal_cond in + List.map (fun (case_rhs, case_cond) -> + legal_tup, case_rhs, case_cond @ legal_cond + ) (rule_cases next_cls) + +(* If "Concurrent Moves" case, divide rule clauses among players. *) +let concurrent_rule_cases players (legal_tup, next_cls) = + Array.mapi (fun i player -> + let legal_head, legal_cond = legal_tup.(i) in + let cls = List.filter + (fun (_,cl_body) -> List.exists ( + function Does (p, _) when p=player -> true | _ -> false) + cl_body) + next_cls in + List.map (fun (case_rhs, case_cond) -> + legal_head, case_rhs, case_cond @ legal_cond + ) (rule_cases cls) + ) players + +let general_int_rule_cases (legal_tup, next_cls) = + failwith "General Interaction Games not implemented yet" + (* The candidates need to be filtered before finishing the translation of Toss rules. *) -let create_rule_cands used_vars next_cls clauses = +let create_rule_cands is_turn_based used_vars next_cls clauses = let players = (* Array.of_list *) Aux.map_some (function | ("role", [player]), _ -> Some player @@ -406,6 +426,13 @@ ) clauses in let legal_cls = List.filter (fun ((rel,_),_) -> rel="legal") clauses in + let is_concurrent = not is_turn_based && + List.for_all + (fun (_, body) -> + List.length + (List.filter (function Does _ -> true | _ -> false) body) + <= 1) + next_cls in (* let next_cls = List.filter (fun ((rel,_),_) -> rel="next") clauses in *) (* constructing $(\calC_1,...,\calC_n)$ tuples *) @@ -415,14 +442,26 @@ | ("legal",[lp; l]), body when lp = p -> Some (l, body) | _ -> None) legal_cls ) players in - let legal_tuples = Aux.product legal_by_player in - let move_tups = move_tuples used_vars next_cls legal_tuples in - let move_tups = - List.map (fun (sb, legal_tup, n_cls) -> - List.map (subst sb) legal_tup, - List.map (subst_clause sb) n_cls) move_tups in - let move_tups = List.map add_erasure_clauses move_tups in - Aux.concat_map rule_cases move_tups + let process_rule_cands legal_tuples = + let move_tups = move_tuples used_vars next_cls legal_tuples in + let move_tups = + List.map (fun (sb, legal_tup, n_cls) -> + List.map (subst sb) legal_tup, + List.map (subst_clause sb) n_cls) move_tups in + List.map add_erasure_clauses move_tups in + let concurrent_rule_cands player legal_cls = + let legal_tuples = List.map (fun cl -> [cl]) legal_cls in + let move_tups = process_rule_cands legal_tuples in + player, Aux.concat_map nonint_rule_cases move_tups + if is_concurrent then + Right (List.map2 concurrent_rule_cands players legal_by_player) + else + let legal_tuples = Aux.product legal_by_player in + let move_tups = process_rule_cands legal_tuples in + if is_turn_based then + Left (Aux.concat_map nonint_rule_cases move_tups) + else + Left (Aux.concat_map general_int_rule_cases move_tups) let filter_rule_cands stable_base defined_rels rule_cands = @@ -434,18 +473,109 @@ List.mem rel defined_rels || not (List.exists (rels_unify a) stable_base) | _ -> true in - List.filter (fun (_, _, case_conds) -> - List.for_all check_atom case_conds - ) rule_cands + let check_cands cands = + List.filter (fun (_, _, _, case_conds) -> + List.for_all check_atom case_conds + ) cands in + match rule_cands with + | Left cands -> Left (check_cands cands) + | Right cands -> + Right (List.map (fun (p,cands) -> p, check_cands cands) cands) +exception Not_turn_based +(* Check if game is turn based and return the player cycle if it is, + otherwise rise [Not_turn_based]. Also return the [noop] actions + for players in the locations. *) +let check_turn_based players agg_actions = + let noop_cands = List.map (fun actions -> + let actions = Aux.map_reduce + (function [player; action] -> player, action + | _ -> assert false) (fun y x->x::y) [] actions in + List.map (function + | player, [Const _ as noop] -> player, Some noop + | player, _ -> player, None) actions + ) agg_actions in + let control_cands = List.map (fun noop_cands -> + List.fold_left (fun accu -> function + | player, None -> + if accu = None then Some player + else raise Not_turn_based + | _, Some _ -> accu) None noop_cands) noop_cands in + let noop_cands = List.map Aux.collect noop_cands in + (* throw in players with (multiple) constant actions *) + let control_noop_cands = List.map2 (fun ccand noops -> + let nccands, noops = Aux.partition_map + (function player, [] -> assert false + | player, [noop] -> Aux.Right (player, noop) + | player, more_actions -> Aux.Left player) noops in + match ccand, nccands with + | None, [player] -> Some player, noops + | Some _, [] -> ccand, noops + | _ -> raise Not_turn_based + ) control_cands noop_cands in + let control_cands, noop_cands = + List.split control_noop_cands in + (* 2b *) + let loc_players = find_cycle control_cands in + (* {{{ log entry *) + if !debug_level > 0 then ( + Printf.printf "check_turn_based: location players %s\n%!" + (String.concat " " + (List.map (function Some t->term_str t | None->"None") + loc_players)) + ); + (* }}} *) + let loc_players = Array.of_list + (List.map (function Some p -> p | None -> players.(0)) + loc_players) in + let loc_n = Array.length loc_players in + let find_player_locs player = + Aux.array_argfind_all (fun p->p=player) loc_players in + (* noop actions of a player in a location *) + let loc_noops = + let i = ref 0 in + let noops = ref noop_cands in + let loc_noops = Array.make_matrix loc_n players_n None in + while !noops <> [] do + List.iter (function _, None -> () + | player, (Some _ as noop) -> + let p_i = find_player player in + if loc_noops.(!i).(p_i) = None + then loc_noops.(!i).(p_i) <- noop + else if loc_noops.(!i).(p_i) <> noop + (* moves are not simultaneous, but different [noop] actions + are used by the same player -- can be resolved by + introducing separate locations for each noop case *) + then raise Not_turn_based) + (List.hd !noops); + incr i; if !i = loc_n then i := 0; + noops := List.tl !noops + done; + loc_noops in + loc_players, loc_noops + + +let loc_graph_turn_based loc_players loc_noops rule_cands = + + +let loc_graph_general_int = + failwith "GDL: General Interaction Games not implemented yet" + +let loc_graph_concurrent = +() + let translate_game clauses = let clauses = expand_players clauses in let used_vars, clauses = rename_clauses clauses in let next_cls, f_paths, m_paths, mask_reps, defined_rels, - stable_base, init_state, struc, elem_term_map = + stable_base, init_state, struc, agg_actions, elem_term_map = create_init_struc clauses in - let rule_cands = create_rule_cands used_vars next_cls clauses in + let turn_data = + try Some (check_turn_based players agg_actions) + with Not_turn_based -> None in + let rule_cands = + create_rule_cands (turn_data <> None) used_vars next_cls clauses in let rule_cands = filter_rule_cands stable_base rule_cands in let all_state_terms = Aux.concat_map state_terms (List.map snd clauses) in @@ -460,18 +590,42 @@ defrel_arg_type = ref []; (* built in TranslateFormula *) term_arities = term_arities; } in - - let game = assert false + let defined_rels = build_defrels transl_data clauses in + let players = Array.of_list + (Aux.map_some (function + | ("role", [player]), _ -> Some player + | _ -> None + ) clauses) in + let player_names = Array.to_list + (Array.mapi (fun i p -> term_to_name p, i) players) in + let graph (*: player_loc array array*) = + match turn_data, rule_cands with + | Some (loc_players, loc_noops), Left cands -> + loc_graph_turn_based loc_players loc_noops cands + | None, Left cands -> + loc_graph_general_int + | None, Right cands + loc_graph_concurrent + | _ -> assert false in + let game = { + Arena.rules = rules; + patterns = []; + graph = graph; + num_players = Array.length players; + player_names = player_names; + data = []; + defined_rels = defined_rels; + } in let gdl_translation = { - (* map between structure elements and their term representations; - the reverse direction is by using element names *) + (* map between structure elements and their term representations; + the reverse direction is by using element names *) elem_term_map = elem_term_map; f_paths = f_paths; m_paths = m_paths; masks = mask_reps; tossrule_data = tossrule_data; - (* rule name to rule translation data *) + (* rule name to rule translation data *) } in gdl_translation, (game, {Arena.struc = struc; time = 0.; cur_loc = 0}) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-10 19:48:05
|
Revision: 1509 http://toss.svn.sourceforge.net/toss/?rev=1509&view=rev Author: lukstafi Date: 2011-07-10 19:47:57 +0000 (Sun, 10 Jul 2011) Log Message: ----------- GDL translation work in progress: file changes. Does not compile yet. Modified Paths: -------------- trunk/Toss/GGP/TranslateFormula.ml trunk/Toss/GGP/TranslateGame.ml Added Paths: ----------- trunk/Toss/GGP/TranslateFormula.mli trunk/Toss/GGP/TranslateGame.mli trunk/Toss/GGP/TranslateGameTest.ml Removed Paths: ------------- trunk/Toss/GGP/Translate.ml trunk/Toss/GGP/Translate.mli trunk/Toss/GGP/TranslateTest.ml Deleted: trunk/Toss/GGP/Translate.ml =================================================================== --- trunk/Toss/GGP/Translate.ml 2011-07-09 12:37:34 UTC (rev 1508) +++ trunk/Toss/GGP/Translate.ml 2011-07-10 19:47:57 UTC (rev 1509) @@ -1,3711 +0,0 @@ -open GDL - -(** {2 Game Description Language.} - - Type definitions, helper functions, game specification - translation. - - The translation is not complete (yet), and not yet guaranteed to - be sound (but aiming at it) -- report any cases where the - algorithm does not fail explicitly but does not preserve - semantics. - - (1) Aggregate playout: generate successive states as if all moves - legal in the previous state were performed. Do not check the - termination predicate. To avoid ungrounded player variables, add - "role" filter to "legal" rules. - - (1a) Reason for unsoundness: "legal" or "next" preconditions can - depend negatively on state, preventing further moves in the - aggregate state that would be possible in some of valid game - states; the aggregate state does not have enough terms as a - result. Workaround: remove negative literals from "legal"/"next" - conditions for generating aggregate playout. - - (1b) Saturation works on definitions stratified - w.r.t. negation. Positive literals are instantiated one by one, - then negative literals are checked over the facts derived from - previous strata. To avoid redundancy, new facts and new - instantiations are kept separate for the next iteration within a - stratum. - - (1c) Heuristic reason for unsoundness: while we check for fixpoint - in the playout, we rule out state terms "F(X)" where X is a player - (assuming that "F" means "control"). Workaround: turn off fixpoint - checking [aggregate_fixpoint]. - - (2) Arena graph: currently, only a simple cycle is allowed. The - succession of players is determined from the aggregate playout. - - In case of problems, it should be relatively easy to expand the - translation to use a single location per player, and for rules to - determine which player is active after the rule takes effect - (i.e. the target location.) Once Toss has a good system for - simultaneous moves, we can simplify by translating into a single - location game, obsoleting this "chapter". - - (2a) We need to recognize which player actually makes a move in a - state. For this we need to locate the "noop" arguments to "legal" - and "does" relations. A noop action in a location is the only - action in the corresponding state of an aggregate playout for the - player that is also constant. - - (2b) We determine the player of a location by requiring that at - most one player has a non-noop action in an aggregate - state. When all players are noops we select the control player so - that the smallest "game cycle" is preserved. Otherwise (more than - one no-noop move) we fail (simultaneous moves not supported). We - remember the noop actions for each location and player. - - (3) Currently, a constant number of elements is assumed. The rules - processed in (3a)-(3b) are already expanded by (6). - - (3a) Element terms are collected from the aggregate playout: the - sum of state terms. - - (3b) Element masks are generated by generalization from all "next" - rules where the "does" relations are expanded by all unifying - "legal" rules (see also (7a)). - - (3c) Generalization in a single expanded "next" rule is by finding - for the "next" term the closest "true" term in the lexicographic - ordering of (# of matched variables, # of other matched leaves), - but in case the closest term is found in the negative part, it is - further processed. - - (3c1) Unmatched subterms are replaced by meta-variables. - - (3c2) When the generalization comes from the negative part, we - replace all constant leaves with meta-variables. Warning: this - heuristic is a reason for unsoundness -- search for a workaround - once a real counterexample is encountered. - - (3c3) When [nonerasing_frame_wave] is set to [true], remove - branches that have a variable/variable mismatch at proposed fluent - position.(TODO) - - (3d) The masks are all the minimal w.r.t. matching (substitution) - of the generalized terms, with only meta-variable positions of the - mask matching meta-variable positions of a generalized - term. - - TODO: this is wrong! Generates too many masks compared to the - paper method (using fluent paths). Should generalize masks that - do not differ at constant/functor-constant/functor positions. - - (3e) The elements are the equivalence classes of element terms, - where terms are equivalent when they both match a single mask and - their matching substitutions differ only at - meta-variables. (I.e. for t1 and t2 there exists a mask m and - substitutions s1 and s2 such that s1(m)=t1 and s2(m)=t2 and - s1(x)=/=s2(x) implies that x is/contains a meta-variable.) - - (Note that there is "nothing wrong" with a given equiv class not - having any member in the initial state or some other state. The - element is still there in the structure, still participating in - the "static" relations, but not in the "dynamic" predicates in - that particular state. We use a special _BLANK_ term/predicate to - faciliate operations on such "absent" elements.) - - (4) Static relations (their tuples do not change during the game) - are derived from static facts with subterms common with element - terms but not below meta-variables. - - Define mask-paths as the set of a mask together with a path in it - to a position that is not below (or at) a meta-variable. - - Implementation: currently we approximate paths by only taking the - positions of variables in the mask. - - (4a) (Fact relations.) For a static fact (a relation that does not - depend on "true" or "init") (unless it is expanded -- see (6)), - introduce a relation for each mask-paths tuple with arity of the - relation (i.e., introduced relations are a dependent product of - static fact relations and a cartesian n-th power of the mask-paths - set where n is the arity of the relation). An introduced relation - holds over a tuple of elements, iff the corresponding element - terms match the respective masks, and the original relation holds - over the tuple of subterms selected from the element terms by the - corresponding paths. - - (4b) (Equality relations.) For each mask-path, introduce a binary - relation that holds over elements which have the same subterm at - the mask-path position. (Because of mask-paths definition, same - for all element terms in element's equivalence class.) - - (4c) (Anchor predicates.) Add a predicate for being derived from a - mask (which is applied in (7i-4c) only if not adding mask-path - predicates, fact or equivalence relations from which it can be - inferred). For each mask-path pointing to a constant in some of - the elements and that constant, introduce a new predicate with - semantics: "matches the mask and has the constant at the path - position". - - Optionally, also include a positive mask predicate for negative - state terms (rather than a negative one). - - (5) (Mostly) dynamic relations ("fluents": their tuples change - during the game), relations derived from all below-meta-variable - subterms of element terms, initialized by those that appear in the - initial state. (Some relations introduced in this step might not - be fluents.) - - (See also (7k).) For each element term, find the element mask it - matches, and introduce relations for each meta-variable of the - element mask, associated with the subterm that matches the - meta-variable. The semantic is that the relation selects the - element terms that match the mask with the associated subterm - subsituted for the corresponding meta-variable, with existential - interpretation. A relation holds initially over an element, if in - the initial set of element terms at least one from the element's - equivalence class is selected by the relation. An occurrence of - "true" or "next" relation is replaced by a conjunction of - relations whose substituted-masks match the relation's term. - - When generating predicates that hold over an element term, no - predicate is generated for any its meta-variable position that - contains _BLANK_. - - (6) Currently how to introduce defined relations in translation is - not yet solved in the presented framework. Currently, we simply - expand relations that are not static, or (optionally) are static - but do not contain ground facts, by duplicating the branch in - which body an atom of the relation occurs, for each branch of the - relation definition, unifying and applying the unifier. (If the - duplication turns out prohibitive, this will be a huge TODO for - this translation framework.) - - First, we expand all uses of the built-in "role" predicate. - - (6a) The definition: - - [(r, params1) <= body1 ... (r, params_n) <= body_n] - - provides a DNF defining formula (using negation-as-failure): - - [(r, args) <=> exist vars1 (params1 = args /\ body1) \/ ... - \/ exist vars_n (params_n = args /\ body_n)] - - which expands in a natural way for positive occurrences. We - duplicate the branch where [(r, args)] is substitued for each - disjunct and apply the unifier of [params_i = args] in the whole - [i]th cloned branch, eliminating the [params] (rather than the - [args]) when possible. We freshen each [vars_i] to avoid - capture. If unification fails, we drop the corresponding branch - clone. - - (6b) For negative occurrences we transform the defining formula - to: - - [not (r, args) <=> not exist vars1 (args = params1 /\ body1) /\ ... - /\ not exist vars_n (args = params_n /\ body_n)] - - (6b1) If the relation has negative subformulas in any of [body_i], - unless all the negative subformulas are just "distinct" checks - that become ground, we first negate the definition and then expand - the negation as in the positive case. - - (6b1a) Eliminate [args = params_i] by substituting-out variables - from [params_i] whenever possible. - - Note: the [args] need to be instatiated for the particular - solution that is extended (the solution substitution applied). - - (6b1b) We group the positive atoms of body_i together and split - the quantifier if each negative subformula and the positive part - have disjoint [vars_i] variables; if not, the translation fails; - currently, if a negative subformula has free variables in vars_i, - the translation also fails. - - (6b1c) So we have two levels of specification-affecting TODOs; - working around variables shared between negated subformulas or the - positive part -- forbidding pushing quantification inside -- will - require major rethinking of implementation; if the quantification - can be pushed inside but doesn't disappear around a negated - subformula, we will need to extend the universal quantifier - handling from only negated to both negated and positive - subformulas, which shouldn't be problematic. - - (6b1d) Now push the negation inside the conjunction so that all - double negations cancel out (the positive conjuncts are under a - single, now negated, quantifier -- see (6b2) about negated - conjunctions of atoms). Next we pull the disjunctions out - (reducing to DNF-like form), and continue as in the positive case - (6a). - - (6b2) We allow conjunctions of atoms to be negated (not only - literals) in a branch. We expand [not (r, args)] (in general, [not - (and (...(r args)...))]) into the conjunction of negations, with - no branch duplication (in general, duplicating the negated - subformula inside a branch). We only apply the unifier of [args = - params_i] to [body_i] (in general, the whole negated subformula), - eliminating the [params] (rather than the [args]) when - possible. Still, we freshen each [vars_i] to avoid capture. We - remember the (uneliminated) [vars_i] in the set of variables - quantified existentially under the negation (since the free - variables occurring only under the negation are quantified - universally there -- it is a positive position). If unification - fails, we drop the corresponding negated subformula. If - unification succeeds but the corresponding [body_i] is empty (and, - in general, no other disjuncts in the negated subformula are - left), we drop the branch. - - (7) Generation of rewrite rules when the dynamic relations are not - recursive and are expanded in the GDL definition. - - (7a) We translate each branch of the "legal" relation definition - as one or more rewrite rules. Currently, we base availability of - rules in a location on the player in the location and noop actions - of other players in it, compared to the "legal" definition - branch (currently, we do not allow simultaneous moves). If the - branch of "legal" definition has a variable for a player, it is - instantiated for each player in the game, and the variable - substituted in the body of the "legal" branch. A rewrite rule is - associated with a single "lead legal" branch of the location's - player. - - (7a1) Filter "lead legal" rules by satisfiability in the current - location plys of the aggregate playout. - - (7b) We collect all the branches of the "next" relation definition - for which the selected branches of "lead legal" and "noop legal" - (the "joint legal" actions) unify with all (usually one, but we - allow zero or more) occurrences of "does" with a single unifier - per "next" branch. (A "noop legal" actually only matches and - substitutes the local variables of "next" branches.) Split the - unifiers into equivalence classes (w.r.t. substitution), each - class will be a different rewrite rule (or set of rules). (Note - that equivalent unifiers turn out to be those that when truncated - to variables of the "legal" branch are renamings of each other.) - - (7b1) Since the "noop legals" are constants (by current - assumption), we do not need to construct equivalence classes for - them. Their branches will join every rule generated for the "joint - legal" choice. - - (7c) Find a single MGU that unifies the "legal" atom argument and - all the "does" atoms arguments into a single instance, and apply - it to all "next" branches of the rule (i.e. after applying the - original unifier, apply a renaming that makes the unifier equal to - all other unifiers in the equiv. class). We replace all - occurrences of "does" with the body of the selected "legal" - branch. - - (7d) Add all branches of equiv classes smaller than a given equiv - class to its branch set. - - Implementation TODO (reason for unsoundness): currently, we - discard non-maximal equivalence classes, because negation (7e) is - not implemented, and with negation it would still be preferable to - have exhaustiveness check so as to not generate spurious - (unapplicable) rules. TODO: rethink, compare with (7f2). - - (7e) Associate negation of equalities specific to the unifiers - strictly less general than the equivalence class with it, so that - the resulting conditions form a partition of the space of - substitutions for the "legal" branch processed. - - (7f) We remember all variables in the "legal"/"does" instantiation - as "fixed variables". We seggregate "next" atoms into these that - contain some fixed variables or no variables at all, and other - containing only unfixed variables. - - (7f1) Branches with only (TODO: some? (x)) unfixed variables in "next" - atoms that are "identities" are the "frame" branches. "Identity" - here means the "next" atom is equal to one of the positive "true" - atoms. - - (x) It is probably better to not expand "identity" branches that - have both fixed and unfixed variables in the head, as they will be - correctly handled (translated to erasure branches) in the - following code. - - (7f2) Transform the "frame" branches into "erasure" branches: - distribute them into equivalence classes of head terms - (w.r.t. substitution but treating fixed variables as constants), - add smaller elements and negation of larger elements (in the same - manner as in (7b) and (7d) for the "legal" term), disjoin bodies - in each class (a "multi-body"), then: - - (7f3) negate the multi-body, push negation inside (using de Morgan - laws etc.), split into separate "erasure" branch for each - disjunct, place the original "next" atom but with meta-variable - positions replaced by _BLANK_ as the head of the "erasure" branch, - apply (and remove) unification atoms resulting from negating the - "distinct" relation. The local variables of newly created negated - subformulas become existentially-quantified-under-negation - (i.e. universally quantified) (while the local variables of old - negated subformulas are "let free"). - - FIXME: it is probably wrongly assumed in the implementation that - negated "distinct" unifies all terms, instead of disjunction of - pairwise unification, check that. - - (7f4) Drop the erasure branches that contradict the "legal" - condition of their rule. (Add the "legal" condition for early pruning.) - - (7f5) Redistribute the erasure branches in case they were - substituted with the "not distinct" unifier to proper equivalence - classes (remove equivalence classes that become empty). - - (7f6) Filter-out branches that are not satisfiable by their static - part (in the initial structure). - - (7g) NOOP (Was eliminating unfixed variables.) - - (7h) Introduce a new element variable for each class of "next" and - "true" terms equal modulo mask (i.e. there is a mask matching them - and they differ only at-or-below metavariables). (Remember the - atoms "corresponding variable".) From now on until (7l1) we keep - both the (partially) Toss-translated versions and the (complete) - GDL-originals of branches (so to use GDL atoms for "subsumption - checking" in (7l)). - - (7i-7k) Variables corresponding to negated "true" atoms - that contain locally existentially quantified variables are - quantified universally (with a scope containing all their - occurrences). - - Implementation: we only introduce universal quantification after - filtering (7m), is it OK? - - (7i-4a) For all subterms of "next" and "true" atoms, identify the - sets of <mask-path, element variable> they "inhabit". Replace a - static fact relation by relations built over a cartesian product - of <mask-path, element variable> sets derived for each static - fact's argument by applying corresponding (4a) relations. Only - build the relation over positive elements, deferring negated ones - to (7k-4a) so that they are included under common - disjunction. Relations over elements coming from different - negations are not introduced, which agrees with negation-as-failure. - - (7i-4c) Include the (4c) relations for "next" and "true" positive - atoms. - - (7i-4b) (4b) is essentially a special case of (4a). Add an - appropriate equality relation of (4b) for each case of subterm - shared by terms corresponding to different positive elements. - - Implementation: instead of all subterms we currently only consider - subterms that instantiate (ordinary) variables in the mask - corresponding to the "next"/"true" atom. - - (7i0) For "distinct", negate the anchors of the constants at mask - paths of the variables, and equivalences of the variables (if - there are multiple variables). - - TODO: currently only checks whether "distinct" arguments are - syntactically equal. - - (7i1) Remove branches that are unsatisfiable by their static - relations (4a), (4b) and (positive) (4c) alone. - - (7j) Identify variables in "next" & "true" terms that are - at-or-below meta-variables in the corresponding mask. (Most of - such variables should be already removed as belonging to "frame" - branches.) Such fixed variables should be expanded by duplicating - the whole set of branches together with the "lead legal" term. - - Implementation: TODO; currently, we check for such fixed - variables and fail if they're present. - - (7k) Replace the "next" and "true" atoms by the conjunction of - (4b), (4c) and (5) predicates over their corresponding variable. (For - negative "true" literals this will be equivalent to a disjunction - of negations of the predicates.) Note that positive static - relations are already added in (7i-4b,4c). Handle negative subformula - translations of (4a, 4b, 4c, 5) together. - - (7k-4a-1) Add to the disjunction a negation of all what (7i-4a) - would generate (i.e. for positive facts), but over tuples with at - least one of the negated elements of current negation (no elements - from other negations). - - (7k-4a-2) For a negative fact generate result equivalent to a - *conjunction* of negations of generated atoms if all elements are - positive, - - (7k-4a-3) but add a *disjunction* of negations (i.e. a negated - conjunction) of tuples with at least one negated element. - - (7k-4c) Include the (4c) relations for "next" and "true" negative - atoms. - - (7k-4b) It is essentially a special case of (7k-4a-1). Introduce - equivalences as in (7i-4b), but with tuples containing at least - one element from the current negation (no elements from other - negations). Generate the same set of equivalence tuples as a - positive occurrence would so that they can be pruned when - possible. - - TODO: handle "distinct" that contains variable(s)! - - (7l) Build a pre-lattice of branch bodies w.r.t. subsumption, - in a manner similar to (7b). The subsumption test has to say "no" - when there exists a game state where the antecedent holds but the - consequent does not, but does not need to always say "yes" - otherwise. Build a rewrite rule for each equivalence class - w.r.t. subsumption, including also branches that are below the - equiv class, and including negation of conditions that make the - branches strictly above more specific -- so that the classes form - a partition of the nonterminal game states (it is semantically - necessary so that all applicable changes are applied in the - translated game when making a move). The lattice is built by - summing rule bodies. - - (7l0) To avoid contradictions and have a complete partition, we - construct the set of all bit vectors indexed by all atoms - occurring in the bodies (optionally, all atoms in bodies of - branches containing "does" atoms). We collapse atoms that have the - same pattern of occurrence in the branches as single index. - - (7l1) With every index-bit value we associate the set of branches - that do not allow such literal. For every vector we calculate the - complement of the sum of branch sets associated with every - bit. The unique resulting sets are exactly the Toss rules - precursors. Heuristic (FIXME: needed?): We only use atoms that are - deterministically present or absent in at least some branch for - indexing. - - (7l2) Filter rule candidates so that each has a "does"-specific - branch. - - TODO: perhaps should be optional -- perhaps there are "default - all noop rules" in some games. - - (7l3) Optionally, remove synthetic branches that do not have (a) - gdl variables (i.e. Toss equivalence relations) or (b) state terms - (i.e. Toss variables) in common with the non-synthetic branches of - the rule candidate. - - Only translate the formulas after (7l3). - - (7l3b) In this optional case, only keep synthetic branches that - either have non-state-term atoms with gdl variables common with - base branches, or actually have state terms in common with base - branches. (E.g. do not keep a branch with "(R ?x ?y) (true (ST ?v ?x)) - (true (ST ?v ?y))" when only "v" is in common with base branches.) - - (7l4) Filter out rule candidates that contradict all states - from the current location plys of aggregate playout (by their - "true" atoms -- "not true" are not valid in the aggregate playout). - - (7l5) Here a set of branches has conjunctive interpretation, since - they are the "next" clauses that simultaneously match. If a branch - fails, the whole case fails. - - (7m) Filter the final rule candidates by satisfiability of the - static part (same as (7i1) conjoined). - - (7n) Include translated negation of the terminal condition. (Now we - build rewrite rules for a refinement of an equivalence class of - (7b): from the branches with unifiers in the equiv class, from - branches with unifiers more general than the equiv class, and from - the disjointness conditions and the terminal condition.) - - (7n1) Prior to translation, expand all variables under - meta-variables in "terminal" branches, as in (7j). - - The rewrite rule is generated by joining the derived conjunctions - from "next" atoms as RHS, and from bodies as the - precondition. Exactly the RHS variables are listed in the LHS - (other variables are existentially closed in the - precondition). All the relations that appear in either LHS or RHS - are considered embedded. - - (7o) After the rules are translated, perform an aggregated playout - of the Toss variant of the game. Remove the rules that were never - applied. - - (8) We use a single payoff matrix for all locations. Goal patterns - are expanded to regular goals by instantiating the value variable - by all values in its domain (for example, as gathered from the - aggregate playout), and expanding all atoms that contained value - variables (both static and dynamic) using (6); fail if a goal - value cannot be determined. - - (8a) Filter-out goal branches that are contradictory with the - terminal condition (using resolution on the GDL - side). Implementation TODO. - - (8b) For each goal value we collect bodies to form a disjunction. - - (8c) The payoff formula is the sum of "goal" value times the - characterisic function of the corresponding "goal" bodies. To - simplify the result, we find the longest formula, and center the - payoff around it: for the goal value V_i if i-th formula phi_i and - phi_K being the longest formula, we translate the payoff into "K + - (V_1 - V_K) :(phi_1) + ... (V_n - V_K) :(phi_n)" thus removing - phi_K from translation. - - (8d) Finally, we simplify the result. Unused predicates are not - removed, because some of them will be needed for action translation. - - (9) To translate an incoming action, we: - - (9a) find the "lead legal" term to which the "does move" ground - term of the current player matches; - - (9b) earlier, remember which Toss variables of a rule contain which - fixed variables at which positions in their masks; - - (9c) find anchor predicates corresponding to instantiations of the - "lead legal" variables, anchoring positions found by (9b) "fixed - var" - "mask + mask var" correspondence; - - (9d) build a conjunction of anchor predicates over variables that - contain the fixed variable which is "instantiated" by the anchor - of the corresponding position, as established by (9c); - - (9e) conjoin the (9d) with the "matching" formula of a rule, and - evaluate the result for all rules (of the located "lead legal" - class); only a single rule should have a match, and only a single - assignment should be returned; this rule with this assignment is - the translated move. - - (10) To translate an outgoing action, we: - - (10a) associate the rule with its corresponding data: the "lead - legal" term, the fixed variables corresponding to rule elements, - ... - - (10b) earlier, return/store the mapping from an element to the - mask and subsitution that define the element; - - (10c) earlier, for each rule store a mapping from fixed variables - to rule variables and the mask variables that in the rule variable - are instantiated by the fixed variables; - - (10d) to determine how to instantiate the fixed variables in the - "lead legal" term, find the (10b) substitutions of assigned - elements and (10c) mask variables for fixed variables; compose the - maps to get fixed variable to GDL ground term mapping, each - "route" should give the same term. - - Implementation TODO: once the LHS-RHS structures are removed from - the backbone and formula registration is removed, some - simplifications can be done in (9) and (10). - -*) - -let debug_level = ref 0 - -(** Include mask predicates (first part of (4c)) of negative state - term atoms as either positive or negated atoms. *) -type mask_anchors_of_neg = Positive_anch | Negative_anch | No_anch -let mask_anchors_of_neg = ref (* Positive_anch *) Negative_anch - -(** Approximate rule preconditions by dropping parts of "partition - guards" of (7l) -- parts of conditions introduced merely to - distinguish rules that should not be available at the same time. *) -type approximate_rule_preconds = - | Exact (** keep all conditions *) - | Connected (** keep all connected to - variables appearing in the - rest, i.e. containing - common gdl variables *) - | TightConnected (** keep connected but - ignoring equivalence - links, i.e. containing - common gdl state terms *) - | DropAll -let approximate_rule_preconds = ref (* Connected *) Exact - -(** Filter rule candidates by the stable part of precondition either - before or after game simplification. *) -type prune_rulecands = Before_simpl | After_simpl | Never -let prune_rulecands_at = ref (* Before_simpl *) Never - -(** Perhaps generate all tuples for equivalences, to faciliate further - transformations of formulas in the game definition (outside of - translation). *) -type pair_matrix = Pairs_all | Pairs_triang | Pairs_star -let equivalences_all_tuples = ref Pairs_triang -let equivalences_ordered = ref true - -(** Generate test case for the given game name. *) -let generate_test_case = ref None - -open Aux.BasicOperators - -type tossrule_data = { - lead_legal : GDL.term; - (* the "legal"/"does" term of the player that performs the move, we - call its parameters "fixed variables" as they are provided externally *) - precond : Formula.formula; - (* the LHS match condition (the LHS structure and the precondition) *) - rhs_add : (string * string array) list; - (* the elements of LHS/RHS structures, corresponding to the "next" - terms *) - struc_elems : string list; - fixvar_elemvars : - (string * (GDL.term * (string * string list) list) list) list; - (* "state" terms indexed by variables that they contain, together - with the mask-path of the variable *) - elemvars : GDL.term Aux.StrMap.t; -(* "state" terms indexed by Toss variable names they generate *) -} - -type gdl_translation = { - anchor_terms : - (GDL.term * (string * (GDL.term * string) list) list) list; - (* mask path (i.e. mask+var) and a ground term to anchor predicate *) - tossrule_data : tossrule_data Aux.StrMap.t; - (* rule name to rule translation data *) - t_elements : GDL.term Aux.IntMap.t; - (* element terms (with metavariables only) *) - playing_as : int; - (* "active" player *) - noop_actions : GDL.term option array; - (* NOOP actions of "active" player indexed by locations *) - fluents : string list; -} - -let empty_gdl_translation = - {anchor_terms = []; - tossrule_data = Aux.StrMap.empty; - t_elements = Aux.IntMap.empty; - playing_as = 0; - noop_actions = [||]; - fluents = []} - - -let fprint_gdl_transl_data ?(details=false) ppf gdl = - (* TODO: print more data if needed *) - Format.fprintf ppf - "GDL_DATA@,{@[<1>FLUENTS@ %a;@ PLAYING_AS@ %d;@ NOOPS@ %a;" - (Aux.fprint_sep_list "," Format.pp_print_string) gdl.fluents - gdl.playing_as - (Aux.fprint_sep_list "," Format.pp_print_string) - (Array.to_list (Array.mapi (fun i -> function - | None -> string_of_int i ^": None" - | Some noop-> string_of_int i ^": "^GDL.term_str noop) gdl.noop_actions)); - Aux.StrMap.iter (fun rname data -> - Format.fprintf ppf "@ @[<1>RULE@ %s:@ LEGAL=@,%s;@ PRECOND=@,%a;@ " - rname (GDL.term_str data.lead_legal) Formula.fprint data.precond; - Format.fprintf ppf "{@[<1>RHS ADD:@ "; - Aux.fprint_sep_list ";" Format.pp_print_string ppf - (List.map (fun (rel,args) -> rel^"("^String.concat ", " - (Array.to_list args)^")") data.rhs_add); - Format.fprintf ppf "@]}@]" - ) gdl.tossrule_data; - Format.fprintf ppf "@]}" - -let sprint_gdl_transl_data ?(details=false) gdl = - ignore (Format.flush_str_formatter ()); - Format.fprintf Format.str_formatter "@[%a@]" - (fprint_gdl_transl_data ~details) gdl; - Format.flush_str_formatter () - - -(* 3c2 *) -let abstract_consts fresh_count term = - let fresh_count = ref fresh_count in - let rec loop = function - | Const _ -> incr fresh_count; MVar ("MV"^string_of_int !fresh_count) - | Func (f,args) -> Func (f, List.map loop args) - | term -> term in - loop term - - -let game_description = ref [] -let player_terms = ref [| |] - -let state_of_file s = - let f = open_in s in - let res = - ArenaParser.parse_game_state Lexer.lex - (Lexing.from_channel f) in - res - -(* 6 *) - -(* Need a global access so that the support can be reset between - different translations. (Generalization uses a local [fresh_count] - state.) *) -let var_support = ref Aux.Strings.empty - -let freshen_branch (args, body, neg_body) = - let sb = ref [] in - let rec map_vnames = function - | Var x -> - if List.mem_assoc x !sb then Var (List.assoc x !sb) - else - let x1 = Aux.not_conflicting_name ~truncate:true !var_support x in - var_support := Aux.Strings.add x1 !var_support; - sb := (x,x1)::!sb; - Var x1 - | MVar x -> - if List.mem_assoc x !sb then MVar (List.assoc x !sb) - else - let x1 = Aux.not_conflicting_name ~truncate:true !var_support x in - var_support := Aux.Strings.add x1 !var_support; - sb := (x,x1)::!sb; - MVar x1 - | Const _ as t -> t - | Func (f, args) -> - Func (f, List.map map_vnames args) in - let map_rel (rel, args) = - rel, List.map map_vnames args in - let map_neg (vs, atoms) = - let vs = - List.map (fun x -> - if List.mem_assoc x !sb then List.assoc x !sb - else - let x1 = Aux.not_conflicting_name ~truncate:true !var_support x in - var_support := Aux.Strings.add x1 !var_support; - sb := (x,x1)::!sb; x1 - ) (Aux.Strings.elements vs) in - Aux.strings_of_list vs, - List.map map_rel atoms in - List.map map_vnames args, - List.map map_rel body, - List.map map_neg neg_body - -let freshen_def_branches brs = - List.map freshen_branch brs - -let extend_sb sb1 sb = Aux.map_prepend sb1 (fun (x,t)->x, subst sb1 t) sb - - -(* [args] are the actual, instatiated, arguments. *) -let negate_def uni_vs args neg_def = - let global_vars = terms_vars args in - let aux_br (params, body, neg_body) = - let sb = unify [] params args in - let body = subst_rels sb body in - let neg_body = List.map (fun (vs, conjs) -> - vs, subst_rels sb conjs) neg_body in - let subforms = (Aux.Strings.empty, body) :: neg_body in - (* components of [vars_i] by conjuncts *) - let sub_fvars = List.map (fun (_, subphi) -> - Aux.Strings.diff (rels_vars subphi) global_vars) subforms in - let subvars = List.map2 (fun fvs (qvs,_) -> - Aux.Strings.diff fvs qvs) sub_fvars subforms in - if List.exists (fun (vs1, vs2) -> - not (Aux.Strings.is_empty (Aux.Strings.inter vs1 vs2))) - (Aux.pairs subvars) - then failwith - ("GDL.negate_def: variables shared between negated subformulas" ^ - " -- long term TODO (params: "^terms_str params^")"); - (if List.exists (fun (fvs, (qvs,_)) -> - (* [fvs - qvs] must be a subset of the "vars_i" quantified vars *) - not (Aux.Strings.is_empty (Aux.Strings.diff fvs qvs))) - (List.tl (List.combine sub_fvars subforms)) - then - let (fvs,(qvs,_)) = List.find (fun (fvs, (qvs,_)) -> - not (Aux.Strings.is_empty (Aux.Strings.diff fvs qvs))) - (List.tl (List.combine sub_fvars subforms)) in - failwith - ("GDL.negate_def: universal quantification escapes negation" ^ - " -- doable TODO (params: "^terms_str params^") (vars: "^ - String.concat ", " (Aux.Strings.elements - (Aux.Strings.diff fvs qvs))^")")); - Aux.Right (List.hd sub_fvars, body) :: - List.map (fun (_,conjs) -> Aux.Left conjs) neg_body in - (* We drop branches whose heads don't match. *) - let cnf = Aux.map_try aux_br neg_def in - let dnf = Aux.product cnf in - List.map (fun conjs -> - let pos, neg = Aux.partition_choice conjs in - let pos = List.concat pos in - pos, neg - ) dnf - -(* assumption: [defs] bodies are already clean of defined relations *) -let subst_def_branch (defs : exp_def list) - (head, body, neg_body as br : lit_def_branch) : exp_def_branch list = - var_support := Aux.Strings.union !var_support - (lit_def_br_vars br); - (* {{{ log entry *) - if !debug_level > 3 then ( - Printf.printf "Expanding branch %s\n%!" (lit_def_str ("BRANCH", [br])); - ); - (* }}} *) - (* 6a *) - let sols = - List.fold_left (fun sols (rel, args as atom) -> - (let try def = - freshen_def_branches (List.assoc rel defs) in - (* {{{ log entry *) - if !debug_level > 3 then ( - Printf.printf "Expanding positive %s by %s\n%!" rel - (exp_def_str (rel, def)) - ); - (* }}} *) - Aux.concat_map (fun (pos_sol, neg_sol, sb) -> - let args = List.map (subst sb) args in - Aux.map_some (fun (dparams, dbody, dneg_body) -> - try - let sb1 = unify [] dparams args in - Some ( - subst_rels sb1 (dbody @ pos_sol), - List.map (fun (vs,bs)->vs, subst_rels sb1 bs) - (dneg_body @ neg_sol), - extend_sb sb1 sb) - with Not_found -> None - ) def - ) sols - with Not_found -> - List.map (fun (pos_sol, neg_sol, sb) -> - subst_rel sb atom::pos_sol, neg_sol, sb) sols)) - ([[],[],[]]) body in - (* 6b *) - let neg_body_flat, neg_body_rec = - Aux.partition_map (fun (uni_vs, (neg_rel, neg_args) as neg_lit) -> - (let try def = - freshen_def_branches (List.assoc neg_rel defs) in - if not (List.exists (fun (_,_,negb) -> negb<>[]) def) - then Aux.Left (neg_lit, Some def) - else ( - (* {{{ log entry *) - if !debug_level > 3 then ( - let _,_,def_neg_body = - List.find (fun (_,_,negb) -> negb <> []) def in - Printf.printf - "expand: found recursive negative %s(%s): neg_body= not %s\n%!" - neg_rel (terms_str neg_args) - (String.concat " and not " - (List.map facts_str (List.map snd def_neg_body))) - ); - (* }}} *) - Aux.Right (neg_lit, def)) - with Not_found -> Aux.Left (neg_lit, None)) - ) neg_body in - (* checking if all negative bodies are just already satisfied - "distinct" atoms; we could refine the split per-solution, but it - isn't worth the effort *) - let more_neg_flat, neg_body_rec = - Aux.partition_map (fun (_, (_, args) as neg_lit, def as neg_case) -> - if List.for_all (function - | _,_,[] -> true - |_,_,neg_body -> - List.for_all (function - | _, ["distinct", _] -> true | _ -> false) neg_body - ) def - then - if List.for_all (function - | _,_,[] -> true - |params,_,neg_body -> - List.for_all (function - | _, ["distinct", terms] -> - List.for_all (fun (_,_,sb) -> - let args = List.map (subst sb) args in - let sb1 = unify [] params args in - let terms = List.map (subst sb1) terms in - (* {{{ log entry *) - if !debug_level > 4 then ( - Printf.printf - "Checking distinctness of %s after sb=%s; sb1=%s\n%!" - (terms_str terms) - (sb_str sb) (sb_str sb1) - ); - (* }}} *) - Aux.Strings.is_empty (terms_vars terms) - && List.length (Aux.unique_sorted terms) > 1 - ) sols - | _ -> false) neg_body) def - then - let def = List.map (fun (params, body, neg_body) -> - params, body, []) def in - Aux.Left (neg_lit, Some def) - else Aux.Right neg_case - else Aux.Right neg_case - ) neg_body_rec in - (* {{{ log entry *) - if !debug_level > 3 then ( - Printf.printf "Expanding (%s) negative part: flat %s; rec %s\n%!" - (terms_str head) - (String.concat ", "(List.map (fun ((_,(nr,_)),_) -> nr) neg_body_flat)) - (String.concat ", "(List.map (fun ((_,(nr,_)),_) -> nr) neg_body_rec)) - ); - (* }}} *) - (* 6b1 *) - let sols = - List.fold_left (fun sols ((uni_vs, (rel, args)), neg_def) -> - (* {{{ log entry *) - if !debug_level > 3 then ( - Printf.printf "Expanding rec-negative %s by %s\n%!" rel - (exp_def_str (rel, neg_def)) - ); - (* }}} *) - (* we don't keep the substitution from the negated match *) - Aux.concat_map (fun (pos_sol, neg_sol, sb) -> - let args = List.map (subst sb) args in - let branches = negate_def uni_vs args neg_def in - List.map (fun (dbody, dneg_body) -> - dbody @ pos_sol, dneg_body @ neg_sol, sb) branches - ) sols) - sols neg_body_rec in - - (* 6b2 *) - let sols = - List.map (fun (pos_sol, neg_sol, sb) -> - let more_neg_sol = - Aux.concat_map (fun ((uni_vs, (rel, args as atom)), def_opt) -> - (* negated subformulas are duplicated instead of branches *) - match def_opt with - | Some def -> - let args = List.map (subst sb) args in - Aux.map_try (fun (dparams, dbody, _) -> - (let sb1 = unify [] dparams args in - let param_vars = terms_vars dparams in - let body_vars = rels_vars dbody in - let dbody = subst_rels sb1 dbody in - let local_vs = - Aux.Strings.diff body_vars - (Aux.Strings.diff param_vars uni_vs) in - local_vs, dbody) - ) def - | None -> (* rel not in defs *) - [uni_vs, [atom]] - ) (more_neg_flat @ neg_body_flat) in - List.rev pos_sol, List.rev_append neg_sol more_neg_sol, sb - ) sols in - let res = - Aux.map_some (fun (pos_sol, neg_sol, sb) -> - if List.exists (function _,[] -> true | _ -> false) neg_sol - then None - else Some (List.map (subst sb) head, pos_sol, neg_sol)) sols in - (* {{{ log entry *) - if !debug_level > 3 then ( - Printf.printf "Expansion: res =\n%s\nExpansion done.\n%!" - (String.concat "\n"(List.map (branch_str "exp-unkn") res)) - ); - (* }}} *) - res - -(* Stratify and expand all relations in the given set. *) -let expand_def_rules ?(more_defs=[]) rules = - let rec loop base = function - | [] -> base - | stratum::strata -> - (* {{{ log entry *) - if !debug_level > 3 then ( - Printf.printf "expand_def_rules: step base rels = %s\n%!" - (String.concat ", " (List.map fst base)) - ); - (* }}} *) - let step = List.map (fun (rel, branches) -> - rel, Aux.concat_map - (subst_def_branch (more_defs@base)) branches) stratum in - (* {{{ log entry *) -if !debug_level > 3 then ( - Printf.printf "expand_def_rules: step result = %s\nexpand_def_rules: end step\n%!" - (String.concat "\n" (List.map exp_def_str step)) -); -(* }}} *) - loop (base @ step) strata in - match stratify ~def:true [] (lit_defs_of_rules rules) with - | [] -> [] - | [no_defined_rels] when more_defs=[] -> - exp_defs_of_lit_defs no_defined_rels - | def_base::def_strata when more_defs=[] -> - loop (exp_defs_of_lit_defs def_base) def_strata - | def_strata -> loop more_defs def_strata - -(* As [subst_def_branch], but specifically for "legal" definition and - result structured by "legal" definition branches. *) -(* 7b *) -let subst_legal_rule legal - (head, body, neg_body as br) - : (exp_def_branch * exp_def_branch) option = - var_support := Aux.Strings.union !var_support - (exp_def_br_vars br); - let legal = freshen_branch legal in - let legal_args, legal_body, legal_neg_body = legal in - (* {{{ log entry *) - if !debug_level > 3 then ( - Printf.printf "subst_legal_rule:\n%s\n%s\n%!" - (exp_def_str ("legal", [legal])) - (exp_def_str ("branch", [br])) - ); - (* }}} *) - if List.exists (fun (_,neg_conjs) -> - List.exists (fun (rel,_)->rel="does") neg_conjs) neg_body - then failwith - "GDL.translate_game: negated \"does\" conditions not implemented yet"; - try - let body, more_neg_body, sb = - List.fold_left (fun (body,more_neg_body,sb) (rel, args as atom) -> - if rel = "does" then - ("_DOES_PLACEHOLDER_", args) :: List.rev_append legal_body body, - List.rev_append legal_neg_body more_neg_body, - unify sb legal_args args - else atom::body, more_neg_body, sb) ([],[],[]) body in - let legal_res = - List.map (subst sb) legal_args, - subst_rels sb legal_body, - List.map (fun (uni_vs,neg_conjs) -> - (* local variables so cannot be touched *) - uni_vs, subst_rels sb neg_conjs) - legal_neg_body in - let br_res = - List.map (subst sb) head, - subst_rels sb (List.rev body), - List.map (fun (uni_vs, neg_conjs) -> - uni_vs, subst_rels sb neg_conjs) - (List.rev_append more_neg_body neg_body) in - (* {{{ log entry *) -if !debug_level > 3 then ( - Printf.printf "%s\n%s\n" - (exp_def_str ("legal-res", [legal_res])) - (exp_def_str ("br-res", [br_res])) -); -(* }}} *) - Some (legal_res, br_res) - with Not_found -> None - -let subst_legal_rules def_brs brs = - Aux.unique_sorted - (Aux.concat_map (fun br -> - List.map (fun (_,x) -> br, x) - (Aux.map_some (fun def -> subst_legal_rule def br) def_brs)) brs) - - -let rec blank_out = function - | Const a as c, Const b when a = b -> c - | (*Var _ as*) v, Var _ -> v - | t, MVar _ -> Const "_BLANK_" - | Func (f, f_args), Func (g, g_args) when f = g -> - Func (f, List.map blank_out (List.combine f_args g_args)) - | a, b -> - Printf.printf "blank_out mismatch: term %s, mask %s\n%!" - (term_str a) (term_str b); - assert false - - -let triang_matrix elems = - let rec aux acc = function - | [] -> acc - | hd::tl -> aux (List.map (fun e->[|hd; e|]) tl @ acc) tl in - aux [] elems - - -let term_to_blank masks next_arg = - let mask_cands = - Aux.map_try (fun mask -> - mask, match_meta [] [] [next_arg] [mask] - ) masks in - let mask, sb, m_sb = match mask_cands with - | [mask, (sb, m_sb)] -> mask, sb, m_sb - | _ -> - Printf.printf "GDL.term_to_blank: bad state term %s\n%!" - (term_str next_arg); - assert false in - mask, sb, m_sb, blank_out (next_arg, mask) - -let toss_var masks term = - let mask, _, _, blank = term_to_blank masks term in - mask, Formula.fo_var_of_string (String.lowercase (term_to_name blank)) - - -(* Expand branch variables. If [freshen_unfixed=Right fixed], expand - all variables that don't belong to [fixed] and appear in the head - of some branch. If [freshen_unfixed=Left freshen], then expand all - variables below meta-variables of masks. If [freshen] is true, - rename other (i.e. non-expanded) variables while duplicating - branches. (When [freshen] is false, all remaining variables should - be fixed.) - - With each branch, also return the instantiation used to derive it??? - - As in the expansion of relation definitions, branches are - duplicated for instantiations of positive literals, and - additionally of heads. For instantiations of atoms in negated - subformulas, the subformulas are duplicated within a branch, with - instantiations kept local to the subformula. Final substitution is - re-applied to catch up with later instantiations. *) -let expand_branch_vars masks playout_terms ~freshen_unfixed brs = - let head_vars = List.fold_left (fun acc -> function [head],_,_ -> - Aux.Strings.union acc (term_vars head) - | _ -> assert false) Aux.Strings.empty brs in - let use_fixed, fixed = - match freshen_unfixed with - | Aux.Left _ -> false, Aux.Strings.empty - | Aux.Right fixed -> true, fixed in -(* {{{ log entry *) -if !debug_level > 4 then ( - Printf.printf "expand_branch_vars: head_vars: %s; fixed vars: %s; before=\n%s\n%!" - (String.concat ","(Aux.Strings.elements head_vars)) - (String.concat ","(Aux.Strings.elements fixed)) - (exp_def_str ("before", brs)) -); -(* }}} *) - let expand sb arg = - let arg = subst sb arg in - let mask, _, m_sb, blank = term_to_blank masks arg in - let ivars = Aux.concat_map (fun (_,t) -> - Aux.Strings.elements (term_vars t)) m_sb in - let is_inst_var v = - (*if use_fixed - then - (Aux.Strings.mem v head_vars || List.mem v ivars) - && not (Aux.Strings.mem v fixed) - else*) List.mem v ivars in - Aux.unique_sorted - (Aux.map_try (fun term -> - let sb1, _ = match_meta [] [] [term] [arg] in - let sb1 = List.sort Pervasives.compare - (List.filter (fun (v,_)->is_inst_var v) sb1) in - extend_sb sb1 sb, subst sb1 arg - ) playout_terms) in - let expand_rel atom (sb, acc) = - match atom with - | "true", [arg] -> - List.map (fun (sb,arg) -> sb, ("true",[arg])::acc) (expand sb arg) - | rel, args -> [sb, (rel, List.map (subst sb) args)::acc] in - let expand_neg sb (vs, neg_conj) = - let neg_conjs = - Aux.concat_foldr expand_rel neg_conj [sb, []] in - List.map (fun (sb, neg_conj) -> - let vs = List.filter (fun v -> not (List.mem_assoc v sb)) - (Aux.Strings.elements vs) in - Aux.strings_of_list vs, neg_conj - ) neg_conjs in - let brs = - Aux.concat_map (function ([head],body,neg_body) -> - Aux.concat_map (fun (sb,head) -> - let bodies = Aux.concat_foldr expand_rel body [sb, []] in - Aux.map_some (fun (sb, body) -> - let head = subst sb head in - let body = List.map (subst_rel sb) body in - let neg_body = - Aux.concat_map (expand_neg sb) neg_body in - if List.exists (function _, [] -> true | _ -> false) - neg_body then None - (* need to pack head into a list for [freshen_branch] *) - else Some (sb, ([head], body, neg_body))) bodies) - (if head = Const "_IGNORE_RHS_" then [[], head] - else expand [] head) - | _ -> assert false) brs in - (* {{{ log entry *) -if !debug_level > 4 then ( - Printf.printf "expand_branch_vars: substitutions=\n%s\n%!" - (String.concat ";; " (List.map (sb_str -| fst) brs)) -); -(* }}} *) - match freshen_unfixed with - | Aux.Left true -> - List.map (fun (sb, br) -> sb, freshen_branch br) brs - | _ -> brs - -(* (7l5)-related exception. *) -exception Failed_branch - -let translate_branches ?(conjunctive=false) struc masks playout_terms - static_rnames dyn_rels - (brs : exp_def_branch list) = - (* {{{ log entry *) - if !debug_level > 4 then ( - Printf.printf "Translating-branches:\n%s\n%!" - (exp_def_str ("translating", brs)); - ); - (* }}} *) - (* 7i *) - (* the state terms are positive, the relation can be positive or - negative -- negate atoms after generation if the atom was negative *) - let pos_conjs_4a pos_state_subterms (rel, args) = - let ptups = List.map (fun arg -> - Aux.assoc_all arg pos_state_subterms) args in - (* {{{ log entry *) - if !debug_level > 4 then ( - Printf.printf "pos_conjs_4a: of %s = subterms %s\n%!" - (fact_str (rel,args)) (String.concat "; " ( - List.map (fun l -> String.concat ", " - (List.map (fun (_,_,term)->term_str term) l)) ptups)) - ); - (* }}} *) - let ptups = Aux.product ptups in - let res = - List.map (fun ptup -> - let rname = rel ^ "__" ^ String.concat "__" - (List.map (fun (mask,v,_)-> - term_to_name mask ^ "_" ^ v) ptup) in - let tup = List.map (fun (_,_,term) -> - snd (toss_var masks term)) ptup in - Formula.Rel (rname, Array.of_list tup)) ptups in - let res = Aux.unique_sorted res in - (* {{{ log entry *) - if !debug_level > 4 then ( - Printf.printf "pos_conjs_4a: of %s = %s\n%!" - (fact_str (rel,args)) (Formula.str (Formula.And res)) - ); - (* }}} *) - res in - (* some of the state terms are always negative, the relation can be - positive or negative but always negate resulting atoms *) - let neg_conjs_4a pos_state_subterms - neg_state_terms neg_state_subterms (rel, args) = - let ptups = List.map (fun arg -> - Aux.assoc_all arg pos_state_subterms @ - Aux.assoc_all arg neg_state_subterms) args in - let ptups = Aux.product ptups in - let ptups = List.filter (fun tup -> - List.exists (fun (_,_,term) -> Terms.mem term neg_state_terms) tup) - ptups in - let res = - List.map (fun ptup -> - let rname = rel ^ "__" ^ String.concat "__" - (List.map (fun (mask,v,_)-> - term_to_name mask ^ "_" ^ v) ptup) in - let tup = List.map (fun (_,_,term) -> - snd (toss_var masks term)) ptup in - Formula.Rel (rname, Array.of_list tup)) ptups in - let res = Aux.unique_sorted res in - (* {{{ log entry *) - if !debug_level > 4 then ( - Printf.printf "neg_conjs_4a: of %s = %s\n%!" - (fact_str (rel,args)) (Formula.str (Formula.And res)) - ); - (* }}} *) - res in - (* 7i-4b *) - (* FIXME: abandon filtering-out rendundant mask variables during - translation -- this is the job of GameSimplify! *) - let constrained_vars = ref [] in - let pos_conjs_4b pos_path_subterms = - Aux.unique_sorted (Aux.concat_map (fun ((mask, v), terms) -> - let rname = "EQ___" ^ term_to_name mask ^ "_" ^ v in - let terms = Aux.collect terms in - Aux.concat_map (fun (_,terms) -> - let vars = Aux.unique_sorted - (List.map (fun t -> snd (toss_var masks t)) terms) in - constrained_vars := vars @ !constrained_vars; - let tups = - match !equivalences_all_tuples with - | Pairs_all -> - Aux.concat_map (fun v -> Aux.map_some (fun w -> - if v=w then None else Some [|v; w|]) vars) vars - | Pairs_triang -> - (* generating more relations to faciliate "contraction" of - co-occurring relations in GameSimpl -- since it - GameSimpl handles inversion, no need for bidirectional - links *) - triang_matrix vars - | Pairs_star -> - (* (4b) are equivalences, so we just build a "star" *) - match vars with [] -> [] - | v::vs -> List.map (fun w -> [|v; w|]) vs in - if !equivalences_ordered then - List.iter (Array.sort Pervasives.compare) tups; - List.map (fun tup -> Formula.Rel (rname, tup)) tups - ) terms - ) pos_path_subterms) in - let neg_conjs_4b pos_path_subterms nterm = - let nmask, nsb, _, _ = term_to_blank masks nterm in - let _,ntossvar = toss_var masks nterm in - Aux.concat_map (fun ((mask, v), terms) -> - if mask <> nmask then [] - else - let nval = - try List.assoc v nsb with Not_found -> assert false in - match nval with - | Var nval -> - let rname = "EQ___" ^ term_to_name mask ^ "_" ^ v in - let terms = - Aux.assoc_all nval terms in - let tossvars = Aux.unique_sorted - (List.map (fun t -> snd (toss_var masks t)) terms) in - (* these don't get constrained since they'll occur negatively *) - let tups = - match !equivalences_all_tuples with - | Pairs_all -> - Aux.concat_map - (fun v -> - if v = ntossvar then [] - else [[|v; ntossvar|]; [|ntossvar; v|]]) tossvars - | Pairs_triang | Pairs_star -> - Aux.map_some (fun v -> - if v = ntossvar then None - else Some [|v; ntossvar|]) tossvars in - if !equivalences_ordered then - List.iter (Array.sort Pervasives.compare) tups; - List.map (fun tup -> Formula.Rel (rname, tup)) tups - | _ -> [] - ) pos_path_subterms in - (* calculate state terms twice: before and after filtering branches *) - let pos_state_terms = - List.fold_left (fun acc -> function - | [next_arg], body, _ -> - let res = - List.fold_left (fun acc -> function - | "true", [true_arg] -> Terms.add true_arg acc - | "true", _ -> assert false - | _ -> acc) acc body in - if next_arg = Const "_IGNORE_RHS_" - then res - else Terms.add next_arg res - | _ -> assert false - ) Terms.empty brs in - let pos_state_terms = Terms.elements pos_state_terms in - (* {{{ log entry *) - if !debug_level > 4 then ( - Printf.printf "pos_state_terms: %s\n%!" - (String.concat ", " (List.map term_str pos_state_terms)) - ); - (* }}} *) - let pos_state_subterms = - Aux.concat_map (fun term -> - let mask, sb, m_sb, blanked = term_to_blank masks term in - List.map (fun (v,t) -> t, (mask, v, term)) sb - ) pos_state_terms in - let pos_path_subterms = - Aux.concat_map (fun term -> - let mask, sb, m_sb, blanked = term_to_blank masks term in - Aux.map_some (function - | v, Var t -> - Some ((mask, v), (t, term)) - | _ -> None) sb - ) pos_state_terms in - let pos_path_subterms = Aux.collect pos_path_subterms in - (* only compute the static part to filter-out inconsistent branches *) - let pconjs_4b = pos_conjs_4b pos_path_subterms in - let brs = Aux.map_some (function - | [next_arg],body,neg_body as br -> - let phi = - if next_arg = Const "_IGNORE_RHS_" then [] - else - let mask, sb, m_sb, blanked = term_to_blank masks next_arg in - let rname = term_to_name mask in - let _, svar = toss_var masks next_arg in - (* if List.mem svar !constrained_... [truncated message content] |
From: <luk...@us...> - 2011-07-09 12:37:40
|
Revision: 1508 http://toss.svn.sourceforge.net/toss/?rev=1508&view=rev Author: lukstafi Date: 2011-07-09 12:37:34 +0000 (Sat, 09 Jul 2011) Log Message: ----------- missing files in Reimplementation of GDL to Toss translation: untested work in progress. Added Paths: ----------- trunk/Toss/GGP/TranslateFormula.ml trunk/Toss/GGP/TranslateGame.ml Added: trunk/Toss/GGP/TranslateFormula.ml =================================================================== --- trunk/Toss/GGP/TranslateFormula.ml (rev 0) +++ trunk/Toss/GGP/TranslateFormula.ml 2011-07-09 12:37:34 UTC (rev 1508) @@ -0,0 +1,341 @@ +(** {2 Translating GDL definition: formulas.} *) + +open GDL + +let rel_atoms body = + let rec aux = function + | Pos (Rel (rel, args)) -> [rel, args] + | Neg (Rel (rel, args)) -> [rel, args] + | Disj ls -> Aux.concat_map aux ls + | _ -> [] in + Aux.concat_map aux body + + + +(* **************************************** *) +(* {3 Translate stable relations and fluents.} *) + +(* [separate_disj] is $\mathrm{TrDistr}$. Separate each disjunct, + splitting disjuncts if necessary, into "positive state terms", + "negative state terms" and "reminder". *) +let separate_disj disj = + let aux conj = + List.fold_right (fun lit acc -> match lit with + | (Pos (True _) | Neg (True _)) as lit -> + List.map (fun conj -> Left lit::conj) acc + | Disj ls as lit -> + if List.for_all (function Pos _ -> true | _ -> false) ls + || List.for_all (function Neg _ -> true | _ -> false) ls + then + List.map (fun conj -> Left lit::conj) acc + else + Aux.concat_map (function + | (Pos (True _) | Neg (True _)) as lit -> + List.map (fun conj -> Left lit::conj) acc + | lit -> List.map (fun conj -> Right lit::conj) acc + ) ls + | lit -> List.map (fun conj -> Right lit::conj) acc + ) conj [[]] in + let disj = Aux.concat_map aux disj in + List.map (fun conj -> + let state_terms, other = Aux.split_choice conj in + let pos_terms, neg_terms = + Aux.partition_map (function + | Pos _ as lit -> Left lit + | Neg _ as lit -> Right lit + | Disj ls as lit + when List.for_all (function Pos _ -> true | _ -> false) ls + -> Left lit + | Disj ls as lit + when List.for_all (function Neg _ -> true | _ -> false) ls + -> Right lit + | _ -> assert false + ) state_terms in + other, pos_terms, neg_terms) disj + +(* Whether $i$th argument is a $\mathrm{DefSide}$ or a + $\mathrm{CallSide}$, and the $p_{R,i}$ path for a relation $R$. *) +type defrel_arg_type = (bool * path) array + +type transl_data { + f_paths : path_set; (* fluent paths *) + m_paths : path_set; (* within-mask paths *) + all_paths : path_set; (* sum of f_paths and m_paths *) + mask_reps : term list; (* mask terms *) + defined_rels : string list; + defrel_arg_type : (string * defrel_arg_type) list ref; + (* late binding to store $ArgType# data *) + term_arities : (string * int) list; +} + +let blank_out data t = + simult_subst data.f_paths blank t + +let var_of_term data t = + Formula.fo_var_of_string (blank_out data t) + +let blank_outside_subterm data path subterm = + let arities = data.term_arities in + List.fold_right + (fun (rel, pos) acc -> + let subterms = Array.make (List.assoc rel arities) blank in + subterms.(pos) <- acc; + Func (rel, subterms)) + path subterm + +let var_of_subterm data path subt = + Formula.fo_var_of_string (blank_outside_subterm data path t) + +(* placeholder *) +let translate_defrel = + ref (fun data sterms_all sterms_in s_subterms sign rel args -> + assert false) + +let transl_rels data rels_phi sterms_all sterms_in = + let s_subterms = List.map + (fun sterm -> sterm, + map_paths (fun path subt -> subt, (sterm, path)) data.f_paths sterm) + sterms_all in + let s_subterms = List.filter + (fun (subt, _) -> subt <> blank) s_subterms in + let s_subterms = Aux.collect s_subterms in + let transl_rel sign rel args = + try + let stuples = + List.map (fun arg -> List.assoc arg s_subterms) args in + let stuples = Aux.product stuples in + let stuples = List.filter + (fun stup -> + List.exists (fun (sterm,_) -> List.mem sterm sterms_in) stup) + stuples in + let atoms = List.map + (fun stup -> + let vartup = List.map (fun (sterm,_) -> + var_of_term data sterm) stup in + let fact_rel = rel_on_paths rel (List.map snd stup) in + Formula.Rel (fact_rel, vartup)) stuples in + if sign then atoms + else List.map (fun a -> Formula.Not a) atoms + with Not_found -> [] in + let transl_defrel sign rel args = + if List.mem rel data.defined_rels + then + !translate_defrel data sterms_all sterms_in s_subterms sign rel args + else transl_rel false rel args in + let rec aux = function + | Pos (Rel (rel, args)) -> transl_defrel true rel args + | Neg (Rel (rel, args)) -> transl_defrel false rel args + | Pos (Does _ | Role _) | Neg (Does _ | Role _) -> + [] + | Disj lits -> + [Formula.Or (List.map (fun l -> [aux l]) lits)] + | _ -> assert false in (* FIXME: what about Distinct? *) + Formula.And (Aux.concat_map aux rels_phi) + +let transl_state data phi = + let transl_sterm sterm = + let s_subterms = + map_paths (fun path subt -> subt, path) data.all_paths sterm in + let s_subterms = List.filter + (fun (subt, _) -> subt <> blank) s_subterms in + let vartup = [|var_of_term data sterm|] in + let anchor_and_fluent_preds = + List.map (fun (subt, path) -> + Formula.Rel (pred_on_path_subterm path subt, vartup)) s_subterms in + let mask_preds = Aux.map_some + (fun mask -> + if mask = simult_subst data.all_paths blank sterm + then Some (Formula.Rel (term_to_name mask, vartup)) + else None) data.mask_reps in + Formula.And (anchor_and_fluent_preds @ mask_preds) in + let rec aux = function + | Pos (True sterm) -> transl_sterm sterm + | Neg (True sterm) -> assert false + | Pos (Does _ | Role _) | Neg (Does _ | Role _) -> + [] + | Disj lits -> + [Formula.Or (Aux.map_some (fun l -> + match aux l with + | [] -> None | [phi] -> phi + | conjs -> Formula.And conjs) lits)] + | _ -> assert false in (* FIXME: what about Distinct? *) + Formula.And (Aux.concat_map aux phi) + + +(* [translate_disjunct] is $\mathrm{Tr}(\Phi_i,E)$, [rels_phi] is + $G_i$, [pos_state_phi] is $ST^{+}_i$, [neg_state_phi] is + $ST^{-}_i$, [ext_phi] is $E$. *) +let transl_disjunct data rels_phi pos_state_phi neg_state_phi ext_phi = + let pos_terms = state_terms pos_state_phi in + let pos_vars = List.map (var_of_term data) pos_terms in + let neg_terms = state_terms pos_state_phi in + let neg_vars = List.map (var_of_term data) neg_terms in + let all_terms = pos_terms @ neg_terms in + let phi_vars = clause_vars + (("", []), + rels_phi @ pos_state_phi @ neg_state_phi) in + let eqs = + List.map (fun v -> Pos (Rel ("EQ_", [v; v]))) phi_vars in + let rels_eqs = rels_phi @ eqs in + let negated_neg_state_transl = + (* negation-normal-form of "not neg_state_phi" *) + Formula.Or ( + List.map (tranls_state data) (nnf_dnf neg_state_phi)) in + Formula.Ex (pos_vars, + Formula.And [ + ext_phi; + transl_rels data rels_eqs pos_terms pos_terms; + transl_state data pos_state_phi; + Formula.Not ( + Formula.Ex (neg_vars, + Formula.And [ + transl_rels data rels_eqs all_terms pos_terms; + negated_neg_state_transl]))]) + + + +(* Translate a disjunction of conjunctions of literals (and disjs of lits). *) +let translate data disj = + let disj = separate_disj disj in + Formula.Or (List.map (fun (rels_phi, pos_state, neg_state) -> + transl_disjunct data rels_phi pos_state neg_state (Formula.And []) + ) disj) + + +(* **************************************** *) +(* {3 Build and use defined relations.} *) + +let build_defrels data clauses = + let all_branches = Aux.concat_map + (fun ((rel,args),body) -> + List.map (fun phi -> rel, (args, phi)) separate_disj [body]) + clauses in + let build_defrel rel = + (* searching for ArgType = DefSide,S,p *) + let branches = Aux.assoc_all rel all_branches in + (* first find the paths, we will find the state terms later *) + let branch_paths = + List.map (fun (args, body) -> + let sterms = state_terms body + and args = Array.of_list args in + Array.map (fun arg -> + Aux.concat_map (fun sterm -> + term_paths (fun subt -> subt = arg) data.m_paths sterm + ) sterms) args + ) branches in + let p_defside = List.fold_left + (Aux.array_map2 Aux.list_inter) branch_sterms in + let p_defside = Array.map + (function path::_ -> Some path | [] -> None) p_defside in + (* now find the mapping $\calS_i$ for the DefSide result *) + let branch_sterms (args, phi) = + let sterms = state_terms phi in + Aux.array_map2 + (fun arg -> function None -> None + | Some path -> + Some (List.find (fun sterm -> + List.mem path + (term_paths (fun subt -> subt = arg) + data.m_paths sterm)) sterms)) + args p_defside in + let s_defside = List.map branch_sterms branches in + (* now computing the ArgType(R,i) = CallSide,p variant *) + let call_branches = Aux.concat_map + (fun (_,(_, phi)) -> + let calls = Aux.assoc_all rel (rel_atoms phi) in + List.map (fun args -> args, phi) calls + ) all_branches in + let callside_for_arg i = + let call_paths = Aux.concat_map + (fun (args, phi) -> + let sterms = state_terms phi and subt = args.(i) in + let paths = + term_paths (fun subt -> subt = arg) data.m_paths sterm in + List.map (fun p -> p, ()) paths + ) call_branches in + let call_paths = List.map + (fun (p, ns) -> List.length ns, p) + (Aux.collect call_paths) in + (* decreasing order *) + match List.sort (fun (x,_) (y,_) -> y-x) call_paths with + | [] -> None + | (_,p)::_ -> Some p in + let p_callside = Array.mapi + (fun i -> + function Some _ -> None | None -> callside_for_arg i) + p_defside in + let arg_paths = Array.map2 + (fun defside callside -> + match defside, callside with + | Some p, _ | None, Some p -> p + | None, None -> (* find a good path *) + failwith "GGP/TranslateFormula: finding path for defined relation argument undetermined by state terms not implemented yet") + p_defside p_callside in + (* now building the translation *) + let defvars = Array.mapi (fun i _ -> + Formula.fo_var_of_string ("v"^string_of_int i)) arg_paths in + let defbody (args,(rels_phi,pos_state,neg_state)) s_defside = + let arg_eqs = Array.mapi + (fun i v -> + let in_I = p_defside.(i) <> None in + if in_I + then Formula.Eq (v, s_defside.(i)) + else Formula.Eq (v, + var_of_subterm data arg_paths.(i) args.(i))) + defvars in + let arg_eqs = Formula.And (Array.to_list arg_eqs) in + let callside_sterms = + Aux.array_mapi_some + (fun i -> function None -> None + | Some path -> + Some (blank_outside_subterm data path args.(i))) + p_defside in + let callside_sterms = Array.to_list + (Array.map (fun sterm -> True sterm) callside_sterms) in + transl_disjunct data rels_phi + (callside_sterms @ pos_state) neg_state arg_eqs in + let def_disjuncts = List.map2 defbody branches s_defside in + let defrel_arg_type = Array.map2 + (fun defside path -> defside <> None, path) + p_defside arg_paths in + data.defrel_arg_type := + (rel, defrel_arg_type) :: !data.defrel_arg_type; + (rel, defvars), Formula.Or def_disjuncts in + List.map build_defrel data.defined_rels + +let transl_defrel data sterms_all sterms_in s_subterms sign rel args = + let arg_type = List.assoc rel !data.defrel_arg_type in + (* the $s \tpos_{p_{R,i}} = t_i$ state terms *) + let arg_sterms = Array.mapi + (fun i (defside, path) -> if defside then None else + try Some ( + List.find (fun s -> at_path path s = args.(i)) sterms_all) + with Not_found -> None) + arg_type in + let var_args = Array.mapi + (fun i (_, path) -> + match arg_sterms.(i) with + | None -> var_of_subterm data path arg (* in J *) + | Some sterm -> var_of_term data sterm) + arg_type in + let defrel_phi = Formula.Rel (rel, var_args) in + let defrel_phi = + if sign then defrel_phi else Formula.Not defrel_phi in + let ex_vars = Array.to_list + (Aux.array_mapi_some (fun i (_,path) -> + if arg_sterms.(i) = None + then Some (var_of_subterm data path args.(i)) + else None) arg_type) in + let in_J_eq_transl i (_,path) = + if arg_sterms.(i) = None + then + let eq_phi = [Pos (Rel ("EQ_", [args.(i); args.(i)]))] in + let v = blank_outside_subterm data path args.(i) in + Some (transl_rels data eq_phi (v::sterms_all) [v]) + else None in + let eqs_phi = Array.to_list + (Aux.array_mapi_some in_J_eq_transl arg_type) in + Formula.Ex (ex_vars, Formula.And (defrel_phi::eqs_phi)) + +let _ = translate_defrel := transl_defrel + Added: trunk/Toss/GGP/TranslateGame.ml =================================================================== --- trunk/Toss/GGP/TranslateGame.ml (rev 0) +++ trunk/Toss/GGP/TranslateGame.ml 2011-07-09 12:37:34 UTC (rev 1508) @@ -0,0 +1,476 @@ +(** {2 Translating GDL definition: Toss rules and initial structure.} + +*) + +open GDL + +(** Translate stable relations that otherwise would be translated as + structure relations, but have arity above the threshold, as + defined relations. *) +let defined_arity_above = ref 2 + +(** Treat "next" clauses which introduce a fluent position for a + variable-variable mismatch, as non-erasing frame clauses (to be + ignored). ("Wave" refers to the process of "propagating the frame + condition" that these clauses are assumed to do, if + [nonerasing_frame_wave] is set to [true].) *) +let nonerasing_frame_wave = ref true + +(** Limit on the number of steps for aggregate playout. *) +let agg_playout_horizon = ref 30 + +(** Use "true" atoms while computing rule cases. *) +let split_on_state_atoms = ref false + + +type tossrule_data = { + lead_legal : term; + (* the "legal"/"does" term of the player that performs the move, we + call its parameters "fixed variables" as they are provided externally *) + precond : Formula.formula; + (* the LHS match condition (the LHS structure and the precondition) *) + rhs_add : (string * string array) list; + (* the elements of LHS/RHS structures, corresponding to the "next" + terms *) + struc_elems : string list; + fixvar_elemvars : + (string * (term * (string * string list) list) list) list; + (* "state" terms indexed by variables that they contain, together + with the mask-path of the variable *) + elemvars : term Aux.StrMap.t; +(* "state" terms indexed by Toss variable names they generate *) +} + +(** Data to be used when translating moves. *) +type gdl_translation = { + (* map between structure elements and their term representations; + the reverse direction is by using element names *) + elem_term : term Aux.IntMap.t; + f_paths : paths; + m_paths : paths; + masks : term list; + tossrule_data : tossrule_data Aux.StrMap.t; + (* rule name to rule translation data *) +} + +(* [most_similar c ts] finds a term from [ts] most similar to [c], and + the set of paths that merges the found term and [c]; as in the + definition of $s_\calC$ and $t_\calC$ for a clause $\calC \in + \mathrm{Next}_{e}$. Among the most similar terms finds one that is + not a "frame wave", if not possible and if {!nonerasing_frame_wave} + is [true] -- raises [Not_found]. *) +let most_similar c ts = + let gens = List.map (fun t -> t, merge_terms c t) ts in + (* worse-or-equal as "leq" *) + let cmp (_, (_, pn1, siz1)) (_, (_, pn2, siz2)) = + not (siz1 > siz2) && pn2 >= pn1 in + let best = Aux.maximal cmp gens in + (* avoid "frame wave" if possible *) + let t, (ps, _, _) = + if !nonerasing_frame_wave + then + List.find (fun (t, (ps, _, _)) -> + c = t || + List.for_all + (fun fluent -> Aux.Strings.is_empty (term_vars fluent)) + (at_paths ps t)) best + else List.hd best in + t, ps + + + +(* Find $s_\calC$ and $t_\calC$ for a clause $\calC \in + \mathrm{Next}_{e}$, i.e. in expanded "next" clauses. Determine + which original clauses are frame clauses, and which have to + be dropped (under assumption of being "frame waves"). Return the + proper frame clauses, the non-frame clauses, and the fluent paths + (as in definition of $\calP_f$). *) +let fluent_paths_and_frames clauses = + let defs = + defs_of_rules (Aux.concat_map rules_of_clause clauses) in + let stable, nonstable = stable_rels defs in + let inline_defs = + List.filter (fun (rel,_) -> List.mem rel nonstable) defs in + (* To determine whether a clause is a frame, we need to know its + expansion, so we expand clauses separately. A proper frame clause + must have *all* expansions being proper frame clauses. But a + clause is dropped as "frame wave" if any of its expansions is + regarded as "frame wave". *) + let next_clauses = + List.filter (fun ((rel,_),_) -> rel="next") clauses in + let next_e = + List.map (fun c -> + c, expand_positive_lits inline_defs [c]) next_clauses in + let find_br_fluents s_C (_,body,neg_body) = + let p_ts = Aux.assoc_all "true" body in + let n_ts = Aux.assoc_all "true" neg_body in + let t_C, ps = most_similar t_C (p_ts @ n_ts) in + (* "negative true" check *) + t_C, ps, List.mem t_C p_ts in + let is_frame s_C (t_C, _, neg_true) = + not neg_true && s_C = t_C in + let find_fluents (c, c_e) = + let s_C = snd (fst c) in + let res = List.map (find_br_fluents s_C) c_e in + if List.for_all is_frame res + then Aux.Left c + else + let f_paths = + List.map (fun (t_C, ps, neg_true) -> + if neg_true + then + term_paths (function Const _ -> true | _ -> false) t_C + else ps) res in + Aux.Right (c, List.fold_left paths_union GDL.Empty f_paths) in + let res = Aux.map_try find_fluents next_e in + let frames, fluents = Aux.partition_choice res in + let move_clauses, f_paths = List.split fluents in + frames, move_clauses, + List.fold_left paths_union GDL.Empty f_paths + + +let rec contains_blank = function + | Const "_BLANK_" -> true + | Func args -> Aux.array_existsi (fun _ -> contains_blank) args + | _ -> false + + +(* Expand role variables, find fluent and mask paths, generate the + initial structure. *) +let create_init_struc clauses = + let players = + Aux.map_some (function + | ("role", [player]), _ -> Some player + | _ -> None + ) clauses in + let stable_rels, nonstable_rels, + stable_base, init_state, (agg_actions, agg_states) = + aggregate_playout players !agg_playout_horizon rules in + let frame_clauses, move_clauses, f_paths = + fluent_paths_and_frames clauses in + let next_clauses = + List.map (fun ((_,s_C),body_C) -> s_C, true, body_C) frame_clauses + @ List.map (fun ((_,s_C),body_C) -> s_C, false, body_C) + move_clauses in + let arities = + ("EQ_", 2):: + Aux.unique_sorted + (List.map (fun ((rel, args),_) -> rel, List.length args) + clauses) in + let element_terms = + List.fold_left (fun acc st -> Aux.unique_sorted (st @ acc)) [] + agg_states in + let element_reps = + Aux.unique_sorted (List.map (fun t -> + simult_subst f_paths blank t) element_terms) in + let m_paths = List.map + (term_paths ~prefix_only:true (neg contains_blank)) element_reps in + let m_paths = + List.fold_left paths_union GDL.Empty m_paths in + let mask_reps = + Aux.unique_sorted (List.map (fun t -> + simult_subst m_paths blank t) element_reps) in + let m_pathl = paths_to_list m_paths in + let f_pathl = paths_to_list f_paths in + (* adding subterm equality relations and fact relations *) + let struc_rels, defined_rels = + List.partition (fun rel -> + List.assoc rel arities <= !defined_arity_above) stable_rels in + let struc_rels = "EQ_"::struc_rels in + let defined_rels = defined_rels @ nonstable_rels in + let struc = + List.fold_left (fun struc rel -> + let arity = List.assoc rel arities in + let elem_tups = Aux.all_ntuples elem_reps arity in + let path_tups = Aux.all_ntuples m_pathl arity in + List.fold_left (fun ptup -> + let fact_rel = rel_on_paths rel ptup in + Aux.fold_left_try (fun etup -> + let tup = List.map2 at_path etup ptup in + if rel = "EQ_" && arity = 2 && + List.hd tup = List.hd (List.tl tup) + || List.mem (rel, tup) stable_base + then + Structure.add_rel_named_elems struc fact_rel + (Aux.array_map_of_list name_of_term tup) + else struc + ) struc elem_tups + ) struc path_tups + ) (Structure.empty ()) struc_rels in + (* adding anchor and fluent predicates *) + let add_pred struc paths elements = + List.fold_left (fun path -> + Aux.fold_left_try (fun elem -> + let pred = + pred_on_path_subterm path (at_path elem path) in + let tup = [|elem|] in + Structure.add_rel_named_elems struc pred + (Aux.array_map_of_list name_of_term tup) + ) struc elements + ) struc paths in + let struc = add_pred struc m_pathl element_reps in + let struc = add_pred struc f_pathl init_state in + (* adding mask predicates *) + let all_paths = paths_union m_paths f_paths in + let struc = + List.fold_left (fun struc m -> + let pred = term_to_name m in + List.fold_left (fun struc elem -> + if simult_subst all_paths blank elem = m + then + Structure.add_rel_named_elems struc pred + [|name_of_term elem|] + else struc + ) struc element_reps + ) struc maks_reps in + next_clauses, f_paths, m_paths, mask_rels, defined_rels, + stable_base, init_state, struc + + +(* Find the rule clauses $\ol{\calC},\ol{\calN}$. *) +let move_tuples used_vars next_cls legal_tuples = + (* computing the $d_i(\calN)$ for each $\calN$ *) + let fresh_x_f () = + let x_f = Aux.not_conflicting_name !used_vars "x_f" in + used_vars := Aux.Strings.add x_f !used_vars; + x_f in + let does_facts (_,body as cl) = + List.fold_right (fun p (sb, dis) -> + let djs = + Aux.map_some (function + | Does (dp, d) when dp = p -> Some d + | _ -> None) body in + let sb = unify_all sb djs in + let d = + match djs with + | [] -> fresh_x_f () + | d::_ -> subst sb d in + sb, d::dis + ) players ([], []) in + let next_cls = + Aux.map_try (fun cl -> + let sb, ds = does_facts cl in + subst_clause sb cl, ds) next_cls in + (* selecting $\ol{\calC},\ol{\calN}$ clauses with + $\sigma_{\ol{\calC},\ol{\calN}}$ applied *) + let tup_unifies ts1 ts2 = + try unify [] ts1 ts2; true + with Not_found -> false in + let move_clauses cs = + (* bag of next clauses for each legal tuple *) + let next_clauses = + List.filter (fun (n_cl, ds) -> tup_unifies cs ds) next_cls in + (* two passes to ensure coverage and maximality *) + let rec coverage = function + | (n_cl, ds)::more_cls as all_cls + , ((sb, tup_ds, n_cls)::other_cl_tups as all_cl_tups) -> + (try + let sb, tup_ds = List.fold_right + (fun (di, acc_di) (sb, tup_ds) -> + let sb = unify sb [di] [acc_di] in + sb, subst sb di::tup_ds + ) (List.combine ds tup_ds) (sb, []) in + coverage (more_cls, (sb, tup_ds, n_cl::n_cls)::other_cl_tups) + with Not_found -> + (* start a new tuple *) + coverage (all_cls, ([], cs, [])::all_cl_tups) + ) + | [], all_cl_tups -> all_cl_tups + | _, [] -> assert false in + let cl_tups = + coverage (next_clauses, [[], cs, []]) in + let maximality cl_tup = + List.fold_left (fun (sb, tup_ds, n_cls as cl_tup) (n_cl, ds) -> + if List.mem n_cl n_cls then cl_tup + else + try + let sb, tup_ds = List.fold_right + (fun (di, acc_di) (sb, tup_ds) -> + let sb = unify sb [di] [acc_di] in + sb, subst sb di::tup_ds + ) (List.combine ds tup_ds) (sb, []) in + (sb, tup_ds, n_cl::n_cls) + with Not_found -> cl_tup + ) cl_tup next_clauses in + List.map maximality cl_tups in + Aux.concat_map move_clauses legal_tuples + + +let add_erasure_clauses (legal_tup, next_cls) = + let fixed_vars = terms_vars legal_tup in + let frame_cls = + Aux.map_some (fun (s, frame, body) -> + if frame then Some (s, body) else None) next_cls in + (* two passes to ensure coverage and maximality *) + (* FIXME-TODO: treat fixed-vars as consts, by substituting them with + Const, and later substituting-back Var *) + let rec coverage = function + | (s, body)::more_cls + , ((sb, s_acc, bodies)::other_frames as all_frames) -> + (try + let sb = unify sb [s] [s_acc] in + let s_acc = subst sb s in + coverage (more_cls, (sb, s_acc, body::bodies)::other_frames) + with Not_found -> + (* start a new frame *) + coverage (more_cls, ([], s, [body])::all_frames) + ) + | [], all_frames -> all_frames + | (s, body)::more_cls, [] -> + coverage (more_cls, [[], s, [body]]) in + let frames = coverage (frame_cls, []) in + let maximality frame = + List.fold_left (fun (sb, s_acc, bodies as frame) (s, body) -> + if List.mem body bodies then frame + else + try + let sb = unify sb [s] [s_acc] in + let s_acc = subst sb s in + (sb, s_acc, body::bodies) + with Not_found -> frame + ) frame frame_cls in + let frames = List.map maximality frames in + let frames = + List.map (fun (sb, s, bodies) -> + s, List.map (subst_rels sb) bodies) in + let erasure_cls = + Aux.concat_map (fun (s, bodies) -> + let nbodies = negate_bodies bodies in + List.map (fun b -> s, b) nbodies + ) frames in + let next_cls = + Aux.map_some (fun (s, frame, body) -> + if not frame then Some (s, body) else None) next_cls in + legal_tup, next_cls @ erasure_cls + + +(* Assign rule clauses to rule cases, i.e. candidates for Toss + rules. Collect the conditions and RHS state terms together. *) +let rule_cases (legal_tup, next_cls) = + let atoms = Aux.concat_map + (fun (_, body) -> Aux.map_some (function + | Pos (Rel _ as a) | Neg (Rel _ as a) -> Some a + | (Pos (True _ as a) | Neg (True _ as a)) + when !split_on_state_atoms -> Some a + | _ -> None) body) next_cls in + let patterns = + let next_cls = Array.of_list next_cls in + List.map (fun a -> + Array.map (fun i (_, body) -> + if List.mem (Neg a) body then -1 + else if List.mem (Pos a) body then 1 + else 0 + ) next_cls, + a) atoms in + let patterns = Aux.collect patterns in + let patterns = List.filter (fun (pat, _) -> + Array.exists (fun v-> v < 1) pat && + Array.exists (fun v-> v > -1) pat) patterns in + let pos_choice = List.map (fun _ -> true) patterns in + let neg_choice = List.map (fun _ -> false) patterns in + let choices = Aux.product [pos_choice; neg_choice] in + let rule_case choice = + let separation_cond = + List.concat + (List.map2 (fun b (_, atoms) -> + if b then List.map (fun a -> Pos a) atoms + else List.map (fun a -> Neg a) atoms) choice patterns) in + let case_cls = + List.filter (fun (_, body) -> + List.for_all2 (fun b (_, atoms) -> + if b then (* atoms not excluded *) + List.for_all (fun a -> not (List.mem (Neg a) body)) atoms + else (* atoms not included *) + List.for_all (fun a -> not (List.mem (Pos a) body)) atoms + ) choice patterns + ) next_cls in + let case_rhs, case_conds = List.split case_cls in + case_rhs, separation_cond @ case_conds in + List.map (fun choice -> + let case_rhs, case_conds = rule_case choice in + let case_conds = case_conds @ + Aux.concat_map snd legal_tup in + case_rhs, case_conds) choices + + +(* The candidates need to be filtered before finishing the + translation of Toss rules. *) +let create_rule_cands used_vars next_cls clauses = + let players = (* Array.of_list *) + Aux.map_some (function + | ("role", [player]), _ -> Some player + | _ -> None + ) clauses in + let legal_cls = + List.filter (fun ((rel,_),_) -> rel="legal") clauses in + (* let next_cls = + List.filter (fun ((rel,_),_) -> rel="next") clauses in *) + (* constructing $(\calC_1,...,\calC_n)$ tuples *) + let legal_by_player = + List.map (fun p -> + Aux.map_some (function + | ("legal",[lp; l]), body when lp = p -> Some (l, body) + | _ -> None) legal_cls + ) players in + let legal_tuples = Aux.product legal_by_player in + let move_tups = move_tuples used_vars next_cls legal_tuples in + let move_tups = + List.map (fun (sb, legal_tup, n_cls) -> + List.map (subst sb) legal_tup, + List.map (subst_clause sb) n_cls) move_tups in + let move_tups = List.map add_erasure_clauses move_tups in + Aux.concat_map rule_cases move_tups + + +let filter_rule_cands stable_base defined_rels rule_cands = + let check_atom = function + | Pos (Rel (rel, _ as a)) -> + List.mem rel defined_rels || + List.exists (rels_unify a) stable_base + | Neg (Rel (rel, _ as a)) -> + List.mem rel defined_rels || + not (List.exists (rels_unify a) stable_base) + | _ -> true in + List.filter (fun (case_rhs, case_conds) -> + List.for_all check_atom case_conds + ) rule_cands + + +let translate_game clauses = + let clauses = expand_players clauses in + let used_vars, clauses = rename_clauses clauses in + let next_cls, f_paths, m_paths, mask_rels, defined_rels, + stable_base, init_state, struc = create_init_struc clauses in + let rule_cands = create_rule_cands used_vars next_cls clauses in + let rule_cands = filter_rule_cands stable_base rule_cands in + let all_state_terms = + Aux.concat_map state_terms (List.map snd clauses) in + let term_arities = Aux.unique_sorted + (Aux.concat_map term_arities all_state_terms) in + + + +(* ************************************************************ *) +(* ************************************************************ *) +(** {3 Translating Moves.} *) + + +let initialize_game player game_descr startcl = + let gdl_transl, state = translate_game player game_descr in + state, None, gdl_transl + + +let translate_last_action gdl_translation state actions = + if actions = [] then (* start of game -- Server will not perform a move *) + "", [] + else translate_incoming_move gdl_translation state actions + + +let translate_move gdl_translation new_state rule emb = + let res = translate_outgoing_move gdl_translation new_state rule emb in + (* {{{ log entry *) + if !debug_level > 0 then ( + Printf.printf "GDL.translate_move: %s\n%!" res + ); + (* }}} *) + res This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-09 10:28:24
|
Revision: 1507 http://toss.svn.sourceforge.net/toss/?rev=1507&view=rev Author: lukstafi Date: 2011-07-09 10:28:17 +0000 (Sat, 09 Jul 2011) Log Message: ----------- Reimplementation of GDL to Toss translation: untested work in progress. Modified Paths: -------------- trunk/Toss/Formula/Aux.ml trunk/Toss/Formula/Aux.mli trunk/Toss/Formula/AuxTest.ml trunk/Toss/GGP/GDL.ml trunk/Toss/GGP/GDL.mli trunk/Toss/GGP/GDLParser.mly trunk/Toss/GGP/Translate.ml trunk/Toss/Solver/Structure.ml trunk/Toss/Solver/Structure.mli trunk/Toss/www/reference/reference.tex Modified: trunk/Toss/Formula/Aux.ml =================================================================== --- trunk/Toss/Formula/Aux.ml 2011-07-06 22:13:35 UTC (rev 1506) +++ trunk/Toss/Formula/Aux.ml 2011-07-09 10:28:17 UTC (rev 1507) @@ -204,10 +204,14 @@ | hd::tl -> List.rev_append (List.map (fun e-> hd, e) tl) (pairs tl) -let all_tuples_for args elems = - List.fold_left (fun tups _ -> +let rec fold_n f accu n = + if n <= 0 then accu + else fold_n f (f accu) (n-1) + +let all_ntuples elems arity = + fold_n (fun tups -> concat_map (fun e -> (List.map (fun tup -> e::tup) tups)) - elems) [[]] args + elems) [[]] arity let rec remove_one e = function | hd::tl when hd = e -> tl @@ -486,11 +490,7 @@ | hd::tl -> aux (List.map (fun e->[e]) hd) tl -let rec fold_n f accu n = - if n <= 0 then accu - else fold_n f (f accu) (n-1) - (* Character classes. *) let is_uppercase c = c >= 'A' && c <= 'Z' let is_lowercase c = c >= 'a' && c <= 'z' Modified: trunk/Toss/Formula/Aux.mli =================================================================== --- trunk/Toss/Formula/Aux.mli 2011-07-06 22:13:35 UTC (rev 1506) +++ trunk/Toss/Formula/Aux.mli 2011-07-09 10:28:17 UTC (rev 1507) @@ -132,9 +132,8 @@ elements from the list. *) val pairs : 'a list -> ('a * 'a) list -(** An [n]th cartesian power of the second list, where [n] is the - length of the first list. Tail recursive. *) -val all_tuples_for : 'a list -> 'b list -> 'b list list +(** An [n]th cartesian power of the list. Tail recursive. *) +val all_ntuples : 'a list -> int -> 'a list list (** Remove an occurrence of a value (uses structural equality). *) val remove_one : 'a -> 'a list -> 'a list Modified: trunk/Toss/Formula/AuxTest.ml =================================================================== --- trunk/Toss/Formula/AuxTest.ml 2011-07-06 22:13:35 UTC (rev 1506) +++ trunk/Toss/Formula/AuxTest.ml 2011-07-09 10:28:17 UTC (rev 1507) @@ -140,7 +140,7 @@ (Aux.map_try f [`A;`B;`C;`D]); ); - "product, all_tuples_for, concat_foldr" >:: + "product, all_ntuples, concat_foldr" >:: (fun () -> let print_llist l = String.concat "; " (List.map (String.concat ", ") l) in @@ -154,11 +154,11 @@ assert_equal ~printer:print_llist [["a"; "a"]; ["a"; "b"]; ["a"; "c"]; ["b"; "a"]; ["b"; "b"]; ["b"; "c"]; ["c"; "a"]; ["c"; "b"]; ["c"; "c"]] - (Aux.all_tuples_for [();()] ["a";"b";"c"]); + (Aux.all_ntuples ["a";"b";"c"] 2); assert_equal ~printer:print_llist [["a"; "a"; "a"]; ["a"; "a"; "b"]; ["a"; "b"; "a"]; ["a"; "b"; "b"]; ["b"; "a"; "a"]; ["b"; "a"; "b"]; ["b"; "b"; "a"]; ["b"; "b"; "b"]] - (Aux.all_tuples_for [();(); ()] ["a";"b"]); + (Aux.all_ntuples ["a";"b"] 3); assert_equal ~printer:print_llist [["a1"; "b"; "c"; "a1"; "d"]; ["a2"; "b"; "c"; "a1"; "d"]; Modified: trunk/Toss/GGP/GDL.ml =================================================================== --- trunk/Toss/GGP/GDL.ml 2011-07-06 22:13:35 UTC (rev 1506) +++ trunk/Toss/GGP/GDL.ml 2011-07-09 10:28:17 UTC (rev 1507) @@ -1,33 +1,40 @@ (** {2 Game Description Language.} - Type definitions, helper functions, game specification. *) + Type definitions, operations on terms, saturation (i.e. Herbrand + model), clause inlining. *) + +(* ************************************************************ *) +(* ************************************************************ *) +(** {3 Datalog programs: Type definitions and saturation.} *) + open Aux.BasicOperators let debug_level = ref 0 let aggregate_drop_negative = ref false let aggregate_fixpoint = ref true -(** Expand static relations that do not have ground facts, are not - directly recursive, and have arity above the threshold. *) -let expand_arity_above = ref 0 - -(** Treat "next" clauses which introduce metavariables only for - variable-variable mismatch, as non-erasing frame clauses (to be - ignored). ("Wave" refers to the process of "propagating the frame - condition" that these clauses are assumed to do, if - [nonerasing_frame_wave] is set to [true].) *) -let nonerasing_frame_wave = ref true - type term = | Const of string | Var of string - | MVar of string (* meta-variable, not used in GDL *) - | Func of string * term list + | Func of string * term array +type rel_atom = string * term list +(** Positive and negative literals separated, disjunctions expanded-out. *) +type gdl_rule = rel_atom * rel_atom list * rel_atom list +(** Collect rules by relations. *) +type def_branch = term list * rel_atom list * rel_atom list +type gdl_defs = (string * def_branch list) list + +module Terms = Set.Make ( + struct type t = term let compare = Pervasives.compare end) +module Atoms = Set.Make ( + struct type t = rel_atom let compare = Pervasives.compare end) + type atom = | Distinct of term list - | Rel of string * term list - | Currently of term + | Rel of rel_atom + | Role of term + | True of term | Does of term * term type literal = @@ -35,51 +42,34 @@ | Neg of atom | Disj of literal list -type game_descr_entry = - | Datalog of string * term list * literal list - | Next of term * literal list - | Legal of term * term * literal list - | Goal of term * int * literal list - | GoalPattern of term * string * literal list - | Terminal of literal list - | Role of term - | Initial of term * literal list - | Atomic of string * term list +type clause = rel_atom * literal list type request = - | Start of string * term * game_descr_entry list * int * int - (* prepare game: match id, role, game, startclock, playclock *) + | Start of string * term * clause list * int * int + (** prepare game: match id, role, game, startclock, playclock *) | Play of string * term list - (* request a move: match id, actions on previous step *) + (** request a move: match id, actions on previous step *) | Stop of string * term list - (* game ends here: match id, actions on previous step *) + (** game ends here: match id, actions on previous step *) let rec term_str = function | Const c -> c | Var v -> "?"^v - | MVar v -> "@"^v | Func (f, args) -> "(" ^ f ^ " " ^ String.concat " " (List.map term_str args) ^ ")" let rec term_to_name ?(nested=false) = function | Const c -> c | Var v -> v - | MVar v -> v | Func (f, args) -> f ^ "_" ^ (if nested then "_S_" else "") ^ String.concat "_" (List.map (term_to_name ~nested:true) args) ^ (if nested then "_Z_" else "") -let rec vars ?(meta=false) = function - | Const _ -> [] - | Var x -> [x] - | MVar x -> if meta then [x] else [] - | Func (_, args) -> Aux.concat_map vars args - let rec term_vars = function | Const _ -> Aux.Strings.empty - | Var v | MVar v -> Aux.Strings.singleton v + | Var v -> Aux.Strings.singleton v | Func (f, args) -> terms_vars args and terms_vars args = @@ -87,166 +77,79 @@ (List.map term_vars args) -let fact_of_atom = function - | Distinct args -> assert false +let rel_of_atom = function + | Distinct args -> "distinct", args (* not a proper relation -- avoid *) | Rel (rel, args) -> rel, args - | Currently arg -> "true", [arg] + | Role arg -> "role", [arg] + | True arg -> "true", [arg] | Does (arg1, arg2) -> "does", [arg1; arg2] +let atom_of_rel = function + | "distinct", args -> Distinct args (* not a proper relation -- avoid *) + | "role", [arg] -> Role arg + | "true", [arg] -> True arg + | "does", [arg1; arg2] -> Does (arg1, arg2) + | rel, args -> Rel (rel, args) + let rec body_of_literal = function | Pos (Distinct args) -> [Aux.Right ("distinct", args)] (* not negated actually! *) | Neg (Distinct _) -> assert false - | Pos atom -> [Aux.Left (fact_of_atom atom)] - | Neg atom -> [Aux.Right (fact_of_atom atom)] + | Pos atom -> [Aux.Left (rel_of_atom atom)] + | Neg atom -> [Aux.Right (rel_of_atom atom)] | Disj disjs -> Aux.concat_map body_of_literal disjs let func_graph f terms = Aux.map_some (function Func (g, args) when f=g -> Some args | _-> None) terms -(* Type shortcuts (mostly for documentation). *) -type gdl_atom = string * term list -type gdl_rule = gdl_atom * gdl_atom list * gdl_atom list -(* Definition with collected relation branches and negation-local - variables found. *) -type lit_def_branch = - term list * gdl_atom list * (Aux.Strings.t * gdl_atom) list -type lit_def = string * lit_def_branch list -(* Definition with expanded definitions: expansion of a negated - relation brings negated (possibly locally existentially quantified) - conjunctions. *) -type exp_def_branch = - term list * gdl_atom list * (Aux.Strings.t * gdl_atom list) list -type exp_def = string * exp_def_branch list -module Terms = Set.Make ( - struct type t = term let compare = Pervasives.compare end) -module Atoms = Set.Make ( - struct type t = string * term list let compare = Pervasives.compare end) - - -let lit_def_br_vars (head, body, neg_body : lit_def_branch) = +let gdl_rule_vars (head, body, neg_body) = List.fold_left Aux.Strings.union Aux.Strings.empty (List.map terms_vars - (head::List.map snd body @ - List.map (snd -| snd) neg_body)) + (head::List.map snd (body @ neg_body))) -let exp_def_br_vars (head, body, neg_body : exp_def_branch) = +let gdl_rules_vars brs = List.fold_left Aux.Strings.union Aux.Strings.empty - (List.map terms_vars - (head::List.map snd body @ - Aux.concat_map (List.map snd -| snd) neg_body)) + (List.map gdl_rule_vars brs) -let lit_def_brs_vars brs = +let rels_vars body = List.fold_left Aux.Strings.union Aux.Strings.empty - (List.map lit_def_br_vars brs) + (List.map (fun (_,args)->terms_vars args) body) -let exp_def_brs_vars brs = - List.fold_left Aux.Strings.union Aux.Strings.empty - (List.map exp_def_br_vars brs) +let gdl_defs_vars defs = + List.fold_left + (fun acc rels -> Aux.Strings.union acc (rels_vars rels)) + Aux.Strings.empty + (Aux.concat_map (fun (hd,body,neg_body) -> + ("",hd)::body @ neg_body) (Aux.concat_map snd defs)) -let sdef_br_vars (head, body, neg_body) = - exp_def_br_vars ([head], body, neg_body) +let rules_of_clause (head, body) = + let body, neg_body = + Aux.partition_choice (Aux.concat_map body_of_literal body) in + head, body, neg_body -let sdef_brs_vars brs = - List.fold_left Aux.Strings.union Aux.Strings.empty - (List.map sdef_br_vars brs) -let rels_vars body = - List.fold_left Aux.Strings.union Aux.Strings.empty - (List.map (fun (_,args)->terms_vars args) body) +let clause_vars cl = gdl_rule_vars (rules_of_clause cl) -let rules_of_entry = function - | Datalog (rel, args, body) -> - let head = rel, args in - let bodies = Aux.product (List.map body_of_literal body) in - List.map (fun body -> - let pos_body, neg_body = Aux.partition_choice body in - head, pos_body, neg_body) bodies - | Next (head, body) -> - let head = "next", [head] in - let bodies = Aux.product (List.map body_of_literal body) in - List.map (fun body -> - let pos_body, neg_body = Aux.partition_choice body in - head, pos_body, neg_body) bodies - | Legal (arg1, arg2, body) -> - let head = "legal", [arg1; arg2] in - let bodies = Aux.product (List.map body_of_literal body) in - List.map (fun body -> - let pos_body, neg_body = Aux.partition_choice body in - head, pos_body, neg_body) bodies - | Goal (arg, payoff, body) -> - let head = "goal", [arg; Const (string_of_int payoff)] in - let bodies = Aux.product (List.map body_of_literal body) in - List.map (fun body -> - let pos_body, neg_body = Aux.partition_choice body in - head, pos_body, neg_body) bodies - | GoalPattern (arg, var, body) -> - let head = "goal", [arg; Var var] in - let bodies = Aux.product (List.map body_of_literal body) in - List.map (fun body -> - let pos_body, neg_body = Aux.partition_choice body in - head, pos_body, neg_body) bodies - | Terminal body -> - let head = "terminal", [] in - let bodies = Aux.product (List.map body_of_literal body) in - List.map (fun body -> - let pos_body, neg_body = Aux.partition_choice body in - head, pos_body, neg_body) bodies - | Role arg -> [("role", [arg]), [], []] - | Initial (arg, body) -> - let head = "init", [arg] in - let bodies = Aux.product (List.map body_of_literal body) in - List.map (fun body -> - let pos_body, neg_body = Aux.partition_choice body in - head, pos_body, neg_body) bodies - | Atomic (rel, args) -> [(rel, args), [], []] +let defs_of_rules rules = + Aux.map_reduce (fun ((rel, args), body, neg_body) -> + rel, (args, body, neg_body)) (fun y x->x::y) [] rules -let add_neg_body_vars global_vars neg_body : (Aux.Strings.t * gdl_atom) list = - List.map (fun (_, args as a)-> - let local_vs = Aux.Strings.diff (terms_vars args) global_vars in - local_vs, a) neg_body - -let lit_defs_of_rules rules : (string * lit_def_branch list) list = - Aux.map_reduce - (fun ((drel, params), body, neg_body) -> - let global_vs = - Aux.Strings.union (terms_vars params) (rels_vars body) in - drel,(params, body, - add_neg_body_vars global_vs neg_body)) - (fun x y->y::x) [] rules - -let rules_of_lit_defs (defs : lit_def list) = +let rules_of_defs defs = Aux.concat_map (fun (rel, branches) -> List.map (fun (args, body, neg_body) -> - let neg_body = - List.map snd neg_body in (rel, args), body, neg_body) branches) defs -let exp_brs_of_lit_brs brs = - List.map (fun (args, body, neg_body) -> - let neg_body = - List.map (fun (vs,a) -> vs,[a]) neg_body in - args, body, neg_body) brs - -let exp_defs_of_lit_defs defs : exp_def list = - List.map (fun (rel, branches) -> - rel, exp_brs_of_lit_brs branches) defs - - -(* Stratify either w.r.t. the dependency graph ([~def:true]) or its - subgraph the negation graph ([~def:false]). *) -let rec stratify ?(def=false) strata (defs : lit_def list) = +(* Stratify w.r.t. the negation call-graph. *) +let rec stratify strata defs = match List.partition (fun (_, branches) -> - List.for_all (fun (_, body, neg_body) -> - let neg_body = List.map snd neg_body in + List.for_all (fun (_, _, neg_body) -> List.for_all (fun (rel1,_) -> rel1 = "distinct" || rel1 = "true" || rel1 = "does" || - not (List.mem_assoc rel1 defs)) - (if def then body @ neg_body - else neg_body)) branches) defs + not (List.mem_assoc rel1 defs)) neg_body) + branches) defs with | [], [] -> (* {{{ log entry *) @@ -269,28 +172,22 @@ (* }}} *) List.rev (stratum::strata) | [], _ -> - if def then raise + raise (Lexer.Parsing_error - "GDL.stratify: recursive non-static definitions not handled yet") - else raise - (Lexer.Parsing_error "GDL.stratify: cyclic negation dependency") | stratum, rules -> - if not def then let stratum, more_rules = List.partition (fun (_, branches) -> List.for_all (fun (_, body, neg_body) -> List.for_all (fun (rel1,_) -> rel1 = "distinct" || rel1 = "true" || rel1 = "does" || not (List.mem_assoc rel1 rules)) body) branches) stratum in - stratify ~def (stratum::strata) (more_rules @ rules) - else stratify ~def (stratum::strata) rules + stratify (stratum::strata) (more_rules @ rules) let rec subst_one (x, term as sb) = function | Var y when x=y -> term - | MVar y when x=y -> term - | (Const _ | Var _ | MVar _ as t) -> t + | (Const _ | Var _ as t) -> t | Func (f, args) -> Func (f, List.map (subst_one sb) args) @@ -321,73 +218,9 @@ | _ -> raise Not_found -(* Match the first argument as term against the second argument as - pattern. Allow nonlinear (object) variables. *) -let rec match_meta ?(ignore_meta=false) sb m_sb terms1 terms2 = - match terms1, terms2 with - | [], [] -> sb, m_sb - | (Const _ (* | Var _ *) as a)::terms1, - (Const _ (* | Var _ *) as b)::terms2 - when a=b -> match_meta ~ignore_meta sb m_sb terms1 terms2 - | Func (f,args1)::terms1, Func (g,args2)::terms2 when f=g -> - match_meta ~ignore_meta sb m_sb (args1 @ terms1) (args2 @ terms2) - | term::terms1, MVar x::terms2 -> - (* we don't substitute because metavariables are linear *) - match_meta ~ignore_meta sb ((x, term)::m_sb) terms1 terms2 - | MVar _::terms1, _::terms2 -> - if ignore_meta then match_meta ~ignore_meta sb m_sb terms1 terms2 - else raise Not_found - | term::terms1, Var x::terms2 -> - let sb1 = x, term in - let sb = - if List.mem_assoc x sb then - if List.assoc x sb = term then sb - else raise Not_found - else sb1::sb in - match_meta ~ignore_meta sb m_sb terms1 terms2 - | _ -> - (* {{{ log entry *) - if !debug_level > 4 then ( - Printf.printf "match_meta: unmatched (%s) against pattern (%s)\n%!" - (String.concat ", " (List.map term_str terms1)) - (String.concat ", " (List.map term_str terms2)) - ); - (* }}} *) - raise Not_found - - -let generalize term1 term2 = - let fresh_count = ref 0 in - let rec loop pf terms1 terms2 = - match terms1, terms2 with - | [], [] -> (0, 0), [], [] - | (Const a as cst)::terms1, Const b::terms2 when a=b -> - let (good_vars, good_csts), mism, gens = loop pf terms1 terms2 in - (good_vars, good_csts+1), mism, cst::gens - | Func (f,args1)::terms1, Func (g,args2)::terms2 when f=g -> - let (good_vars1, good_csts1), mism1, gen_args = loop f args1 args2 in - let (good_vars2, good_csts2), mism2, gens = loop pf terms1 terms2 in - (good_vars1+good_vars2, good_csts1+good_csts2), mism1 @ mism2, - (Func (f,gen_args))::gens - | (Var x as var)::terms1, Var y::terms2 when x=y -> - let (good_vars, good_csts), mism, gens = loop pf terms1 terms2 in - (good_vars+1, good_csts), mism, var::gens - | t1::terms1, t2::terms2 -> - let measure, mism, gens = loop pf terms1 terms2 in - incr fresh_count; - measure, (t1,t2)::mism, MVar ("MV"^string_of_int !fresh_count)::gens - | _::_, [] | [], _::_ -> raise - (Lexer.Parsing_error - ("GDL.generalize: arity mismatch at function "^pf)) in - let measure, mism, gens = loop "impossible" [term1] [term2] in - measure, !fresh_count, mism, List.hd gens - - let rec subst sb = function | Var y as t -> (try List.assoc y sb with Not_found -> t) - | MVar y as t -> - (try List.assoc y sb with Not_found -> t) | Const _ as t -> t | Func (f, args) -> Func (f, List.map (subst sb) args) @@ -409,6 +242,10 @@ if rel1 = rel2 then unify [] args1 args2 else raise Not_found +let rels_unify atom1 atom2 = + try ignore (unify_rels atom1 atom2); true + with Not_found -> false + let subst_rel sb (rel, args) = rel, List.map (subst sb) args let subst_rels sb body = List.map (subst_rel sb) body @@ -418,12 +255,28 @@ let var_terms = List.map (fun v->Var v) (vars1 @ vars2) in unify [] var_terms (terms1 @ terms2) -let subst_br sb (head, body, neg_body) = - List.map (subst sb) head, +let subst_br sb (args, body, neg_body) = + List.map (subst sb) args, subst_rels sb body, List.map (fun (uni_vs,neg) -> uni_vs, subst_rels sb neg) neg_body -let fact_str (rel, args) = + +let subst_atom sb = function + | Distinct args -> Distinct (List.map (subst sb) args) + | Rel rel_atom -> Rel (subst_rel sb rel_atom) + | Role arg -> Role (subst sb arg) + | True arg -> True (subst sb arg) + | Does (arg1, arg2) -> Does (subst sb arg1, subst sb arg2) + +let rec subst_literal sb = function + | Pos atom -> Pos (subst_atom sb atom) + | Neg atom -> Neg (subst_atom sb atom) + | Disj disjs -> Disj (List.map (subst_literal sb) disjs) + +let subst_clause sb (head, body) = + subst_rel sb head, List.map (subst_literal sb) body + +let rel_atom_str (rel, args) = "(" ^ rel ^ " " ^ String.concat " " (List.map term_str args) ^ ")" let tuples_str tups = @@ -434,40 +287,22 @@ let terms_str facts = String.concat ", " (List.map term_str facts) -let facts_str facts = String.concat " " (List.map fact_str facts) +let rel_atoms_str body = String.concat " " (List.map rel_atom_str body) -let neg_lfacts_str negs = +let neg_rel_atoms_str neg_body = String.concat " " - (List.map (fun (vs,d) -> - let vs = Aux.Strings.elements vs in - let q = if vs = [] then "" - else "forall "^String.concat ", " vs in - q ^ "(not "^fact_str d^")") negs) + (List.map (fun a -> "(not " ^ rel_atom_str a ^")") neg_body) -let neg_facts_str negs = - String.concat " " - (List.map (fun (vs,d) -> - let vs = Aux.Strings.elements vs in - let q = if vs = [] then "" - else "forall "^String.concat ", " vs in - q ^ "(not (and "^facts_str d^"))") negs) - let branch_str rel (args, body, neg_body) = - "("^ fact_str (rel, args) ^ " <= " ^ facts_str body ^ - " " ^ neg_facts_str neg_body ^ ")" + "("^ rel_atom_str (rel, args) ^ " <= " ^ rel_atoms_str body ^ + " " ^ neg_rel_atoms_str neg_body ^ ")" -let lit_def_str (rel, branches) = +let def_str (rel, branches) = String.concat "\n" (List.map (fun (args, body, neg_body) -> - "("^ fact_str (rel, args) ^ " <= " ^ facts_str body ^ - " " ^ neg_lfacts_str neg_body ^ ")" - ) branches) + "("^ rel_atom_str (rel, args) ^ " <= " ^ rel_atoms_str body ^ + " " ^ neg_rel_atoms_str neg_body) + branches) -let exp_def_str (rel, branches) = - String.concat "\n" (List.map (fun (args, body, neg_body) -> - "("^ fact_str (rel, args) ^ " <= " ^ facts_str body ^ - " " ^ neg_facts_str neg_body ^ ")" - ) branches) - let sb_str sb = String.concat ", " (List.map (fun (v,t)->v^":="^term_str t) sb) @@ -486,7 +321,11 @@ if List.mem head tot_base then [] else if List.exists (fun (rel,args as neg_atom) -> rel = "distinct" && Aux.not_unique args || - List.mem neg_atom tot_base) neg_body then [] + (* faster option: *) + (* List.mem neg_atom tot_base *) + (* accurate option: *) + List.exists (unifies neg_atom) tot_base + ) neg_body then [] else [Aux.Left head] | head, cond1::body, neg_body -> Aux.map_try (fun fact -> @@ -494,7 +333,7 @@ if !debug_level > 5 then ( Printf.printf "instantiate_one: trying to unify %s and %s\n%!" - (fact_str fact) (fact_str cond1) + (rel_atom_str fact) (rel_atom_str cond1) ); (* }}} *) @@ -515,7 +354,7 @@ (* {{{ log entry *) if !debug_level > 4 then ( Printf.printf "inst_stratum: old_base = %s; cur_base = %s\n%!" - (facts_str old_base) (facts_str cur_base); + (rel_atoms_str old_base) (rel_atoms_str cur_base); Printf.printf "inst_stratum: #old_irules = %d, #cur_irules = %d\n%!" (List.length old_irules) (List.length cur_irules) @@ -528,7 +367,7 @@ (* {{{ log entry *) if !debug_level > 4 then ( Printf.printf "inst_stratum: cur-cur = %s\n%!" - (facts_str new_base1) + (rel_atoms_str new_base1) ); (* }}} *) let new_base2, new_irules2 = @@ -536,7 +375,7 @@ (* {{{ log entry *) if !debug_level > 4 then ( Printf.printf "inst_stratum: cur-old = %s\n%!" - (facts_str new_base2) + (rel_atoms_str new_base2) ); (* }}} *) let new_base3, new_irules3 = @@ -544,7 +383,7 @@ (* {{{ log entry *) if !debug_level > 4 then ( Printf.printf "inst_stratum: old-cur = %s\n%!" - (facts_str new_base3) + (rel_atoms_str new_base3) ); (* }}} *) let new_base = Aux.unique_sorted (new_base1 @ new_base2 @ new_base3) @@ -564,9 +403,117 @@ instantiate (inst_stratum [] [] base stratum) strata in instantiate base - (List.map rules_of_lit_defs (stratify [] (lit_defs_of_rules rules))) + (List.map rules_of_defs (stratify [] (defs_of_rules rules))) +(* ************************************************************ *) +(* ************************************************************ *) +(** {3 Transformations of GDL clauses: inlining, negation.} *) +(** Expand branches of a definition inlining the provided definitions, + only expand positive literals. Iterate expansion to support + nesting of definitions. *) +let expand_positive_lits defs brs = + let used_vars = ref (gdl_defs_vars (("",brs)::defs)) in + let freshen_brs brs = + let br_vars = gdl_defs_vars ["",brs] in + let sb = List.map + (fun v -> + v, Aux.not_conflicting_name ~truncate:true !used_vars v) + (Aux.Strings.elements br_vars) in + used_vars := Aux.add_strings (List.map snd sb) !used_vars; + List.map (subst_br sb) brs in + let expand_atom (rel, args as atom) result = + (let try def_brs = freshen_brs (List.assoc rel defs) in + Aux.concat_map (fun (sb, (head, r_body, r_neg_body)) -> + let args = subst_terms sb args in + List.map (fun (params,d_body,d_neg_body) -> + let sb = unify sb params args in + let r_br = + head, d_body @ r_body, d_neg_body @ r_neg_body in + sb, subst_br sb r_br + ) def_brs + ) result + with Not_found -> + List.map (fun (sb,(head,r_body,r_neg_body)) -> + sb, atom::r_body, r_neg_body) result) in + let expand_br (head, body, neg_body) = + let init = [[], (head, [], neg_body)] in + Aux.concat_foldr expand_atom body init in + let rec fix n_brs brs i = + let brs = Aux.concat_map expand_br brs in + let new_n_brs = List.length brs in + if new_n_brs > n_brs && i > 0 then fix new_n_brs brs (i-1) + else brs in + fix (List.length brs) brs 5 + + +(** Form clause bodies whose disjunction is equivalent to the + negation of disjunction of given clause bodies. *) +let negate_bodies conjs = + let placeholder = "", [] in + let clauses = List.map (fun body -> placeholder, body) conjs in + let clauses = List.map rules_of_clause clauses in + let clauses = List.map (fun (_,body,neg_body) -> + List.map (fun a -> Pos (atom_of_clause a)) body @ + List.map (fun a -> Neg (atom_of_clause a)) neg_body) clauses in + let negated = Aux.product clauses in + (* can raise [Not_found] in case of unsatisfiable "not distinct" *) + let nclause body = + let uniterms, lits = + Aux.partition_map (function + | Neg (Distinct terms) -> Left terms + | Neg atom -> Pos atom + | Pos atom -> Neg atom + | Disjunction _ -> assert false) body in + let sb = List.fold_left unify_all [] uniterms in + List.map (subst_literal sb) lits in + Aux.map_try nclause negated + + +(** Rename clauses so that they have disjoint variables. Return a cell + storing all variables. *) +let rename_clauses clauses = + let used_vars = ref Aux.Strings.empty in + let clauses = List.map (fun cl -> + let cl_vars = clause_vars cl in + let sb = + List.map (fun v -> + let nv = Aux.not_conflicting_name ~truncate:true !used_vars v in + used_vars := Aux.Strings.add nv !used_vars; + v, nv + ) cl_vars in + subst_clause sb cl + ) clauses in + used_vars, clauses + + +let flatten_disjs body = + let rec aux = function + | (Pos _ | Neg _) as lit -> [lit] + | Disj lits -> Aux.concat_map aux lits in + List.map (function + | (Pos _ | Neg _) as lit -> lit + | Disj _ as disj -> Disj (aux disj)) body + + +let nnf_dnf body = + List.map (function + | Pos a -> [Neg a] + | Neg a -> [Pos a] + | Disj lits -> + List.map (function + | Pos a -> Neg a + | Neg a -> Pos a + | _ -> assert false) lits + ) (List.map flatten_disjs body) + + +(* ************************************************************ *) +(* ************************************************************ *) +(** {3 GDL whole-game operations.} + + Aggregate playout, player-denoting variable elimination. *) + (* Collect the aggregate playout, but also the actions available in the state. *) exception Playout_over @@ -578,7 +525,7 @@ (* {{{ log entry *) if !debug_level > 4 then ( Printf.printf "GDL.aggregate_ply: updated base -- %s\n%!" - (String.concat " " (List.map fact_str base)) + (rel_atoms_str base) ); (* }}} *) let does = Aux.map_some (fun (rel, args) -> @@ -714,23 +661,258 @@ loop cycle trav [] cycle tail in loop [] [] [] [] cands -let cmp_masks t1 t2 = - (* {{{ log entry *) - if !debug_level > 4 then ( - Printf.printf "cmp_masks: %s <= %s .. " (term_str t1) (term_str t2); - ); - (* }}} *) - try ignore (match_meta [] [] [t2] [t1]); - (* {{{ log entry *) - if !debug_level > 4 then ( - Printf.printf "true\n%!"; - ); - (* }}} *) - true - with Not_found -> - (* {{{ log entry *) - if !debug_level > 4 then ( - Printf.printf "false\n%!"; - ); - (* }}} *) - false + +let expand_players clauses = + let players = + Aux.map_some (function + | ("role", [player]), _ -> Some player + | _ -> None + ) clauses in + let exp_clause (rel, _ as head, body as clause) = + (* determine variables standing for players *) + let plvars = + let head = if rel = "role" then [] else [head] in + Aux.concat_map player_vars_of + (head @ List.map rel_of_atom body) in + if plvars = [] then [clause] + else + let sbs = List.map (fun v -> + List.map (fun pl -> v, pl) players) plvars in + List.map (fun sb -> subst_clause sb clause) sbs in + Aux.concat_map exp_clause clauses + +(** Partition relations into stable (not depending, even indirectly, + on "true") and remaining ones. *) +let stable_rels defs = + let rec aux nonstable remaining = + let more = Aux.map_some (fun (rel, branches) -> + if List.exists + (fun (_, body, neg_body) -> + let called = List.map fst (body @ neg_body) in + List.exists (fun rel -> rel = "true" || + List.mem rel nonstable) called + ) branches + then Some rel else None + ) remaining in + if more = [] then List.map fst remaining, nonstable + else aux (more @ nonstable) + (List.filter (fun (rel,_) -> not (List.mem rel more)) remaining) + in + aux [] remaining + + +let state_terms body = + let rec aux = function + | Pos (True t) -> [t] + | Neg (True t) -> [t] + | Disj ls -> Aux.concat_map aux ls + | _ -> [] in + Aux.concat_map aux body + +let rec term_arities = + function + | Func (rel, args) -> + (rel, Array.length args):: + Aux.concat_map term_arities (Array.to_list args) + | _ -> [] + + +(* ************************************************************ *) +(* ************************************************************ *) +(** {3 Paths and operations involving terms and paths.} *) + +(** A path is a position in a tree together with labels on nodes from + the root to that position (but excluding the position). *) +type path = (string * int) list + +(** A trie representing a set of paths. *) +type path_set = + | Empty + | Here (** Singleton $\{\epsilon\}$. *) + | Below of (string * path_set array) list + | Here_and_below of (string * path_set array) list +(* Subtries are in sorted order. *) + +let path_str p = + String.concat "_" (List.map (fun (rel, arg) -> + rel ^ "_" ^ string_of_int arg) p) + +let paths_union ps1 ps2 = + let rec aux = function + | Empty, p | p, Empty -> p + | Here, Below ps | Below ps, Here -> Here_and_below ps + | Below ps1, Below ps2 -> Below (merge (ps1, ps2)) + | Below ps1, Here_and_below ps2 + | Here_and_below ps2, Below ps1 + | Here_and_below ps1, Here_and_below ps2 + -> Here_and_below (merge (ps1, ps2)) + and merge = function + | [], ps | ps, [] -> ps + | ((rel1, args1)::ps1), ((rel2, args2)::ps2) when rel1 = rel2 -> + let args = Aux.array_map2 aux args1 args2 in + (rel1, args)::merge (ps1, ps2) + | ((rel1, _ as rel_ps)::ps1), ((rel2, _)::_ as ps2) when rel1 < rel2 -> + rel_ps::merge (ps1, ps2) + | ((rel1, _)::_ as ps1), ((rel2, _ as rel_ps)::ps2) -> + rel_ps::merge (ps1, ps2) in + aux (ps1, ps2) + +let add_path arities p ps = + let rec aux = function + | [], Empty -> Here + | [], (Below ps | Here_and_below ps) -> Here_and_below ps + | (rel, pos)::suffix, Below ps -> + Below (add suffix rel pos ps) + | (rel, pos)::suffix, Here_and_below ps -> + Here_and_below (add suffix rel pos ps) + and add p rel pos ps = + (let try args, ps = Aux.pop_assoc rel ps in + (* Keeping functional... *) + let args = Array.copy args in + args.(pos) <- aux (p, args.(pos)); + (rel, args)::ps + with Not_found -> + let args = Array.make (arities rel) Empty in + args.(pos) <- aux (p, args.(pos)); + (rel, args)::ps) + in + aux (p, ps) + +(** Find a path in a term and substitute, raise [Not_found] if path + not present. [subst_at_path p s t] is $t[p \ot s]$. *) +let subst_at_path p s t = + let rec aux = function + | [], _ -> s + | (rel1, pos)::p, Func (rel2, args) when rel1 = rel2 -> + let args = Array.copy args in + args.(pos) <- aux (p, args.(pos)); + Func (rel1, args) + | _ -> raise Not_found in + aux (p, t) + +(** [simult_subst ps s t] substitutes [s] at all [t] paths that belong + to the set [ps], returns $t[ps \ot s]$. *) +let simult_subst ps s t = + let rec aux = function + | Empty, t -> t + | (Here | Here_and_below _), _ -> s + | Below subps, (Func (rel, args) as t) -> + (let try argps = List.assoc rel subps in + Func (rel, Aux.array_map2 (fun ps t -> aux (ps,t)) argps args) + with Not_found -> t) + | Below _, t -> t in + aux (ps, t) + +(** Find the subterm at given path, if the term does not have the + path, return [Not_found]; [at_path p t] is $t \tpos p$. *) +let at_path t p = + let rec aux = function + | [], t -> t + | (rel1, pos)::p, Func (rel2, args) when rel1 = rel2 -> + aux (p, args.(pos)) + | _ -> raise Not_found in + aux (p, t) + +(** Find the list of subterms at paths from the given set, if the term + does not have some of the paths, ignore them if [~fail_at_missing:false], + raise [Not_found] if [~fail_at_missing:true]. *) +let at_paths ?(fail_at_missing=false) ps t = + let miss () = + if fail_at_missing then raise Not_found else [] in + let rec aux = function + | Empty, t -> [] + | Here, t -> [t] + | Here_and_below subps, t -> t::(aux (Below subps, t)) + | Below subps, (Func (rel, args) as t) + when not fail_at_missing -> + (let try argps = List.assoc rel subps in + let res = Aux.array_map2 (fun ps t -> aux (ps,t)) argps args in + List.concat (Array.to_list res) + with Not_found -> []) + | Below [rel1, argps], (Func (rel2, args) as t) + when rel1 = rel2 (* && fail_at_missing *) -> + let res = Aux.array_map2 (fun ps t -> aux (ps,t)) argps args in + List.concat (Array.to_list res) + | Below _, t -> miss () in + aux (ps, t) + +(** Find the list of results of a function applied to paths from the + given set that are in the term, and to subterms at these paths. *) +let map_paths f ps t = + let rec aux revp = function + | Empty, t -> [] + | Here, t -> [f (List.rev revp) t] + | Here_and_below subps, t -> + f (List.rev revp) t::(aux path (Below subps, t)) + | Below subps, (Func (rel, args) as t) -> + (let try argps = List.assoc rel subps in + let res = + Array.mapi (fun i ps -> aux ((rel,i)::revp) (ps,args.(i))) argps in + List.concat (Array.to_list res) + with Not_found -> []) + | Below _, t -> [] in + aux [] (ps, t) + +(** All paths in a term pointing to subterms that satisfy a + predicate. With [~prefix_only:true], paths that contain a path + that has been included, are not included. *) +let rec term_paths ?(prefix_only=false) cond = function + | Func (rel, args) as t -> + let subps = Array.map (term_paths p) args in + let no_sub = Array.for_all (fun subp -> subp = Empty) subps in + let here = cond t in + if no_sub && not here then Empty + else if here && not no_sub && not prefix_only then Here_and_below subps + else if here then Here + else Below subps + | t -> if cond t then Here else Empty + +(** The number of nodes in a term tree. *) +let rec term_size = function + | Const _ | Var _ -> 1 + | Func (_, args) -> + Array.fold_left (fun acc t -> acc + term_size t) 1 args + +(** The set of paths that merges two terms, the cardinality of this + set, and the size of the largest common subtree. *) +let rec merge_terms s t = + match s, t with + | s, t when s = t -> Empty, 0, term_size t + | Func (rel1, args1), Func (rel2, args2) when rel1 = rel2 -> + let subr = Aux.array_map2 merge_terms args1 args2 in + let subps = Array.map Aux.fst3 subr + and subcard = Array.map Aux.snd3 subr + and subsize = Array.map Aux.trd3 subr in + Below [rel1, subps], Array.fold_left (+) 0 subcard, + Array.fold_left (+) 1 subsize + | _ -> Here, 1, 0 + + +(** List the paths in a set. *) +let paths_to_list ps = + let rec subpaths subps = + Aux.concat_map (fun (rel, subps) -> + Array.to_list + (Array.mapi (fun i ps -> + let sub_res = aux ps in + List.map (fun p -> (rel, i)::p) sub_res) subps)) subps + and aux = function + | Empty -> [] + | Here -> [[]] + | Here_and_below subps -> []::(subpaths subps) + | Below subps -> subpaths subps in + aux ps + + +(** Toss relations hold between subterms of GDL state terms: generate + Toss relation name. *) +let rel_on_paths rel paths_tup = + rel ^ "__" ^ String.concat "__" (List.map path_str paths_tup) + +(** Some Toss predicates are generated from a path and an expected + subterm at that path. *) +let pred_on_path_subterm path subterm = + path_str path ^ term_to_name subterm + +(** A "blank" term. *) +let blank = Const "_BLANK_" Modified: trunk/Toss/GGP/GDL.mli =================================================================== --- trunk/Toss/GGP/GDL.mli 2011-07-06 22:13:35 UTC (rev 1506) +++ trunk/Toss/GGP/GDL.mli 2011-07-09 10:28:17 UTC (rev 1507) @@ -19,13 +19,23 @@ type term = | Const of string | Var of string - | MVar of string | Func of string * term list +type rel_atom = string * term list +(** Positive and negative literals separated, disjunctions expanded-out. *) +type gdl_rule = rel_atom * rel_atom list * rel_atom list +(** Collect rules by relations. *) +type def_branch = term list * rel_atom list * rel_atom list +type gdl_defs = (string * def_branch list) list + +module Terms : Set.S with type elt = term +module Atoms : Set.S with type elt = rel_atom + type atom = | Distinct of term list - | Rel of string * term list - | Currently of term + | Rel of rel_atom + | Role of term + | True of term | Does of term * term type literal = @@ -33,71 +43,37 @@ | Neg of atom | Disj of literal list -type game_descr_entry = - | Datalog of string * term list * literal list - | Next of term * literal list - | Legal of term * term * literal list - | Goal of term * int * literal list - | GoalPattern of term * string * literal list - | Terminal of literal list - | Role of term - | Initial of term * literal list - | Atomic of string * term list +type clause = rel_atom * literal list type request = - | Start of string * term * game_descr_entry list * int * int + | Start of string * term * clause list * int * int (** prepare game: match id, role, game, startclock, playclock *) | Play of string * term list (** request a move: match id, actions on previous step *) | Stop of string * term list (** game ends here: match id, actions on previous step *) -(** Type shortcuts (mostly for documentation). *) -type gdl_atom = string * term list -type gdl_rule = gdl_atom * gdl_atom list * gdl_atom list -(** Definition with collected relation branches and negation-local - variables found. *) -type lit_def_branch = - term list * gdl_atom list * (Aux.Strings.t * gdl_atom) list -type lit_def = string * lit_def_branch list -(** Definition with expanded definitions: expansion of a negated - relation brings negated conjunctions. *) -type exp_def_branch = - term list * gdl_atom list * (Aux.Strings.t * gdl_atom list) list -type exp_def = string * exp_def_branch list - -module Terms : Set.S with type elt = term -module Atoms : Set.S with type elt = gdl_atom - val term_str : term -> string val terms_str : term list -> string val sb_str : (string * term) list -> string -val fact_str : string * term list -> string -val facts_str : (string * term list) list -> string -val exp_def_str : exp_def -> string +val rel_atom_str : rel_atom -> string +val rel_atoms_str : rel_atom list -> string +val def_str : + string * (term list * rel_atom list * rel_atom list) -> string val tuples_str : term list list -> string val proto_rel_str : string * string array -> string -val lit_def_br_vars : lit_def_branch -> Aux.Strings.t -val lit_def_str : lit_def -> string -val neg_facts_str : (Aux.Strings.t * gdl_atom list) list -> string +val gdl_rule_vars : gdl_rule -> Aux.Strings.t +val gdl_rules_vars : gdl_rule list -> Aux.Strings.t +val branch_str : string -> def_branch -> string -val exp_def_br_vars : exp_def_branch -> Aux.Strings.t -val branch_str : string -> exp_def_branch -> string - -val sdef_br_vars : term * gdl_atom list * (Aux.Strings.t * gdl_atom list) list-> - Aux.Strings.t -val sdef_brs_vars : - (term * gdl_atom list * (Aux.Strings.t * gdl_atom list) list) list -> - Aux.Strings.t - val func_graph : string -> term list -> term list list -val rules_of_entry : game_descr_entry -> gdl_rule list +val rules_of_clause : clause -> gdl_rule list val terms_vars : term list -> Aux.Strings.t -val rels_vars : gdl_atom list -> Aux.Strings.t +val rels_vars : rel_atom list -> Aux.Strings.t val term_to_name : ?nested:bool -> term -> string val term_vars : term -> Aux.Strings.t @@ -107,40 +83,24 @@ val subst_one : string * term -> term -> term val subst : (string * term) list -> term -> term -val subst_rel : (string * term) list -> gdl_atom -> gdl_atom -val subst_rels : (string * term) list -> gdl_atom list -> gdl_atom list -val subst_br : (string * term) list -> exp_def_branch -> exp_def_branch +val subst_rel : (string * term) list -> rel_atom -> rel_atom +val subst_rels : (string * term) list -> rel_atom list -> rel_atom list +val subst_br : (string * term) list -> def_branch -> def_branch -val add_neg_body_vars : Aux.Strings.t -> gdl_atom list -> - (Aux.Strings.t * gdl_atom) list +val defs_of_rules : gdl_rule list -> gdl_defs -val lit_defs_of_rules : - ((string * term list) * gdl_atom list * (string * term list) list) list -> - lit_def list - -val exp_defs_of_lit_defs : lit_def list -> exp_def list - -val match_meta : ?ignore_meta:bool -> (string * term) list -> - (string * term) list -> term list -> term list -> - (string * term) list * (string * term) list - val unify : (string * term) list -> term list -> term list -> (string * term) list val unifies : term -> term -> bool -val generalize : term -> term -> (int * int) * int * (term * term) list * term +val saturate : rel_atom list -> gdl_rule list -> rel_atom list -val saturate : gdl_atom list -> gdl_rule list -> gdl_atom list +val stratify : gdl_defs list -> gdl_defs -> gdl_defs list -val stratify : ?def:bool -> lit_def list list -> - lit_def list -> lit_def list list - val aggregate_playout : term array -> int -> gdl_rule list -> gdl_rule list * gdl_rule list * (string * term list) list * term list * (term list list list * term list list) val find_cycle : term option list -> term option list - -val cmp_masks : term -> term -> bool Modified: trunk/Toss/GGP/GDLParser.mly =================================================================== --- trunk/Toss/GGP/GDLParser.mly 2011-07-06 22:13:35 UTC (rev 1506) +++ trunk/Toss/GGP/GDLParser.mly 2011-07-09 10:28:17 UTC (rev 1507) @@ -17,7 +17,7 @@ %start parse_game_description parse_request parse_term %type <GDL.request> parse_request request %type <GDL.term> parse_term -%type <GDL.game_descr_entry list> parse_game_description game_description +%type <GDL.clause list> parse_game_description game_description %% @@ -44,11 +44,11 @@ | (Const "distinct" | Const "DISTINCT")::args -> Distinct args | [(Const "true" | Const "TRUE"); arg] -> - Currently arg + True arg | [(Const "does" | Const "DOES"); player; action] -> Does (player, action) | (Const "role" | Const "ROLE")::player -> - Rel ("role", player) + Role player | (Const "init" | Const "INIT")::state -> Rel ("init", state) | (Const "next" | Const "NEXT")::state -> @@ -71,38 +71,12 @@ | OPEN NOT a=atom CLOSE { Neg a } | OPEN OR disjs=list (literal) CLOSE { Disj disjs } -game_descr_entry: +clause: | OPEN REVIMPL head=atom body=list (literal) CLOSE { match head with - | Rel ("next", [t]) -> Next (t, body) - | Rel ("next", _) -> - raise (Lexer.Parsing_error "GDL next: not unary") - | Rel ("init", [arg]) -> Initial (arg, body) - | Rel ("init", _) -> - raise (Lexer.Parsing_error "GDL init: not unary") - | Rel ("terminal", []) -> Terminal body - | Rel ("terminal", _) -> - raise (Lexer.Parsing_error "GDL terminal: not nullary") - | Rel ("legal", [t1; t2]) -> - Legal (t1, t2, body) - | Rel ("legal", _) -> - raise (Lexer.Parsing_error "GDL legal: not binary") - | Rel ("goal", [t; Const gv]) -> - (try - let gv = int_of_string gv in - Goal (t, gv, body) - with Failure _ | Invalid_argument _ -> - raise (Lexer.Parsing_error "GDL goal: value not a constant int")) - | Rel ("goal", [t; Var gv]) -> - (try - GoalPattern (t, gv, body) - with Failure _ | Invalid_argument _ -> - raise (Lexer.Parsing_error "GDL goal: value not a constant int")) - | Rel ("goal", _) | Rel ("GOAL", _) -> - raise (Lexer.Parsing_error - "GDL goal: not binary or value not constant") - | Rel (r, args) -> Datalog (r, args, body) - | Currently _ -> + | Rel rel_atom -> rel_atom, body + | Role player -> ("role", [player]), body + | True _ -> raise (Lexer.Parsing_error "GDL rule: \"true\" in head") | Distinct _ -> raise (Lexer.Parsing_error "GDL rule: \"distinct\" in head") @@ -111,13 +85,8 @@ } | a=atom { match a with - | (Rel ("init", [arg])) -> Initial (arg, []) - | (Rel ("init", _)) -> - raise (Lexer.Parsing_error "GDL init: not unary") - | (Rel ("role", [arg])) -> Role arg - | (Rel ("role", _) | Rel ("ROLE", _)) -> - raise (Lexer.Parsing_error "GDL role: not unary") - | Rel (r, args) -> Atomic (r, args) + | Role player -> ("role", [player]), [] + | Rel rel_atom -> rel_atom, [] | _ -> raise (Lexer.Parsing_error "GDL atomic entry: not init, role nor fact") @@ -125,7 +94,7 @@ %public game_description: -| descr=list(game_descr_entry) +| descr=list(clause) { descr } %public request: Modified: trunk/Toss/GGP/Translate.ml =================================================================== --- trunk/Toss/GGP/Translate.ml 2011-07-06 22:13:35 UTC (rev 1506) +++ trunk/Toss/GGP/Translate.ml 2011-07-09 10:28:17 UTC (rev 1507) @@ -2072,8 +2072,8 @@ rname, List.map (fun _ -> ()) args) static_rules) in let static_rels = List.map (fun (rel,args) -> - rel, List.length args, - Aux.all_tuples_for args mask_paths) static_rels in + let ar = List.length args in + rel, ar, Aux.all_ntuples mask_paths ar) static_rels in let static_base = Aux.collect static_base in (* TODO: optimize by indexing elements by path position terms (currently, substitution values) *) @@ -3696,7 +3696,7 @@ let translate_last_action gdl_translation state actions = - if actions = [] then (* start of game -- Server will handle this as NOOP *) + if actions = [] then (* start of game -- Server will not perform a move *) "", [] else translate_incoming_move gdl_translation state actions Modified: trunk/Toss/Solver/Structure.ml =================================================================== --- trunk/Toss/Solver/Structure.ml 2011-07-06 22:13:35 UTC (rev 1506) +++ trunk/Toss/Solver/Structure.ml 2011-07-09 10:28:17 UTC (rev 1507) @@ -261,7 +261,32 @@ let new_incidence = StringMap.add rn new_incidence_imap new_struc.incidence in { new_struc with relations = new_rel ; incidence = new_incidence } +(* Add tuple [tp] to relation [rn] in structure [struc]. *) +let add_rel_named_elems struc rn tp = + let new_struc, tp = + Array.fold_right (fun (struc, tp) e -> + let struc, e = find_or_new_elem struc e in + struc, e::tp) + (add_rel_name rn (Array.length tp) struc) tp in + let tp = Array.of_list tp in + let add_to_relmap rmap = + let tps = StringMap.find rn rmap in + StringMap.add rn (Tuples.add tp tps) rmap in + let new_rel = add_to_relmap new_struc.relations in + let add_to_imap imap e = + try + IntMap.add e (Tuples.add tp (IntMap.find e imap)) imap + with Not_found -> + IntMap.add e (Tuples.singleton tp) imap in + let new_incidence_imap = + try + Array.fold_left add_to_imap (StringMap.find rn new_struc.incidence) tp + with Not_found -> + Array.fold_left add_to_imap IntMap.empty tp in + let new_incidence = StringMap.add rn new_incidence_imap new_struc.incidence in + { new_struc with relations = new_rel ; incidence = new_incidence } + (* Return a structure with a single relation, over a single tuple, of different elements. *) let free_for_rel rel arity = Modified: trunk/Toss/Solver/Structure.mli =================================================================== --- trunk/Toss/Solver/Structure.mli 2011-07-06 22:13:35 UTC (rev 1506) +++ trunk/Toss/Solver/Structure.mli 2011-07-09 10:28:17 UTC (rev 1507) @@ -167,6 +167,9 @@ (** Add tuple [tp] to relation [rn] in structure [struc]. *) val add_rel : structure -> string -> int array -> structure +(** Add tuple [tp] to relation [rn] in structure [struc]. *) +val add_rel_named_elems : structure -> string -> string array -> structure + (** Add tuple [tp] to relation [rn] in structure [struc] without checking whether it and its elements already exist in the structure and without checking arity. *) Modified: trunk/Toss/www/reference/reference.tex =================================================================== --- trunk/Toss/www/reference/reference.tex 2011-07-06 22:13:35 UTC (rev 1506) +++ trunk/Toss/www/reference/reference.tex 2011-07-09 10:28:17 UTC (rev 1507) @@ -1343,11 +1343,13 @@ of $s$ and $t$, the bigger its size the more similar $s$ and $t$ are. \end{definition} -Let $\mathrm{Next}_{e}$ be the set of \texttt{next} clauses in $G$ with all -atoms of \texttt{does} expanded (inlined) by the \texttt{legal} -clause definitions, duplicating the \texttt{next} clause when more -than one head of \texttt{legal} unifies with the \texttt{does} atom. -Intuitively, these are expanded forms of clauses defining game state change. +Let $\mathrm{Next}_{e}$ be the set of \texttt{next} clauses in $G$ +with all atoms of relations whose definitions use \texttt{true} +expanded (inlined) by their clause definitions, duplicating the +\texttt{next} clause when more than one clause of a relation unifies +with its atom. We expand \texttt{does} atoms by \texttt{legal} +clauses. We also expand disjunctions. Intuitively, these are expanded +forms of clauses defining game state change. For each clause $\calC \in \mathrm{Next}_{e}$, we select two terms $s_\calC$ and $t_\calC$ in the following way. The term $s_\calC$ is @@ -1420,7 +1422,7 @@ \begin{definition} We define the \emph{element mask equivalence} $\sim$ by: \[ t \sim s \quad \Leftrightarrow \quad - t[P_f \ot c] = s[P_f \ot c] \text{ for all terms } c.\] + t[\calP_f \ot c] = s[\calP_f \ot c] \text{ for all terms } c.\] The set of elements $A$ of the initial Toss structure $\frakA$ consists of equivalence classes of $\sim$. For $a \in A$ we write $\lsem a \rsem$ to denote the corresponding subset of equivalent terms from $\calS$. @@ -1488,19 +1490,21 @@ $p \in \calP_f$ and subterms $s = t\tpos_p, t \in \calS$, we introduce the \emph{fluent predicate} $Flu^s_p(a)$: \[ Flu^s_p(a) \ \ \iff \ \ t\tpos_p\ =\ s \text{ for some } - t \in \lsem a \rsem \cap \calS^{\text{init}}. \] +t \in \lsem a \rsem \cap \calS^{\text{init}}. +\] +Currently in the implementation, the string representing the path $p$ +alone is used as the predicate name, we use the prefixes $Anch$ and +$Flu$ in the reference for clarity. \noindent \textbf{Mask predicates.} -We say that a term $m$ is a \emph{mask term} if the paths to all variables -of $m$ are contained in $\calP_m \cup \calP_f$ and for each -$p \in \calP_m \cup \calP_f$ if $p$ exists in $m$ then $m \tpos_p$ is -a variable. We say that $m$ \emph{masks} a term $t$ if $m$ is a mask term -and there exists -a substitution $\sigma$ such that $\sigma(m) = t$. For all mask terms -$m \in \calS$ we introduce the \emph{mask predicate} $Mask_m$. +We define the mask root relation $\sim_m$ by: +\[ t \sim_m s \quad \Leftrightarrow \quad t[\calP_f \cup \calP_m \ot +c] = s[\calP_f \cup \calP_m \ot c] \text{ for all terms } c.\] We call +an equivalence class of $\sim_m$ a \emph{mask root}. For all mask +roots $m$ we introduce the \emph{mask predicate} $Mask_m$. Mask predicates are similar to the anchor predicates, but instead of -matching against a subterm, they match against the mask. -\[ Mask_m(a) \ \ \iff \ \ m \text{ masks all } t \in \lsem a \rsem. \] +matching against a subterm, they match against the mask root. +\[ Mask_m(a) \ \ \iff \ \ \lsem a \rsem \subset m. \] %Elements $a \in A$ can be represented as tuples consisting of a mask %term $m_a$ such that $Mask_{m_a}(a)$ and terms $s_p = a\tpos^m_p$ for @@ -1570,8 +1574,8 @@ \text{ and } \ \ Flu^{\mathtt{x}}_{(\mathtt{control},1)} = \{a_{ctrl}\}. \] \emph{Mask predicates.} -For the specification we consider, there are two mask terms: -$m_1 = (\mathtt{control}\ x)$ and $m_2 = (\mathtt{cell}\ x\ y\ z)$. +For the specification we consider, there are two mask roots: +$m_1 = \big\{(\mathtt{control}\ x) \ \big| \ (\mathtt{control}\ x) \in \calS \big\}$ and $m_2 = \big\{(\mathtt{cell}\ x\ y\ z) \ \big|\ (\mathtt{cell}\ x\ y\ z) \in \calS \big\}$. The predicate $Mask_{m_1} \ = \ \{ a_{ctrl} \}$ holds exactly for the control element, and $Mask_{m_2} = A \setminus \{a_{ctrl}\}$ contains these elements of $A$ which are not the control element, \ie the board elements. @@ -1690,8 +1694,13 @@ then for correctness, we need to preclude application of the first (more general) rule when the more concrete rule is applicable, adding \texttt{distinct} conditions to clauses of the otherwise more general -rule. In the current implementation, we only consider maximal sets of -\texttt{next} clauses. +rule. In the current implementation, we select a minimal covering +family of maximal sets of \texttt{next} clauses, where covering +means that every clause occurs in at least one set of the +family. (While in Section~\ref{subsec-rules} we describe additional +partition of the substituted clauses, in unlikely scenarios the +generated $\sigma_{\ol{\calC},\ol{\calN}}$ might be too specific to +capture all possible moves.) \begin{example} Let $\calC_1 = \mathtt{noop}$ and $\calC_2 = (\mathtt{mark}\ x\ y)$. @@ -1723,16 +1732,24 @@ will keep track of the elements that possibly lose fluents and ensure correct translation. +We determine which clauses are frame clauses prior to partitioning +into the rule clauses and computing the substitution +$\sigma_{\ol{\calC},\ol{\calN}}$ -- at the point where fluent paths +are computed. + From the frame clauses in $\sigma_{\ol{\calC}, \ol{\calN}}(\calN_1), \dots, -\sigma_{\ol{\calC}, \ol{\calN}}(\calN_m)$, we select all (maximal) subsets $J$ +\sigma_{\ol{\calC}, \ol{\calN}}(\calN_m)$, we select subsets $J$ such that, clauses in $J$ having the form $\mathtt{(<= (next\ s_i)\ b_i)}$, it holds -\[ s_1 \ \dot{=}_f \ \ldots \ \dot{=}_f \ s_{|J|}, \] -\ie the arguments of \texttt{next} unify. Note that we use $\dot{=}_f$ -instead of the standard unification, and by that we mean that the variables -shared with the \texttt{legal} clauses $\ol{\calC}$ are treated as constants. -The reason is that these variables are not local to the clauses and must -therefore remain intact. +\[ s_1 \ \dot{=}_f \ \ldots \ \dot{=}_f \ s_{|J|}, \] \ie the +arguments of \texttt{next} unify. Note that we use $\dot{=}_f$ instead +of the standard unification, and by that we mean that the variables +shared with the \texttt{legal} clauses $\ol{\calC}$ are treated as +constants. The reason is that these variables are not local to the +clauses and must therefore remain intact. As before, we select a +minimal covering family of maximal such subsets (possibly resulting, +in unlikely cases, in rules that do not remove fluent predicates over +elements that do not gain fluent predicates during rewriting.) Intuitively, the selected sets $J$ describe a partition of the state terms that could possibly be copied without change by the rule we will generate @@ -1751,8 +1768,8 @@ paths with \texttt{BLANK} and thus allow them to be deleted in case they are not preserved by other \texttt{next} clauses of the rule. Let us denote by $h$ the term $\rho(s_1)$ after the above replacement. The -erasure clauses $\calE_{\ol{\calC}, \ol{\calN}}(J) = \{ \mathtt{(<=\ - h\ e_1)} \dots \mathtt{(<=\ h\ e_l)} \},$ and we write +erasure clauses +$\calE_{\ol{\calC}, \ol{\calN}}(J) = \{ \mathtt{(<=\ h\ e_1)} \dots \mathtt{(<=\ h\ e_l)} \}$, and we write $\calE_{\ol{\calC}, \ol{\calN}}$ for the union of all $\calE_{\ol{\calC}, \ol{\calN}}(J)$, \ie for the set of all $\ol{\calC}, \ol{\calN}$ erasure clauses. @@ -1797,9 +1814,15 @@ rule clauses, and generate a Toss rule candidate for every partition of the groups into true and false ones: we collect the rule clauses that agree with the given partition. The selected atoms, some negated -according to the partition, form the separation condition. +according to the partition, form the separation condition. Currently, +we do not consider atoms under disjunction (mostly for simplicity +considerations; would this cause problems, the definition can be +extended to include disjunctions in making the partition). -For each candidate, we will construct the Toss rule in two steps. +We filter the rule candidates by checking for satisfiability (in the +same GDL model as used for building the initial Toss structure) of the +stable part of their clause bodies. For each remaining candidate, +we will construct the Toss rule in two steps. In the first step we generate the \emph{matching condition}: we translate the conjunction of the bodies of rule clauses and the @@ -1807,10 +1830,6 @@ atomic relations presented in Section~\ref{subsec-rels} and is described in Section~\ref{subsec-translate}. -Later we \emph{filter} the rule candidates by checking for -satisfiability in the initial structure of the stable part of the -matching condition. - In the second step, we build a Toss rewrite rule it... [truncated message content] |
From: <luk...@us...> - 2011-07-06 22:13:41
|
Revision: 1506 http://toss.svn.sourceforge.net/toss/?rev=1506&view=rev Author: lukaszkaiser Date: 2011-07-06 22:13:35 +0000 (Wed, 06 Jul 2011) Log Message: ----------- Small stability bug. Modified Paths: -------------- trunk/Toss/Server/ReqHandler.ml Modified: trunk/Toss/Server/ReqHandler.ml =================================================================== --- trunk/Toss/Server/ReqHandler.ml 2011-07-06 20:07:16 UTC (rev 1505) +++ trunk/Toss/Server/ReqHandler.ml 2011-07-06 22:13:35 UTC (rev 1506) @@ -731,7 +731,7 @@ if line_in = "" || line_in = "\r" then try nonempty () with End_of_file -> "" else line_in in - try nonempty () with Sys_error _ -> "" in + try nonempty () with Sys_blocked_io | Sys_error _ -> "" in let line_in_len = String.length line_in in if line_in_len = 0 then ("", None) else (* TODO: who needs escaping? *) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-06 20:07:22
|
Revision: 1505 http://toss.svn.sourceforge.net/toss/?rev=1505&view=rev Author: lukaszkaiser Date: 2011-07-06 20:07:16 +0000 (Wed, 06 Jul 2011) Log Message: ----------- Hide game descriptions by default. Modified Paths: -------------- trunk/Toss/WebClient/Main.js Modified: trunk/Toss/WebClient/Main.js =================================================================== --- trunk/Toss/WebClient/Main.js 2011-07-06 19:55:23 UTC (rev 1504) +++ trunk/Toss/WebClient/Main.js 2011-07-06 20:07:16 UTC (rev 1505) @@ -200,7 +200,7 @@ document.getElementById (game + "-desc").style.display = "block"; document.getElementById ("game-desc-controls").style.display = "block"; GAME_NAME = game; - if (SIMPLE_SET) { toggle_game_desc (); } + toggle_game_desc (); list_plays (game); document.getElementById ("welcome").style.display = "none"; document.getElementById ("game-disp").style.display = "none"; @@ -330,7 +330,7 @@ function new_play_do (opp_uid) { document.getElementById (GAME_NAME + "-desc").style.display = "block"; document.getElementById ("game-desc-controls").style.display = "block"; - if (SIMPLE_SET) { toggle_game_desc (); } + toggle_game_desc (); list_plays (GAME_NAME); document.getElementById ("welcome").style.display = "none"; document.getElementById ("game-disp").style.display = "none"; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-06 19:55:29
|
Revision: 1504 http://toss.svn.sourceforge.net/toss/?rev=1504&view=rev Author: lukaszkaiser Date: 2011-07-06 19:55:23 +0000 (Wed, 06 Jul 2011) Log Message: ----------- Placeholder for ads. Modified Paths: -------------- trunk/Toss/WebClient/Login.js trunk/Toss/WebClient/Style.css trunk/Toss/WebClient/index.html Modified: trunk/Toss/WebClient/Login.js =================================================================== --- trunk/Toss/WebClient/Login.js 2011-07-05 00:07:39 UTC (rev 1503) +++ trunk/Toss/WebClient/Login.js 2011-07-06 19:55:23 UTC (rev 1504) @@ -46,6 +46,7 @@ if (udata != "") { setup_user (udata.split("@")) }; } if (window.location.href.indexOf("?simple=true") > 0) { + document.getElementById ("ads").style.display = "none"; SIMPLE_SET = true; document.getElementById("gamestablink").href = "index.html?simple=true"; document.getElementById("pdescChess").style.display = "block"; Modified: trunk/Toss/WebClient/Style.css =================================================================== --- trunk/Toss/WebClient/Style.css 2011-07-05 00:07:39 UTC (rev 1503) +++ trunk/Toss/WebClient/Style.css 2011-07-06 19:55:23 UTC (rev 1504) @@ -533,6 +533,16 @@ font-weight: normal; } +#ads { + position: absolute; + top: 6.5em; + right: 0px; + background-color: #f5f2ef; + width: 160px; + height: 600px; + z-index: 99; +} + #main { text-align: left; position: absolute; Modified: trunk/Toss/WebClient/index.html =================================================================== --- trunk/Toss/WebClient/index.html 2011-07-05 00:07:39 UTC (rev 1503) +++ trunk/Toss/WebClient/index.html 2011-07-06 19:55:23 UTC (rev 1504) @@ -19,6 +19,9 @@ <body onload="startup('')"> +<div id="ads"> +</div> + <div id="main"> <div id="top"> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-05 00:07:47
|
Revision: 1503 http://toss.svn.sourceforge.net/toss/?rev=1503&view=rev Author: lukaszkaiser Date: 2011-07-05 00:07:39 +0000 (Tue, 05 Jul 2011) Log Message: ----------- Stability work. Modified Paths: -------------- trunk/Toss/Server/ReqHandler.ml trunk/Toss/Server/Server.ml Modified: trunk/Toss/Server/ReqHandler.ml =================================================================== --- trunk/Toss/Server/ReqHandler.ml 2011-07-03 00:41:39 UTC (rev 1502) +++ trunk/Toss/Server/ReqHandler.ml 2011-07-05 00:07:39 UTC (rev 1503) @@ -777,7 +777,7 @@ | (line, Some (Aux.Right (f, x))) when line = "COMP" -> (match Unix.fork () with | 0 (* child *) -> - if Unix.fork() <> 0 then exit 0; (* double fork trick for zombies *) + (* if Unix.fork() <> 0 then exit 0; double fork trick for zombies *) let res = f x in Marshal.to_channel out_ch res [Marshal.Closures]; flush out_ch; @@ -790,7 +790,7 @@ | Aux.Right (state, future) -> match Unix.fork () with | 0 (* child *) -> - if Unix.fork() <> 0 then exit 0;(* double fork trick, zombies *) + (*if Unix.fork() <> 0 then exit 0; double fork trick, zombies *) report (state, future ()) false | _ (* parent *) -> state, true ) Modified: trunk/Toss/Server/Server.ml =================================================================== --- trunk/Toss/Server/Server.ml 2011-07-03 00:41:39 UTC (rev 1502) +++ trunk/Toss/Server/Server.ml 2011-07-05 00:07:39 UTC (rev 1503) @@ -24,26 +24,31 @@ (* -------------------- GENERAL SERVER AND REQUEST HANDLER ------------------ *) +let rec accept_sock n s = + if n < 1 then failwith "Accept Sock Failed" else + try Unix.accept s with _ -> accept_sock (n-1) s + let start_server f port addr_s = (* Unix.establish_server f (Unix.ADDR_INET (get_inet_addr (addr_s), port)) BUT we do not want a separate process for each [f], we use global state.*) let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in Unix.setsockopt_optint sock Unix.SO_LINGER (Some 2); + Unix.setsockopt_float sock Unix.SO_RCVTIMEO (120.); Unix.setsockopt sock Unix.SO_REUSEADDR true; Unix.bind sock (Unix.ADDR_INET (Aux.get_inet_addr (addr_s), port)); Unix.listen sock 9; (* maximally 9 pending requests *) let continue = ref true in while !continue do - let (cl_sock, _) = Unix.accept sock in + let (cl_sock, _) = accept_sock 99 sock in continue := f (Unix.in_channel_of_descr cl_sock) - (Unix.out_channel_of_descr cl_sock); + (Unix.out_channel_of_descr cl_sock); Unix.close cl_sock; if !continue then (* collect zombies *) try ignore (Unix.waitpid [Unix.WNOHANG] (-1)); with Unix.Unix_error (e,_,_) -> if !debug_level > 1 then Printf.printf "UNIX WAITPID: %s\n%!" (Unix.error_message e); - else Unix.close sock + else (try Unix.close cl_sock with _ -> (); Unix.close sock) done let req_handle in_ch out_ch = This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-03 00:41:45
|
Revision: 1502 http://toss.svn.sourceforge.net/toss/?rev=1502&view=rev Author: lukaszkaiser Date: 2011-07-03 00:41:39 +0000 (Sun, 03 Jul 2011) Log Message: ----------- Stability debugging. Modified Paths: -------------- trunk/Toss/Server/ReqHandler.ml trunk/Toss/Server/Server.ml Modified: trunk/Toss/Server/ReqHandler.ml =================================================================== --- trunk/Toss/Server/ReqHandler.ml 2011-07-02 23:36:25 UTC (rev 1501) +++ trunk/Toss/Server/ReqHandler.ml 2011-07-03 00:41:39 UTC (rev 1502) @@ -777,6 +777,7 @@ | (line, Some (Aux.Right (f, x))) when line = "COMP" -> (match Unix.fork () with | 0 (* child *) -> + if Unix.fork() <> 0 then exit 0; (* double fork trick for zombies *) let res = f x in Marshal.to_channel out_ch res [Marshal.Closures]; flush out_ch; @@ -788,7 +789,9 @@ | Aux.Left ((state, resp)) -> report (state, resp) true | Aux.Right (state, future) -> match Unix.fork () with - | 0 (* child *) -> report (state, future ()) false + | 0 (* child *) -> + if Unix.fork() <> 0 then exit 0;(* double fork trick, zombies *) + report (state, future ()) false | _ (* parent *) -> state, true ) | (_, Some _) -> failwith "Internal ReqHandler Error (full_req_handle)!" Modified: trunk/Toss/Server/Server.ml =================================================================== --- trunk/Toss/Server/Server.ml 2011-07-02 23:36:25 UTC (rev 1501) +++ trunk/Toss/Server/Server.ml 2011-07-03 00:41:39 UTC (rev 1502) @@ -31,7 +31,7 @@ Unix.setsockopt_optint sock Unix.SO_LINGER (Some 2); Unix.setsockopt sock Unix.SO_REUSEADDR true; Unix.bind sock (Unix.ADDR_INET (Aux.get_inet_addr (addr_s), port)); - Unix.listen sock 99; (* maximally 99 pending requests *) + Unix.listen sock 9; (* maximally 9 pending requests *) let continue = ref true in while !continue do let (cl_sock, _) = Unix.accept sock in @@ -39,11 +39,11 @@ (Unix.out_channel_of_descr cl_sock); Unix.close cl_sock; if !continue then (* collect zombies *) - try - ignore (Unix.waitpid [Unix.WNOHANG] (-1)); - with - Unix.Unix_error (e,_,_) -> if !debug_level > 1 then + try ignore (Unix.waitpid [Unix.WNOHANG] (-1)); with + Unix.Unix_error (e,_,_) -> + if !debug_level > 1 then Printf.printf "UNIX WAITPID: %s\n%!" (Unix.error_message e); + else Unix.close sock done let req_handle in_ch out_ch = This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-02 23:36:31
|
Revision: 1501 http://toss.svn.sourceforge.net/toss/?rev=1501&view=rev Author: lukaszkaiser Date: 2011-07-02 23:36:25 +0000 (Sat, 02 Jul 2011) Log Message: ----------- Do not list guest plays. Modified Paths: -------------- trunk/Toss/WebClient/Connect.js Modified: trunk/Toss/WebClient/Connect.js =================================================================== --- trunk/Toss/WebClient/Connect.js 2011-07-02 22:46:56 UTC (rev 1500) +++ trunk/Toss/WebClient/Connect.js 2011-07-02 23:36:25 UTC (rev 1501) @@ -104,6 +104,7 @@ this.get_name = function (uname) { return (srv ("GET_NAME", uname)); } this.list_plays = function (game, uname) { + if (uname == "guest") { return ("[]"); } return (srv ("LIST_PLAYS", game + ", " + uname)); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <luk...@us...> - 2011-07-02 22:47:03
|
Revision: 1500 http://toss.svn.sourceforge.net/toss/?rev=1500&view=rev Author: lukaszkaiser Date: 2011-07-02 22:46:56 +0000 (Sat, 02 Jul 2011) Log Message: ----------- Small corrections and adding game descriptions. Modified Paths: -------------- trunk/Toss/Server/Server.ml trunk/Toss/WebClient/Main.js trunk/Toss/WebClient/Style.css trunk/Toss/WebClient/index.html Added Paths: ----------- trunk/Toss/WebClient/pics/appstore-small.png Modified: trunk/Toss/Server/Server.ml =================================================================== --- trunk/Toss/Server/Server.ml 2011-07-01 23:30:17 UTC (rev 1499) +++ trunk/Toss/Server/Server.ml 2011-07-02 22:46:56 UTC (rev 1500) @@ -41,8 +41,6 @@ if !continue then (* collect zombies *) try ignore (Unix.waitpid [Unix.WNOHANG] (-1)); - ignore (Unix.waitpid [Unix.WNOHANG] (-1)); - ignore (Unix.waitpid [Unix.WNOHANG] (-1)); with Unix.Unix_error (e,_,_) -> if !debug_level > 1 then Printf.printf "UNIX WAITPID: %s\n%!" (Unix.error_message e); Modified: trunk/Toss/WebClient/Main.js =================================================================== --- trunk/Toss/WebClient/Main.js 2011-07-01 23:30:17 UTC (rev 1499) +++ trunk/Toss/WebClient/Main.js 2011-07-02 22:46:56 UTC (rev 1500) @@ -199,11 +199,12 @@ document.getElementById ("opponents").style.display = "none"; document.getElementById (game + "-desc").style.display = "block"; document.getElementById ("game-desc-controls").style.display = "block"; + GAME_NAME = game; + if (SIMPLE_SET) { toggle_game_desc (); } list_plays (game); document.getElementById ("welcome").style.display = "none"; document.getElementById ("game-disp").style.display = "none"; document.getElementById ("plays").style.display = "none"; - GAME_NAME = game; var gd = document.getElementById ("game-disp"); gd.style.display = "block"; gd.setAttribute ("class", "Game-" + game); @@ -329,6 +330,7 @@ function new_play_do (opp_uid) { document.getElementById (GAME_NAME + "-desc").style.display = "block"; document.getElementById ("game-desc-controls").style.display = "block"; + if (SIMPLE_SET) { toggle_game_desc (); } list_plays (GAME_NAME); document.getElementById ("welcome").style.display = "none"; document.getElementById ("game-disp").style.display = "none"; Modified: trunk/Toss/WebClient/Style.css =================================================================== --- trunk/Toss/WebClient/Style.css 2011-07-01 23:30:17 UTC (rev 1499) +++ trunk/Toss/WebClient/Style.css 2011-07-02 22:46:56 UTC (rev 1500) @@ -501,6 +501,8 @@ } #game-desc-controls { + position: relative; + top: -1.5em; display: none; width: 80%; margin: auto; Modified: trunk/Toss/WebClient/index.html =================================================================== --- trunk/Toss/WebClient/index.html 2011-07-01 23:30:17 UTC (rev 1499) +++ trunk/Toss/WebClient/index.html 2011-07-02 22:46:56 UTC (rev 1500) @@ -14,6 +14,7 @@ <script type="text/javascript" src="Play.js"> </script> <script type="text/javascript" src="Main.js"> </script> <script type="text/javascript" src="Login.js"> </script> + <script type="text/javascript" src="https://apis.google.com/js/plusone.js"> </script> </head> <body onload="startup('')"> @@ -87,10 +88,11 @@ <div id="welcome"> <p id="welcome-top">Enjoy the best games on <span class="logo-in">tPlay</span> - for free - <a href="http://itunes.apple.com/us/app/tplay/id438620686"> - <img style="height: 2em; float:right;" src="pics/appstore.png" /> - </a> + for free <span style="float: right;"> + <a href="http://itunes.apple.com/us/app/tplay/id438620686" + ><img style="height: 24px;" src="pics/appstore-small.png" /></a> + <g:plusone></g:plusone> + </span> </p> <p id="p-under-welcome" style="display: none;"> Strategic games are fun! @@ -172,6 +174,7 @@ <div id="news"> <h3>News</h3> <ul id="welcome-list-news" class="welcome-list"> +<li><b>03/07/11</b> Added game descriptions viewable when playing</li> <li><b>30/06/11</b> View previous moves in a play</li> <li><b>27/06/11</b> Tabs and searching opponents in the profile page</li> <li><b>22/06/11</b> Better organized lists of plays</li> @@ -305,10 +308,48 @@ two bishops, and eight pawns. Pieces move in different assigned ways according to their type, and accordingly are used to attack and capture the opponent's pieces. The object of the game is to checkmate - the opponent's king, whereby the king is under immediate attack - (in check) if there is no way to move or defend it.</p> - <p><b>Moves.</b> The moves differ by figure.</p> - <p><b>Objective.</b> Checkmate.</p> + the opponent's king. + <p><b>Moves.</b> The moves differ by figure. Please consult the chess link + above for a complete explanation with examples.</p> + <ul> + <li>The king moves one square in any direction. The king has also + a special move which is called castling and involves moving two fields + towards a rook which has not moved before.</li> + <li>The rook can move any number of squares along any rank or file, + but may not leap over other pieces. Along with the king, the rook, + during the king's castling move, jumps over the king.</li> + <li>The bishop can move any number of squares diagonally, but may not + leap over other pieces.</li> + <li>The queen combines the power of the rook and bishop and can move + any number of squares along rank, file, or diagonal, but it may not + leap over other pieces.</li> + <li>The knight moves to any of the closest squares that are not on + the same rank, file, or diagonal, thus the move forms an L-shape + two squares long and one square wide. The knight is the only piece + that can leap over other pieces.</li> + <li>The pawn may move forward to the unoccupied square immediately + in front of it on the same file; or on its first move it may advance + two squares along the same file provided both squares are unoccupied; + or it may move to a square occupied by an opponent's piece which is + diagonally in front of it on an adjacent file, capturing that piece. + The pawn has two special moves: the en passant capture and pawn + promotion. In the first it captures another pawn which has just made a + two-field move, in the other one it becomes a queen in the last row.</p> + </ul> + <p><b>Objective.</b> + When a king is under immediate attack by one or more of the opponent's + pieces, it is said to be in check. A response to a check is a legal + move if it results in a position where the king is no longer under + direct attack (that is, not in check). This can involve capturing + the checking piece; interposing a piece between the checking piece + and the king (which is possible only if the attacking piece is a queen, + rook, or bishop and there is a square between it and the king); or + moving the king to a square where it is not under attack. Castling is + not a permissible response to a check. It is illegal for + a player to make a move that would put or leave his own king in check. + The objective of the game is to checkmate the opponent; this occurs when + the opponent's king is in check, and there is no legal way to remove it + from attack.</p> </div> <div class="game-desc" id="Connect4-desc"> <p><a href="http://en.wikipedia.org/wiki/Connect4">Connect4</a> (also known Added: trunk/Toss/WebClient/pics/appstore-small.png =================================================================== (Binary files differ) Property changes on: trunk/Toss/WebClient/pics/appstore-small.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |