From 6b649aba925b6f7462da07599fe67ebb12a3460e Mon Sep 17 00:00:00 2001 From: Samuel Mimram Date: Wed, 28 Jul 2004 21:54:47 +0000 Subject: Imported Upstream version 8.0pl1 --- contrib/jprover/README | 76 + contrib/jprover/jall.ml | 4701 +++++++++++++++++++++++++++++++++++++++++++ contrib/jprover/jall.mli | 339 ++++ contrib/jprover/jlogic.ml | 106 + contrib/jprover/jlogic.mli | 40 + contrib/jprover/jprover.ml4 | 565 ++++++ contrib/jprover/jterm.ml | 872 ++++++++ contrib/jprover/jterm.mli | 110 + contrib/jprover/jtunify.ml | 507 +++++ contrib/jprover/jtunify.mli | 35 + contrib/jprover/opname.ml | 90 + contrib/jprover/opname.mli | 15 + 12 files changed, 7456 insertions(+) create mode 100644 contrib/jprover/README create mode 100644 contrib/jprover/jall.ml create mode 100644 contrib/jprover/jall.mli create mode 100644 contrib/jprover/jlogic.ml create mode 100644 contrib/jprover/jlogic.mli create mode 100644 contrib/jprover/jprover.ml4 create mode 100644 contrib/jprover/jterm.ml create mode 100644 contrib/jprover/jterm.mli create mode 100644 contrib/jprover/jtunify.ml create mode 100644 contrib/jprover/jtunify.mli create mode 100644 contrib/jprover/opname.ml create mode 100644 contrib/jprover/opname.mli (limited to 'contrib/jprover') diff --git a/contrib/jprover/README b/contrib/jprover/README new file mode 100644 index 00000000..ec654a03 --- /dev/null +++ b/contrib/jprover/README @@ -0,0 +1,76 @@ +An intuitionistic first-order theorem prover -- JProver. + +Usage: + +Require JProver. +Jp [num]. + +Whem [num] is provided, proof is done automatically with +the multiplicity limit [num], otherwise no limit is forced +and JProver may not terminate. + +Example: + +Require JProver. +Coq < Goal (P:Prop) P->P. +1 subgoal + +============================ + (P:Prop)P->P + +Unnamed_thm < Jp 1. +Proof is built. +Subtree proved! +----------------------------------------- + +Description: +JProver is a theorem prover for first-order intuitionistic logic. +It is originally implemented by Stephan Schmitt and then integrated into +MetaPRL by Aleksey Nogin (see jall.ml). After this, Huang extracted the +necessary ML-codes from MetaPRL and then integrated it into Coq. +The MetaPRL URL is http://metaprl.org/. For more information on +integrating JProver into interactive proof assistants, please refer to + + "Stephan Schmitt, Lori Lorigo, Christoph Kreitz, and Aleksey Nogin, + Jprover: Integrating connection-based theorem proving into interactive + proof assistants. In International Joint Conference on Automated + Reasoning, volume 2083 of Lecture Notes in Artificial Intelligence, + pages 421-426. Springer-Verlag, 2001" - + http://www.cs.cornell.edu/nogin/papers/jprover.html + + +Structure of this directory: +This directory contains + + README ------ this file + jall.ml ------ the main module of JProver + jtunify.ml ------ string unification procedures for jall.ml + jlogic.ml ------ interface module of jall.ml + jterm.ml + opname.ml ------ implement the infrastructure for jall.ml + jprover.ml4 ------ the interface of jall.ml to Coq + JProver.v ------ declaration for Coq + Makefile ------ the makefile + go ------ batch file to load JProver to Coq dynamically + + +Comments: +1. The original is located in meta-prl/refiner/reflib of the +MetaPRL directory. Some parts of this file are modified by Huang. + +2. is also located in meta-prl/refiner/reflib with no modification. + +3. is modified from meta-prl/refiner/reflib/jlogic_sig.mlz. + +4. and are modified from the standard term module +of MetaPRL in meta-prl/refiner/term_std. + +5. The Jp tactic currently cannot prove formula such as + ((x:nat) (P x)) -> (EX y:nat| (P y)), which requires extra constants +in the domain when the left-All rule is applied. + + + +by Huang Guan-Shieng (Guan-Shieng.Huang@lri.fr), March 2002. + + diff --git a/contrib/jprover/jall.ml b/contrib/jprover/jall.ml new file mode 100644 index 00000000..876dc6c0 --- /dev/null +++ b/contrib/jprover/jall.ml @@ -0,0 +1,4701 @@ +(* + * JProver first-order automated prover. See the interface file + * for more information and a list of references for JProver. + * + * ---------------------------------------------------------------- + * + * This file is part of MetaPRL, a modular, higher order + * logical framework that provides a logical programming + * environment for OCaml and other languages. + * + * See the file doc/index.html for information on Nuprl, + * OCaml, and more information about this system. + * + * Copyright (C) 2000 Stephan Schmitt + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Stephan Schmitt + * Modified by: Aleksey Nogin + *) + +(*: All of Huang's modifications of this file are quoted or denoted + by comments followed by a colon. +:*) + +(*: +open Mp_debug + +open Refiner.Refiner +open Term +open TermType +open TermOp +open TermSubst +open TermMan +open RefineError +open Opname +:*) + +open Jterm +open Opname +open Jlogic +open Jtunify + +let ruletable = Jlogic.ruletable + +(*: +let free_var_op = make_opname ["free_variable";"Jprover"] +let jprover_op = make_opname ["string";"Jprover"] +:*) +let free_var_op = make_opname ["free_variable"; "Jprover"] +let jprover_op = make_opname ["jprover"; "string"] + +module JProver (JLogic : JLogicSig) = +struct + type polarity = I | O + + type connective = And | Or | Neg | Imp | All | Ex | At | Null + + type ptype = Alpha | Beta | Gamma | Delta | Phi | Psi | PNull + + type stype = + Alpha_1 | Alpha_2 | Beta_1 | Beta_2 | Gamma_0 | Delta_0 + | Phi_0 | Psi_0 | PNull_0 + + type pos = {name : string; + address : int list; + op : connective; + pol : polarity; + pt : ptype; + st : stype; + label : term} + + type 'pos ftree = + Empty + | NodeAt of 'pos + | NodeA of 'pos * ('pos ftree) array + + type atom = {aname : string; + aaddress : int list; + aprefix : string list; + apredicate : operator; + apol : polarity; + ast : stype; + alabel : term} + + type atom_relations = atom * atom list * atom list +(* all atoms except atom occur in [alpha_set] and [beta_set] of atom*) + +(* beta proofs *) + + type bproof = BEmpty + | RNode of string list * bproof + | CNode of (string * string) + | BNode of string * (string list * bproof) * (string list * bproof) + | AtNode of string * (string * string) + +(* Assume only constants for instantiations, not adapted to terms yet *) + type inf = rule * term * term + +(* proof tree for pretty print and permutation *) + type 'inf ptree = + PEmpty + | PNodeAx of 'inf + | PNodeA of 'inf * 'inf ptree + | PNodeB of 'inf * 'inf ptree * 'inf ptree + + module OrderedAtom = + struct + type t = atom + let compare a1 a2 = if (a1.aname) = (a2.aname) then 0 else + if (a1.aname) < (a2.aname) then -1 else 1 + end + + module AtomSet = Set.Make(OrderedAtom) + + module OrderedString = + struct + type t = string + let compare a1 a2 = if a1 = a2 then 0 else + if a1 < a2 then -1 else 1 + end + + module StringSet = Set.Make(OrderedString) + +(*i let _ = + show_loading "Loading Jall%t" i*) + + let debug_jprover = + create_debug (**) + { debug_name = "jprover"; + debug_description = "Display Jprover operations"; + debug_value = false + } + + let jprover_bug = Invalid_argument "Jprover bug (Jall module)" + +(*****************************************************************) + +(************* printing function *************************************) + +(************ printing T-string unifiers ****************************) + +(* ******* printing ********** *) + + let rec list_to_string s = + match s with + [] -> "" + | f::r -> + f^"."^(list_to_string r) + + let rec print_eqlist eqlist = + match eqlist with + [] -> + print_endline "" + | (atnames,f)::r -> + let (s,t) = f in + let ls = list_to_string s + and lt = list_to_string t in + begin + print_endline ("Atom names: "^(list_to_string atnames)); + print_endline (ls^" = "^lt); + print_eqlist r + end + + let print_equations eqlist = + begin + Format.open_box 0; + Format.force_newline (); + print_endline "Equations:"; + print_eqlist eqlist; + Format.force_newline (); + end + + let rec print_subst sigma = + match sigma with + [] -> + print_endline "" + | f::r -> + let (v,s) = f in + let ls = list_to_string s in + begin + print_endline (v^" = "^ls); + print_subst r + end + + let print_tunify sigma = + let (n,subst) = sigma in + begin + print_endline " "; + print_endline ("MaxVar = "^(string_of_int (n-1))); + print_endline " "; + print_endline "Substitution:"; + print_subst subst; + print_endline " " + end + +(*****************************************************) + +(********* printing atoms and their relations ***********************) + + let print_stype st = + match st with + Alpha_1 -> Format.print_string "Alpha_1" + | Alpha_2 -> Format.print_string "Alpha_2" + | Beta_1 -> Format.print_string "Beta_1" + | Beta_2 -> Format.print_string "Beta_2" + | Gamma_0 -> Format.print_string "Gamma_0" + | Delta_0 -> Format.print_string "Delta_0" + | Phi_0 -> Format.print_string "Phi_0" + | Psi_0 -> Format.print_string "Psi_0" + | PNull_0 -> Format.print_string "PNull_0" + + let print_pol pol = + if pol = O then + Format.print_string "O" + else + Format.print_string "I" + + let rec print_address int_list = + match int_list with + [] -> + Format.print_string "" + | hd::rest -> + begin + Format.print_int hd; + print_address rest + end + + let rec print_prefix prefix_list = + match prefix_list with + [] -> Format.print_string "" + | f::r -> + begin + Format.print_string f; + print_prefix r + end + + let print_atom at tab = + let ({aname=x; aaddress=y; aprefix=z; apredicate=p; apol=a; ast=b; alabel=label}) = at in + begin + Format.print_string ("{aname="^x^"; address="); + print_address y; + Format.print_string "; "; + Format.force_newline (); + Format.print_break (tab+1) (tab+1); + Format.print_string "prefix="; + print_prefix z; + Format.print_string "; predicate=; "; + Format.print_break (tab+1) (tab+1); + Format.print_break (tab+1) (tab+1); + Format.print_string "pol="; + print_pol a; + Format.print_string "; stype="; + print_stype b; + Format.print_string "; arguments=[]"; + Format.print_string "\n alabel="; + print_term stdout label; + Format.print_string "}" + end + + let rec print_atom_list set tab = + match set with + [] -> Format.print_string "" + | (f::r) -> + begin + Format.force_newline (); + Format.print_break (tab) (tab); + print_atom f tab; + print_atom_list r (tab) + end + + let rec print_atom_info atom_relation = + match atom_relation with + [] -> Format.print_string "" + | (a,b,c)::r -> + begin + Format.print_string "atom:"; + Format.force_newline (); + Format.print_break 3 3; + print_atom a 3; + Format.force_newline (); + Format.print_break 0 0; + Format.print_string "alpha_set:"; + print_atom_list b 3; + Format.force_newline (); + Format.print_break 0 0; + Format.print_string "beta_set:"; + print_atom_list c 3; + Format.force_newline (); + Format.force_newline (); + Format.print_break 0 0; + print_atom_info r + end + +(*************** print formula tree, tree ordering etc. ***********) + + let print_ptype pt = + match pt with + Alpha -> Format.print_string "Alpha" + | Beta -> Format.print_string "Beta" + | Gamma -> Format.print_string "Gamma" + | Delta -> Format.print_string "Delta" + | Phi -> Format.print_string "Phi" + | Psi -> Format.print_string "Psi" + | PNull -> Format.print_string "PNull" + + let print_op op = + match op with + At -> Format.print_string "Atom" + | Neg -> Format.print_string "Neg" + | And -> Format.print_string "And" + | Or -> Format.print_string "Or" + | Imp -> Format.print_string "Imp" + | Ex -> Format.print_string "Ex" + | All -> Format.print_string "All" + | Null -> Format.print_string "Null" + + let print_position position tab = + let ({name=x; address=y; op=z; pol=a; pt=b; st=c; label=t}) = position in + begin + Format.print_string ("{name="^x^"; address="); + print_address y; + Format.print_string "; "; + Format.force_newline (); + Format.print_break (tab+1) 0; +(* Format.print_break 0 3; *) + Format.print_string "op="; + print_op z; + Format.print_string "; pol="; + print_pol a; + Format.print_string "; ptype="; + print_ptype b; + Format.print_string "; stype="; + print_stype c; + Format.print_string ";"; + Format.force_newline (); + Format.print_break (tab+1) 0; + Format.print_string "label="; + Format.print_break 0 0; + Format.force_newline (); + Format.print_break tab 0; + print_term stdout t; + Format.print_string "}" + end + + let rec pp_ftree_list tree_list tab = + let rec pp_ftree ftree new_tab = + let dummy = String.make (new_tab-2) ' ' in + match ftree with + Empty -> Format.print_string "" + | NodeAt(position) -> + begin + Format.force_newline (); + Format.print_break new_tab 0; + print_string (dummy^"AtomNode: "); +(* Format.force_newline (); + Format.print_break 0 3; +*) + print_position position new_tab; + Format.force_newline (); + Format.print_break new_tab 0 + end + | NodeA(position,subtrees) -> + let tree_list = Array.to_list subtrees in + begin + Format.force_newline (); + Format.print_break new_tab 0; + Format.print_break 0 0; + print_string (dummy^"InnerNode: "); + print_position position new_tab; + Format.force_newline (); + Format.print_break 0 0; + pp_ftree_list tree_list (new_tab-3) + end + in + let new_tab = tab+5 in + match tree_list with + [] -> Format.print_string "" + | first::rest -> + begin + pp_ftree first new_tab; + pp_ftree_list rest tab + end + + let print_ftree ftree = + begin + Format.open_box 0; + Format.print_break 3 0; + pp_ftree_list [ftree] 0; + Format.print_flush () + end + + let rec stringlist_to_string stringlist = + match stringlist with + [] -> "." + | f::r -> + let rest_s = stringlist_to_string r in + (f^"."^rest_s) + + let rec print_stringlist slist = + match slist with + [] -> + Format.print_string "" + | f::r -> + begin + Format.print_string (f^"."); + print_stringlist r + end + + let rec pp_bproof_list tree_list tab = + let rec pp_bproof ftree new_tab = + let dummy = String.make (new_tab-2) ' ' in + match ftree with + BEmpty -> Format.print_string "" + | CNode((c1,c2)) -> + begin + Format.open_box 0; + Format.force_newline (); + Format.print_break (new_tab-10) 0; + Format.open_box 0; + Format.force_newline (); + Format.print_string (dummy^"CloseNode: connection = ("^c1^","^c2^")"); + Format.print_flush(); +(* Format.force_newline (); + Format.print_break 0 3; +*) + Format.open_box 0; + Format.print_break new_tab 0; + Format.print_flush() + end + | AtNode(posname,(c1,c2)) -> + begin + Format.open_box 0; + Format.force_newline (); + Format.print_break (new_tab-10) 0; + Format.open_box 0; + Format.force_newline (); + Format.print_string (dummy^"AtNode: pos = "^posname^" conneciton = ("^c1^","^c2^")"); + Format.print_flush(); +(* Format.force_newline (); + Format.print_break 0 3; +*) + Format.open_box 0; + Format.print_break new_tab 0; + Format.print_flush() + end + | RNode(alpha_layer,bproof) -> + let alpha_string = stringlist_to_string alpha_layer in + begin + Format.open_box 0; + Format.force_newline (); + Format.print_break new_tab 0; + Format.print_break 0 0; + Format.force_newline (); + Format.print_flush(); + Format.open_box 0; + print_string (dummy^"RootNode: "^alpha_string); + Format.print_flush(); + Format.open_box 0; + Format.print_break 0 0; + Format.print_flush(); + pp_bproof_list [bproof] (new_tab-3) + end + | BNode(posname,(alph1,bproof1),(alph2,bproof2)) -> + let alpha_string1 = stringlist_to_string alph1 + and alpha_string2 = stringlist_to_string alph2 in + begin + Format.open_box 0; + Format.force_newline (); + Format.print_break new_tab 0; + Format.print_break 0 0; + Format.force_newline (); + Format.print_flush(); + Format.open_box 0; + print_string (dummy^"BetaNode: pos = "^posname^" layer1 = "^alpha_string1^" layer2 = "^alpha_string2); + Format.print_flush(); + Format.open_box 0; + Format.print_break 0 0; + Format.print_flush(); + pp_bproof_list [bproof1;bproof2] (new_tab-3) + end + in + let new_tab = tab+5 in + match tree_list with + [] -> Format.print_string "" + | first::rest -> + begin + pp_bproof first new_tab; + pp_bproof_list rest tab + end + + let rec print_pairlist pairlist = + match pairlist with + [] -> Format.print_string "" + | (a,b)::rest -> + begin + Format.print_break 1 1; + Format.print_string ("("^a^","^b^")"); + print_pairlist rest + end + + let print_beta_proof bproof = + begin + Format.open_box 0; + Format.force_newline (); + Format.force_newline (); + Format.print_break 3 0; + pp_bproof_list [bproof] 0; + Format.force_newline (); + Format.force_newline (); + Format.force_newline (); + Format.print_flush () + end + + let rec print_treelist treelist = + match treelist with + [] -> + print_endline "END"; + | f::r -> + begin + print_ftree f; + Format.open_box 0; + print_endline ""; + print_endline ""; + print_endline "NEXT TREE"; + print_endline ""; + print_endline ""; + print_treelist r; + Format.print_flush () + end + + let rec print_set_list set_list = + match set_list with + [] -> "" + | f::r -> + (f.aname)^" "^(print_set_list r) + + let print_set set = + let set_list = AtomSet.elements set in + if set_list = [] then "empty" + else + print_set_list set_list + + let print_string_set set = + let set_list = StringSet.elements set in + print_stringlist set_list + + let rec print_list_sets list_of_sets = + match list_of_sets with + [] -> Format.print_string "" + | (pos,fset)::r -> + begin + Format.print_string (pos^": "); (* first element = node which successors depend on *) + print_stringlist (StringSet.elements fset); + Format.force_newline (); + print_list_sets r + end + + let print_ordering list_of_sets = + begin + Format.open_box 0; + print_list_sets list_of_sets; + Format.print_flush () + end + + let rec print_triplelist triplelist = + match triplelist with + [] -> Format.print_string "" + | ((a,b),i)::rest -> + begin + Format.print_break 1 1; + Format.print_string ("(("^a^","^b^"),"^(string_of_int i)^")"); + print_triplelist rest + end + + let print_pos_n pos_n = + Format.print_int pos_n + + let print_formula_info ftree ordering pos_n = + begin + print_ftree ftree; + Format.open_box 0; + Format.force_newline (); + print_ordering ordering; + Format.force_newline (); + Format.force_newline (); + Format.print_string "number of positions: "; + print_pos_n pos_n; + Format.force_newline (); + print_endline ""; + print_endline ""; + Format.print_flush () + end + +(* print sequent proof tree *) + + let pp_rule (pos,r,formula,term) tab = + let rep = ruletable r in + if List.mem rep ["Alll";"Allr";"Exl";"Exr"] then + begin + Format.open_box 0; +(* Format.force_newline (); *) + Format.print_break tab 0; + Format.print_string (pos^": "^rep^" "); + Format.print_flush (); +(* Format.print_break tab 0; + Format.force_newline (); + Format.print_break tab 0; +*) + + Format.open_box 0; + print_term stdout formula; + Format.print_flush (); + Format.open_box 0; + Format.print_string " "; + Format.print_flush (); + Format.open_box 0; + print_term stdout term; + Format.force_newline (); + Format.force_newline (); + Format.print_flush () + end + else + begin + Format.open_box 0; + Format.print_break tab 0; + Format.print_string (pos^": "^rep^" "); + Format.print_flush (); + Format.open_box 0; +(* Format.print_break tab 0; *) + Format.force_newline (); +(* Format.print_break tab 0; *) + print_term stdout formula; + Format.force_newline () + end + + let last addr = + if addr = "" + then "" + else + String.make 1 (String.get addr (String.length addr-1)) + + let rest addr = + if addr = "" + then "" + else + String.sub addr 0 ((String.length addr) - 1) + + let rec get_r_chain addr = + if addr = "" then + 0 + else + let l = last addr in + if l = "l" then + 0 + else (* l = "r" *) + let rs = rest addr in + 1 + (get_r_chain rs) + + let rec tpp seqtree tab addr = + match seqtree with + | PEmpty -> raise jprover_bug + | PNodeAx(rule) -> + let (pos,r,p,pa) = rule in + begin + pp_rule (pos,r,p,pa) tab; +(* Format.force_newline (); *) +(* let mult = get_r_chain addr in *) +(* Format.print_break 100 (tab - (3 * mult)) *) + end + | PNodeA(rule,left) -> + let (pos,r,p,pa) = rule in + begin + pp_rule (pos,r,p,pa) tab; + tpp left tab addr + end + | PNodeB(rule,left,right) -> + let (pos,r,p,pa) = rule in + let newtab = tab + 3 in + begin + pp_rule (pos,r,p,pa) tab; +(* Format.force_newline (); *) +(* Format.print_break 100 newtab; *) + (tpp left newtab (addr^"l")); + (tpp right newtab (addr^"r")) + end + + let tt seqtree = + begin + Format.open_box 0; + tpp seqtree 0 ""; + Format.force_newline (); + Format.close_box (); + Format.print_newline () + end + +(************ END printing functions *********************************) + +(************ Beta proofs and redundancy deletion **********************) + + let rec remove_dups_connections connection_list = + match connection_list with + [] -> [] + | (c1,c2)::r -> + if (List.mem (c1,c2) r) or (List.mem (c2,c1) r) then + (* only one direction variant of a connection stays *) + remove_dups_connections r + else + (c1,c2)::(remove_dups_connections r) + + let rec remove_dups_list list = + match list with + [] -> [] + | f::r -> + if List.mem f r then + remove_dups_list r + else + f::(remove_dups_list r) + + let beta_pure alpha_layer connections beta_expansions = + let (l1,l2) = List.split connections in + let test_list = l1 @ l2 @ beta_expansions in + begin +(* Format.open_box 0; + print_endline ""; + print_stringlist alpha_layer; + Format.print_flush(); + Format.open_box 0; + print_endline ""; + print_stringlist test_list; + print_endline ""; + Format.print_flush(); +*) + not (List.exists (fun x -> (List.mem x test_list)) alpha_layer) + end + + let rec apply_bproof_purity bproof = + match bproof with + BEmpty -> + raise jprover_bug + | CNode((c1,c2)) -> + bproof,[(c1,c2)],[] + | AtNode(_,(c1,c2)) -> + bproof,[(c1,c2)],[] + | RNode(alpha_layer,subproof) -> + let (opt_subproof,min_connections,beta_expansions) = + apply_bproof_purity subproof in + (RNode(alpha_layer,opt_subproof),min_connections,beta_expansions) + | BNode(pos,(alph1,subp1),(alph2,subp2)) -> + let (opt_subp1,min_conn1,beta_exp1) = apply_bproof_purity subp1 in + if beta_pure alph1 min_conn1 beta_exp1 then + begin +(* print_endline ("Left layer of "^pos); *) + (opt_subp1,min_conn1,beta_exp1) + end + else + let (opt_subp2,min_conn2,beta_exp2) = apply_bproof_purity subp2 in + if beta_pure alph2 min_conn2 beta_exp2 then + begin +(* print_endline ("Right layer of "^pos); *) + (opt_subp2,min_conn2,beta_exp2) + end + else + let min_conn = remove_dups_connections (min_conn1 @ min_conn2) + and beta_exp = remove_dups_list ([pos] @ beta_exp1 @ beta_exp2) in + (BNode(pos,(alph1,opt_subp1),(alph2,opt_subp2)),min_conn,beta_exp) + + let bproof_purity bproof = + let (opt_bproof,min_connections,_) = apply_bproof_purity bproof in + opt_bproof,min_connections + +(*********** split permutation *****************) + + let rec apply_permutation bproof rep_name direction act_blayer = + match bproof with + BEmpty | RNode(_,_) -> + raise jprover_bug + | AtNode(cx,(c1,c2)) -> + bproof,act_blayer + | CNode((c1,c2)) -> + bproof,act_blayer + | BNode(pos,(alph1,subp1),(alph2,subp2)) -> + if rep_name = pos then + let (new_blayer,replace_branch) = + if direction = "left" then + (alph1,subp1) + else (* direciton = "right" *) + (alph2,subp2) + in + (match replace_branch with + CNode((c1,c2)) -> + (AtNode(c1,(c1,c2))),new_blayer (* perform atom expansion at c1 *) + | _ -> + replace_branch,new_blayer + ) + else + let pproof1,new_blayer1 = apply_permutation subp1 rep_name direction act_blayer in + let pproof2,new_blayer2 = apply_permutation subp2 rep_name direction new_blayer1 in + (BNode(pos,(alph1,pproof1),(alph2,pproof2))),new_blayer2 + + let split_permutation pname opt_bproof = + match opt_bproof with + RNode(alayer,BNode(pos,(alph1,opt_subp1),(alph2,opt_subp2))) -> + if pos = pname then +(* if topmost beta expansion agrees with pname, then *) +(* only split the beta proof and give back the two subproofs *) + let (osubp1,min_con1) = bproof_purity opt_subp1 + and (osubp2,min_con2) = bproof_purity opt_subp2 in +(* there will be no purity reductions in the beta subproofs. We use this *) +(* predicate to collect the set of used leaf-connections in each subproof*) + ((RNode((alayer @ alph1),osubp1),min_con1), + (RNode((alayer @ alph2),osubp2),min_con2) + ) +(* we combine the branch after topmost beta expansion at pos into one root alpha layer *) +(* -- the beta expansion node pos will not be needed in this root layer *) + else + let perm_bproof1,balph1 = apply_permutation + (BNode(pos,(alph1,opt_subp1),(alph2,opt_subp2))) pname "left" [] + and perm_bproof2,balph2 = apply_permutation + (BNode(pos,(alph1,opt_subp1),(alph2,opt_subp2))) pname "right" [] in + + begin +(* print_endline " "; + print_beta_proof perm_bproof1; + print_endline" " ; + print_beta_proof perm_bproof2; + print_endline" "; +*) + let (osubp1,min_con1) = bproof_purity perm_bproof1 + and (osubp2,min_con2) = bproof_purity perm_bproof2 in + ((RNode((alayer @ balph1),osubp1),min_con1), + (RNode((alayer @ balph2),osubp2),min_con2) + ) + end +(* we combine the branch after the NEW topmost beta expansion at bpos *) +(* into one root alpha layer -- the beta expansion node bpos will not be *) +(* needed in this root layer *) + | _ -> + raise jprover_bug + +(*********** END split permutation *****************) + + let rec list_del list_el el_list = + match el_list with + [] -> + raise jprover_bug + | f::r -> + if list_el = f then + r + else + f::(list_del list_el r) + + let rec list_diff del_list check_list = + match del_list with + [] -> + [] + | f::r -> + if List.mem f check_list then + list_diff r check_list + else + f::(list_diff r check_list) + +(* let rec compute_alpha_layer ftree_list = + match ftree_list with + [] -> + [],[],[] + | f::r -> + (match f with + Empty -> + raise jprover_bug + | NodeAt(pos) -> + let pn = pos.name + and (rnode,ratom,borderings) = compute_alpha_layer r in + ((pn::rnode),(pn::ratom),borderings) + | NodeA(pos,suctrees) -> + let pn = pos.name in + if pos.pt = Beta then + let (rnode,ratom,borderings) = compute_alpha_layer r in + ((pn::rnode),(ratom),(f::borderings)) + else + let suclist = Array.to_list suctrees in + compute_alpha_layer (suclist @ r) + ) + + let rec compute_connection alpha_layer union_atoms connections = + match connections with + [] -> ("none","none") + | (c,d)::r -> + if (List.mem c union_atoms) & (List.mem d union_atoms) then + let (c1,c2) = + if List.mem c alpha_layer then + (c,d) + else + if List.mem d alpha_layer then + (d,c) (* then, d is supposed to occur in [alpha_layer] *) + else + raise (Invalid_argument "Jprover bug: connection match failure") + in + (c1,c2) + else + compute_connection alpha_layer union_atoms r + + let get_beta_suctrees btree = + match btree with + Empty | NodeAt(_) -> raise jprover_bug + | NodeA(pos,suctrees) -> + let b1tree = suctrees.(0) + and b2tree = suctrees.(1) in + (pos.name,b1tree,b2tree) + + let rec build_beta_proof alpha_layer union_atoms beta_orderings connections = + let (c1,c2) = compute_connection alpha_layer union_atoms connections in +(* [c1] is supposed to occur in the lowmost alpha layer of the branch, *) +(* i.e. [aplha_layer] *) + if (c1,c2) = ("none","none") then + (match beta_orderings with + [] -> raise jprover_bug + | btree::r -> + let (beta_pos,suctree1,suctree2) = get_beta_suctrees btree in + let (alpha_layer1, atoms1, bordering1) = compute_alpha_layer [suctree1] + and (alpha_layer2, atoms2, bordering2) = compute_alpha_layer [suctree2] in + let bproof1,beta1,closure1 = + build_beta_proof alpha_layer1 (atoms1 @ union_atoms) + (bordering1 @ r) connections + in + let bproof2,beta2,closure2 = + build_beta_proof alpha_layer2 (atoms2 @ union_atoms) + (bordering2 @ r) connections in + (BNode(beta_pos,(alpha_layer1,bproof1),(alpha_layer2,bproof2))),(1+beta1+beta2),(closure1+closure2) + ) + else + CNode((c1,c2)),0,1 + + let construct_beta_proof ftree connections = + let (root_node,root_atoms,beta_orderings) = compute_alpha_layer [ftree] + in + let beta_proof,beta_exp,closures = + build_beta_proof root_node root_atoms beta_orderings connections in + (RNode(root_node,beta_proof)),beta_exp,closures +*) + + +(* *********** New Version with direct computation from extension proof **** *) +(* follows a DIRECT step from proof histories via pr-connection orderings to opt. beta-proofs *) + + let rec compute_alpha_layer ftree_list = + match ftree_list with + [] -> + [] + | f::r -> + (match f with + Empty -> + raise jprover_bug + | NodeAt(pos) -> + let rnode = compute_alpha_layer r in + (pos.name::rnode) + | NodeA(pos,suctrees) -> + if pos.pt = Beta then + let rnode = compute_alpha_layer r in + (pos.name::rnode) + else + let suclist = Array.to_list suctrees in + compute_alpha_layer (suclist @ r) + ) + + let rec compute_beta_difference c1_context c2_context act_context = + match c1_context,c2_context with + ([],c2_context) -> + (list_diff c2_context act_context) +(* both connection partners in the same submatrix; [c1] already isolated *) + | ((fc1::rc1),[]) -> + [] (* [c2] is a reduction step, i.e. isolated before [c1] *) + | ((fc1::rc1),(fc2::rc2)) -> + if fc1 = fc2 then (* common initial beta-expansions *) + compute_beta_difference rc1 rc2 act_context + else + (list_diff c2_context act_context) + + let rec non_closed beta_proof_list = + match beta_proof_list with + [] -> + false + | bpf::rbpf -> + (match bpf with + RNode(_,_) -> raise (Invalid_argument "Jprover bug: invalid beta-proof") + | AtNode(_,_) -> raise (Invalid_argument "Jprover bug: invalid beta-proof") + | BEmpty -> true + | CNode(_) -> non_closed rbpf + | BNode(pos,(_,bp1),(_,bp2)) -> non_closed ([bp1;bp2] @ rbpf) + ) + + let rec cut_context pos context = + match context with + [] -> + raise (Invalid_argument "Jprover bug: invalid context element") + | (f,num)::r -> + if pos = f then + context + else + cut_context pos r + + let compute_tree_difference beta_proof c1_context = + match beta_proof with + RNode(_,_) -> raise (Invalid_argument "Jprover bug: invalid beta-proof") + | CNode(_) -> raise (Invalid_argument "Jprover bug: invalid beta-proof") + | AtNode(_,_) -> raise (Invalid_argument "Jprover bug: invalid beta-proof") + | BEmpty -> c1_context + | BNode(pos,_,_) -> +(* print_endline ("actual root: "^pos); *) + cut_context pos c1_context + + let print_context conn bcontext = + begin + Format.open_box 0; + Format.print_string conn; + Format.print_string ": "; + List.iter (fun x -> let (pos,num) = x in Format.print_string (pos^" "^(string_of_int num)^"")) bcontext; + print_endline " "; + Format.print_flush () + end + + let rec build_opt_beta_proof beta_proof ext_proof beta_atoms beta_layer_list act_context = + let rec add_c2_tree (c1,c2) c2_diff_context = + match c2_diff_context with + [] -> + (CNode(c1,c2),0) + | (f,num)::c2_diff_r -> + let next_beta_proof,next_exp = + add_c2_tree (c1,c2) c2_diff_r in + let (layer1,layer2) = List.assoc f beta_layer_list in + let new_bproof = + if num = 1 then + BNode(f,(layer1,next_beta_proof),(layer2,BEmpty)) + else (* num = 2*) + BNode(f,(layer1,BEmpty),(layer2,next_beta_proof)) + in + (new_bproof,(next_exp+1)) + in + let rec add_beta_expansions (c1,c2) rest_ext_proof c1_diff_context c2_diff_context new_act_context = + match c1_diff_context with + [] -> + let (n_c1,n_c2) = + if c2_diff_context = [] then (* make sure that leaf-connection is first element *) + (c1,c2) + else + (c2,c1) + in + let c2_bproof,c2_exp = add_c2_tree (n_c1,n_c2) c2_diff_context in + if c2_exp <> 0 then (* at least one open branch was generated to isloate [c2] *) + begin +(* print_endline "start with new beta-proof"; *) + let new_bproof,new_exp,new_closures,new_rest_proof = + build_opt_beta_proof c2_bproof rest_ext_proof beta_atoms beta_layer_list (act_context @ new_act_context) in + (new_bproof,(new_exp+c2_exp),(new_closures+1),new_rest_proof) + end + else + begin +(* print_endline "proceed with old beta-proof"; *) + (c2_bproof,c2_exp,1,rest_ext_proof) + end + | (f,num)::c1_diff_r -> + let (layer1,layer2) = List.assoc f beta_layer_list in + let next_beta_proof,next_exp,next_closures,next_ext_proof = + add_beta_expansions (c1,c2) rest_ext_proof c1_diff_r c2_diff_context new_act_context in + let new_bproof = + if num = 1 then + BNode(f,(layer1,next_beta_proof),(layer2,BEmpty)) + else (* num = 2*) + BNode(f,(layer1,BEmpty),(layer2,next_beta_proof)) + in + (new_bproof,(next_exp+1),next_closures,next_ext_proof) + + in + let rec insert_connection beta_proof (c1,c2) rest_ext_proof c1_diff_context c2_diff_context act_context = + begin +(* print_context c1 c1_diff_context; + print_endline ""; + print_context c2 c2_diff_context; + print_endline ""; +*) + match beta_proof with + RNode(_,_) -> raise (Invalid_argument "Jprover bug: invalid beta-proof") + | CNode(_) -> raise (Invalid_argument "Jprover bug: invalid beta-proof") + | AtNode(_,_) -> raise (Invalid_argument "Jprover bug: invalid beta-proof") + | BEmpty -> + add_beta_expansions (c1,c2) rest_ext_proof c1_diff_context c2_diff_context act_context + | BNode(pos,(layer1,sproof1),(layer2,sproof2)) -> +(* print_endline (c1^" "^c2^" "^pos); *) + (match c1_diff_context with + [] -> + raise (Invalid_argument "Jprover bug: invalid beta-proof") + | (f,num)::rest_context -> (* f = pos must hold!! *) + if num = 1 then + let (next_bproof,next_exp,next_closure,next_ext_proof) = + insert_connection sproof1 (c1,c2) rest_ext_proof rest_context c2_diff_context act_context in + (BNode(pos,(layer1,next_bproof),(layer2,sproof2)),next_exp,next_closure,next_ext_proof) + else (* num = 2 *) + let (next_bproof,next_exp,next_closure,next_ext_proof) = + insert_connection sproof2 (c1,c2) rest_ext_proof rest_context c2_diff_context act_context in + (BNode(pos,(layer1,sproof1),(layer2,next_bproof)),next_exp,next_closure,next_ext_proof) + ) + end + + in + match ext_proof with + [] -> + beta_proof,0,0,[] + | (c1,c2)::rproof -> +(* print_endline ("actual connection: "^c1^" "^c2); *) + let c1_context = List.assoc c1 beta_atoms + and c2_context = List.assoc c2 beta_atoms in + let c2_diff_context = compute_beta_difference c1_context c2_context act_context + and c1_diff_context = compute_tree_difference beta_proof c1_context in (* wrt. actual beta-proof *) + let (next_beta_proof,next_exp,next_closures,next_ext_proof) = + insert_connection beta_proof (c1,c2) rproof c1_diff_context c2_diff_context c1_diff_context in + if non_closed [next_beta_proof] then (* at least one branch was generated to isolate [c1] *) + let rest_beta_proof,rest_exp,rest_closures,rest_ext_proof = + build_opt_beta_proof next_beta_proof next_ext_proof beta_atoms beta_layer_list act_context in + rest_beta_proof,(next_exp+rest_exp),(next_closures+rest_closures),rest_ext_proof + else + next_beta_proof,next_exp,next_closures,next_ext_proof + + let rec annotate_atoms beta_context atlist treelist = + let rec annotate_tree beta_context tree atlist = + match tree with + Empty -> + (atlist,[],[]) + | NodeAt(pos) -> + if List.mem pos.name atlist then + let new_atlist = list_del pos.name atlist in + (new_atlist,[(pos.name,beta_context)],[]) + else + (atlist,[],[]) + | NodeA(pos,suctrees) -> + if pos.pt = Beta then + let s1,s2 = suctrees.(0),suctrees.(1) in + let alayer1 = compute_alpha_layer [s1] + and alayer2 = compute_alpha_layer [s2] + and new_beta_context1 = beta_context @ [(pos.name,1)] + and new_beta_context2 = beta_context @ [(pos.name,2)] in + let atlist1,annotates1,blayer_list1 = + annotate_atoms new_beta_context1 atlist [s1] in + let atlist2,annotates2,blayer_list2 = + annotate_atoms new_beta_context2 atlist1 [s2] + in + (atlist2,(annotates1 @ annotates2),((pos.name,(alayer1,alayer2))::(blayer_list1 @ blayer_list2))) + else + annotate_atoms beta_context atlist (Array.to_list suctrees) + in + match treelist with + [] -> (atlist,[],[]) + | f::r -> + let (next_atlist,f_annotates,f_beta_layers) = annotate_tree beta_context f atlist in + let (rest_atlist,rest_annotates,rest_beta_layers) = (annotate_atoms beta_context next_atlist r) + in + (rest_atlist, (f_annotates @ rest_annotates),(f_beta_layers @ rest_beta_layers)) + + let construct_opt_beta_proof ftree ext_proof = + let con1,con2 = List.split ext_proof in + let con_atoms = remove_dups_list (con1 @ con2) in + let (empty_atoms,beta_atoms,beta_layer_list) = annotate_atoms [] con_atoms [ftree] in + let root_node = compute_alpha_layer [ftree] in + let (beta_proof,beta_exp,closures,_) = + build_opt_beta_proof BEmpty ext_proof beta_atoms beta_layer_list [] in + (RNode(root_node,beta_proof)),beta_exp,closures + +(************* permutation ljmc -> lj *********************************) + +(* REAL PERMUTATION STAFF *) + + let subf1 n m subrel = List.mem ((n,m),1) subrel + let subf2 n m subrel = List.mem ((n,m),2) subrel + let tsubf n m tsubrel = List.mem (n,m) tsubrel + +(* Transforms all normal form layers in an LJ proof *) + + let rec modify prooftree (subrel,tsubrel) = + match prooftree with + PEmpty -> + raise jprover_bug + | PNodeAx((pos,inf,form,term)) -> + prooftree,pos + | PNodeA((pos,inf,form,term),left) -> + let t,qpos = modify left (subrel,tsubrel) in + if List.mem inf [Impr;Negr;Allr] then + PNodeA((pos,inf,form,term),t),pos (* layer bound *) + else if qpos = "Orl-True" then + PNodeA((pos,inf,form,term),t),qpos + else if List.mem inf [Andl;Alll;Exl] then + PNodeA((pos,inf,form,term),t),qpos (* simply propagation *) + else if inf = Exr then + if (subf1 pos qpos subrel) then + PNodeA((pos,inf,form,term),t),pos + else t,qpos + else if inf = Negl then + if (subf1 pos qpos subrel) then + PNodeA((pos,inf,form,term),t),"" (* empty string *) + else t,qpos + else (* x = Orr *) + if (subf1 pos qpos subrel) then + PNodeA((pos,Orr1,form,term),t),pos (* make Orr for LJ *) + else if (subf2 pos qpos subrel) then + PNodeA((pos,Orr2,form,term),t),pos (* make Orr for LJ *) + else t,qpos + | PNodeB((pos,inf,form,term),left,right) -> + let t,qpos = modify left (subrel,tsubrel) in + if inf = Andr then + if (or) (qpos = "Orl-True") (subf1 pos qpos subrel) then + let s,rpos = modify right (subrel,tsubrel) in (* Orl-True -> subf *) + if (or) (rpos = "Orl-True") (subf2 pos rpos subrel) then + PNodeB((pos,inf,form,term),t,s),pos + else s,rpos + else t,qpos (* not subf -> not Orl-True *) + else if inf = Impl then + if (subf1 pos qpos subrel) then + let s,rpos = modify right (subrel,tsubrel) in + PNodeB((pos,inf,form,term),t,s),"" (* empty string *) + else t,qpos + else (* x = Orl *) + let s,rpos = modify right (subrel,tsubrel) in + PNodeB((pos,inf,form,term),t,s),"Orl-True" + +(* transforms the subproof into an LJ proof between + the beta-inference rule (excluded) and + layer boundary in the branch ptree *) + + let rec rec_modify ptree (subrel,tsubrel) = + match ptree with + PEmpty -> + raise jprover_bug + | PNodeAx((pos,inf,form,term)) -> + ptree,pos + | PNodeA((pos,inf,form,term),left) -> + if List.mem inf [Impr;Negr;Allr] then + ptree,pos (* layer bound, stop transforming! *) + else + let t,qpos = rec_modify left (subrel,tsubrel) in + if List.mem inf [Andl;Alll;Exl] then + PNodeA((pos,inf,form,term),t),qpos (* simply propagation*) + else if inf = Exr then + if (subf1 pos qpos subrel) then + PNodeA((pos,inf,form,term),t),pos + else t,qpos + else if inf = Negl then + if (subf1 pos qpos subrel) then + PNodeA((pos,inf,form,term),t),"" (* empty string *) + else t,qpos + else (* x = Orr *) + if (subf1 pos qpos subrel) then + PNodeA((pos,Orr1,form,term),t),pos (* make Orr for LJ *) + else if (subf2 pos qpos subrel) then + PNodeA((pos,Orr2,form,term),t),pos (* make Orr for LJ *) + else t,qpos + | PNodeB((pos,inf,form,term),left,right) -> + let t,qpos = rec_modify left (subrel,tsubrel) in + if inf = Andr then + if (subf1 pos qpos subrel) then + let s,rpos = rec_modify right (subrel,tsubrel) in + if (subf2 pos rpos subrel) then + PNodeB((pos,inf,form,term),t,s),pos + else s,rpos + else t,qpos + else (* x = Impl since x= Orl cannot occur in the partial layer ptree *) + + if (subf1 pos qpos subrel) then + let s,rpos = rec_modify right (subrel,tsubrel) in + PNodeB((pos,inf,form,term),t,s),"" (* empty string *) + else t,qpos + + let weak_modify rule ptree (subrel,tsubrel) = (* recall rule = or_l *) + let (pos,inf,formlua,term) = rule in + if inf = Orl then + ptree,true + else + let ptreem,qpos = rec_modify ptree (subrel,tsubrel) in + if (subf1 pos qpos subrel) then (* weak_modify will always be applied on left branches *) + ptreem,true + else + ptreem,false + +(* Now, the permutation stuff .... *) + +(* Permutation schemes *) + +(* corresponds to local permutation lemma -- Lemma 3 in the paper -- *) +(* with eigenvariablen renaming and branch modification *) + +(* eigenvariablen renaming and branch modification over *) +(* the whole proofs, i.e. over layer boundaries, too *) + + +(* global variable vor eigenvariable renaming during permutations *) + + let eigen_counter = ref 1 + +(* append renamed paramater "r" to non-quantifier subformulae + of renamed quantifier formulae *) + +(*: BUG :*) +(*: + let make_new_eigenvariable term = + let op = (dest_term term).term_op in + let opn = (dest_op op).op_name in + let opnam = dest_opname opn in + match opnam with + [] -> + raise jprover_bug + | ofirst::orest -> + let ofname = List.hd orest in + let new_eigen_var = (ofname^"_r"^(string_of_int (!eigen_counter))) in + eigen_counter := !eigen_counter + 1; +(* print_endline ("New Counter :"^(string_of_int (!eigen_counter))); *) + mk_string_term jprover_op new_eigen_var +:*) + + let make_new_eigenvariable term = + let op = (dest_term term).term_op in + let opa = (dest_op op).op_params in + let oppar = dest_param opa in + match oppar with + | String ofname::_ -> + let new_eigen_var = (ofname^"_r"^(string_of_int (!eigen_counter))) in + eigen_counter := !eigen_counter + 1; + mk_string_term jprover_op new_eigen_var + | _ -> raise jprover_bug + + + let replace_subterm term oldt rept = + let v_term = var_subst term oldt "dummy_var" in + subst1 v_term "dummy_var" rept + + let rec eigen_rename old_parameter new_parameter ptree = + match ptree with + PEmpty -> + raise jprover_bug + | PNodeAx((pos,inf,form,term)) -> + let new_form = replace_subterm form old_parameter new_parameter in + PNodeAx((pos,inf,new_form,term)) + | PNodeA((pos,inf,form,term), left) -> + let new_form = replace_subterm form old_parameter new_parameter + and new_term = replace_subterm term old_parameter new_parameter in + let ren_left = eigen_rename old_parameter new_parameter left in + PNodeA((pos,inf,new_form,new_term), ren_left) + | PNodeB((pos,inf,form,term),left, right) -> + let new_form = replace_subterm form old_parameter new_parameter in + let ren_left = eigen_rename old_parameter new_parameter left in + let ren_right = eigen_rename old_parameter new_parameter right in + PNodeB((pos,inf,new_form,term), ren_left, ren_right) + + let rec update_ptree rule subtree direction tsubrel = + match subtree with + PEmpty -> + raise jprover_bug + | PNodeAx(r) -> + subtree + | PNodeA((pos,inf,formula,term), left) -> + if (pos,inf,formula,term) = rule then + left + (* don't delete rule if subformula belongs to renamed instance of quantifiers; *) + (* but this can never occur now since (renamed) formula is part of rule *) + else + let (posn,infn,formn,termn) = rule in + if (&) (List.mem infn [Exl;Allr] ) (term = termn) then + (* this can only occur if eigenvariable rule with same term as termn has been permuted; *) + (* the application of the same eigenvariable introduction on the same subformula with *) + (* different instantiated variables might occur! *) + (* termn cannot occur in terms of permuted quantifier rules due to substitution split *) + (* during reconstruciton of the ljmc proof *) + let new_term = make_new_eigenvariable term in +(* print_endline "Eigenvariable renaming!!!"; *) + eigen_rename termn new_term subtree + else + let left_del = + update_ptree rule left direction tsubrel + in + PNodeA((pos,inf,formula,term), left_del) + | PNodeB((pos,inf,formula,term), left, right) -> + if (pos,inf,formula,term) = rule then + if direction = "l" then + left + else + right (* direction = "r" *) + else + let left_del = update_ptree rule left direction tsubrel in + let right_del = update_ptree rule right direction tsubrel in + PNodeB((pos,inf,formula,term),left_del,right_del) + + let permute r1 r2 ptree la tsubrel = +(* print_endline "permute in"; *) + match ptree,la with + PNodeA(r1, PNodeA(r2,left)),la -> +(* print_endline "1-o-1"; *) + PNodeA(r2, PNodeA(r1,left)) + (* one-over-one *) + | PNodeA(r1, PNodeB(r2,left,right)),la -> +(* print_endline "1-o-2"; *) + PNodeB(r2, PNodeA(r1,left), PNodeA(r1,right)) + (* one-over-two *) + | PNodeB(r1, PNodeA(r2,left), right),"l" -> +(* print_endline "2-o-1 left"; *) + let right_u = update_ptree r2 right "l" tsubrel in + PNodeA(r2, PNodeB(r1, left, right_u)) + (* two-over-one left *) + | PNodeB(r1, left, PNodeA(r2,right)),"r" -> +(* print_endline "2-o-1 right"; *) + let left_u = update_ptree r2 left "l" tsubrel in + PNodeA(r2, PNodeB(r1, left_u, right)) + (* two-over-one right *) + | PNodeB(r1, PNodeB(r2,left2,right2), right),"l" -> +(* print_endline "2-o-2 left"; *) + let right_ul = update_ptree r2 right "l" tsubrel in + let right_ur = update_ptree r2 right "r" tsubrel in + PNodeB(r2,PNodeB(r1,left2,right_ul),PNodeB(r1,right2,right_ur)) + (* two-over-two left *) + | PNodeB(r1, left, PNodeB(r2,left2,right2)),"r" -> +(* print_endline "2-o-2 right"; *) + let left_ul = update_ptree r2 left "l" tsubrel in + let left_ur = update_ptree r2 left "r" tsubrel in + PNodeB(r2,PNodeB(r1,left_ul,left2),PNodeB(r1,left_ur, right2)) + (* two-over-two right *) + | _ -> raise jprover_bug + +(* permute layers, isolate addmissible branches *) + +(* computes if an Andr is d-generatives *) + + let layer_bound rule = + let (pos,inf,formula,term) = rule in + if List.mem inf [Impr;Negr;Allr] then + true + else + false + + let rec orl_free ptree = + match ptree with + PEmpty -> + raise jprover_bug + | PNodeAx(rule) -> + true + | PNodeA(rule,left) -> + if layer_bound rule then + true + else + orl_free left + | PNodeB(rule,left,right) -> + let (pos,inf,formula,term) = rule in + if inf = Orl then + false + else + (&) (orl_free left) (orl_free right) + + let rec dgenerative rule dglist ptree tsubrel = + let (pos,inf,formula,term) = rule in + if List.mem inf [Exr;Orr;Negl] then + true + else if inf = Andr then + if dglist = [] then + false + else + let first,rest = (List.hd dglist),(List.tl dglist) in + let (pos1,inf1,formula1,term1) = first in + if tsubf pos1 pos tsubrel then + true + else + dgenerative rule rest ptree tsubrel + else if inf = Impl then + not (orl_free ptree) + else + false + + +(* to compute a topmost addmissible pair r,o with + the address addr of r in the proof tree +*) + + let rec top_addmissible_pair ptree dglist act_r act_o act_addr tsubrel dummyt = + let rec search_pair ptree dglist act_r act_o act_addr tsubrel = + match ptree with + PEmpty -> raise jprover_bug + | PNodeAx(_) -> raise jprover_bug + | PNodeA(rule, left) -> +(* print_endline "alpha"; *) + if (dgenerative rule dglist left tsubrel) then (* r = Exr,Orr,Negl *) + let newdg = (@) [rule] dglist in + search_pair left newdg act_r rule act_addr tsubrel + else (* Impr, Allr, Notr only for test *) + search_pair left dglist act_r act_o act_addr tsubrel + | PNodeB(rule,left,right) -> +(* print_endline "beta"; *) + let (pos,inf,formula,term) = rule in + if List.mem inf [Andr;Impl] then + let bool = dgenerative rule dglist left tsubrel in + let newdg,newrule = + if bool then + ((@) [rule] dglist),rule + else + dglist,act_o + in + if orl_free left then + search_pair right newdg act_r newrule (act_addr^"r") tsubrel + else (* not orl_free *) + let left_r,left_o,left_addr = + search_pair left newdg act_r newrule (act_addr^"l") tsubrel in + if left_o = ("",Orr,dummyt,dummyt) then + top_addmissible_pair right dglist act_r act_o (act_addr^"r") tsubrel dummyt + else left_r,left_o,left_addr + else (* r = Orl *) + if orl_free left then + top_addmissible_pair right dglist rule act_o (act_addr^"r") tsubrel dummyt + else + let left_r,left_o,left_addr + = search_pair left dglist rule act_o (act_addr^"l") tsubrel in + if left_o = ("",Orr,dummyt,dummyt) then + top_addmissible_pair right dglist rule act_o (act_addr^"r") tsubrel dummyt + else + left_r,left_o,left_addr + in +(* print_endline "top_addmissible_pair in"; *) + if orl_free ptree then (* there must be a orl BELOW an layer bound *) + begin +(* print_endline "orl_free"; *) + act_r,act_o,act_addr + end + else + begin +(* print_endline "orl_full"; *) + search_pair ptree dglist act_r act_o act_addr tsubrel + end + + let next_direction addr act_addr = + String.make 1 (String.get addr (String.length act_addr)) + (* get starts with count 0*) + + let change_last addr d = + let split = (String.length addr) - 1 in + let prec,last = + (String.sub addr 0 split),(String.sub addr split 1) in + prec^d^last + + let last addr = + if addr = "" + then "" + else + String.make 1 (String.get addr (String.length addr-1)) + + let rest addr = + if addr = "" + then "" + else + String.sub addr 0 ((String.length addr) - 1) + + let rec permute_layer ptree dglist (subrel,tsubrel) = + let rec permute_branch r addr act_addr ptree dglist (subrel,tsubrel) = +(* print_endline "pbranch in"; *) + let la = last act_addr in (* no ensure uniqueness at 2-over-x *) + match ptree,la with + PNodeA(o,PNodeA(rule,left)),la -> (* one-over-one *) +(* print_endline " one-over-one "; *) + let permute_result = permute o rule ptree la tsubrel in + begin match permute_result with + PNodeA(r2,left2) -> + let pbleft = permute_branch r addr act_addr left2 dglist (subrel,tsubrel) in + PNodeA(r2,pbleft) + | _ -> raise jprover_bug + end + | PNodeA(o,PNodeB(rule,left,right)),la -> (* one-over-two *) +(* print_endline " one-over-two "; *) + if rule = r then (* left,right are or_l free *) + permute o rule ptree la tsubrel (* first termination case *) + else + let d = next_direction addr act_addr in + if d = "l" then + let permute_result = permute o rule ptree la tsubrel in + (match permute_result with + PNodeB(r2,left2,right2) -> + let pbleft = permute_branch r addr (act_addr^d) left2 dglist (subrel,tsubrel) in + let plright = permute_layer right2 dglist (subrel,tsubrel) in + PNodeB(r2,pbleft,plright) + | _ -> raise jprover_bug + ) + else (* d = "r", that is left of rule is or_l free *) + let left1,bool = weak_modify rule left (subrel,tsubrel) in + if bool then (* rule is relevant *) + let permute_result = permute o rule (PNodeA(o,PNodeB(rule,left1,right))) la tsubrel in + (match permute_result with + PNodeB(r2,left2,right2) -> + let pbright = permute_branch r addr (act_addr^d) right2 dglist (subrel,tsubrel) in + PNodeB(r2,left2,pbright) + | _ -> raise jprover_bug + ) + else (* rule is not relevant *) + PNodeA(o,left1) (* optimized termination case (1) *) + | PNodeB(o,PNodeA(rule,left),right1),"l" -> (* two-over-one, left *) +(* print_endline " two-over-one, left "; *) + let permute_result = permute o rule ptree la tsubrel in + (match permute_result with + PNodeA(r2,left2) -> + let pbleft = permute_branch r addr act_addr left2 dglist (subrel,tsubrel) in + PNodeA(r2,pbleft) + | _ -> raise jprover_bug + ) + | PNodeB(o,left1,PNodeA(rule,left)),"r" -> (* two-over-one, right *) + (* left of o is or_l free *) +(* print_endline " two-over-one, right"; *) + let leftm,bool = weak_modify o left1 (subrel,tsubrel) in + if bool then (* rule is relevant *) + let permute_result = permute o rule (PNodeB(o,leftm,PNodeA(rule,left))) la tsubrel in + (match permute_result with + PNodeA(r2,left2) -> + let pbleft = permute_branch r addr act_addr left2 dglist (subrel,tsubrel) in + PNodeA(r2,pbleft) + | _ -> raise jprover_bug + ) + else (* rule is not relevant *) + leftm (* optimized termination case (2) *) + | PNodeB(o,PNodeB(rule,left,right),right1),"l" -> (* two-over-two, left *) +(* print_endline " two-over-two, left"; *) + if rule = r then (* left,right are or_l free *) + let permute_result = permute o rule ptree la tsubrel in + (match permute_result with + PNodeB(r2,PNodeB(r3,left3,right3),PNodeB(r4,left4,right4)) -> +(* print_endline "permute 2-o-2, left ok"; *) + let leftm3,bool3 = weak_modify r3 left3 (subrel,tsubrel) in + let leftm4,bool4 = weak_modify r4 left4 (subrel,tsubrel) in + let plleft,plright = + if (&) bool3 bool4 then (* r3 and r4 are relevant *) + (permute_layer (PNodeB(r3,leftm3,right3)) dglist (subrel,tsubrel)), + (permute_layer (PNodeB(r4,leftm4,right4)) dglist (subrel,tsubrel)) + else if (&) bool3 (not bool4) then (* only r3 is relevant *) + begin +(* print_endline "two-over-two left: bool3 and not bool4"; *) + (permute_layer (PNodeB(r3,leftm3,right3)) dglist (subrel,tsubrel)), + leftm4 + end + else if (&) (not bool3) bool4 then (* only r4 is relevant *) + leftm3, + (permute_layer (PNodeB(r4,leftm4,right4)) dglist (subrel,tsubrel)) + else (* neither r3 nor r4 are relevant *) + leftm3,leftm4 + in + PNodeB(r2,plleft,plright) + | _ -> raise jprover_bug + ) + else + let d = next_direction addr act_addr in + let newadd = change_last act_addr d in + if d = "l" then + let permute_result = permute o rule ptree la tsubrel in + (match permute_result with + PNodeB(r2,left2,right2) -> + let pbleft = permute_branch r addr newadd left2 dglist (subrel,tsubrel) in + let plright = permute_layer right2 dglist (subrel,tsubrel) in + PNodeB(r2,pbleft,plright) + | _ -> raise jprover_bug + ) + else (* d = "r", that is left is or_l free *) + let left1,bool = weak_modify rule left (subrel,tsubrel) in + if bool then (* rule is relevant *) + let permute_result = + permute o rule (PNodeB(o,PNodeB(rule,left1,right),right1)) la tsubrel in + (match permute_result with + PNodeB(r2,PNodeB(r3,left3,right3),right2) -> + let pbright = permute_branch r addr newadd right2 dglist (subrel,tsubrel) in + let leftm3,bool3 = weak_modify r3 left3 (subrel,tsubrel) in + let plleft = + if bool3 (* r3 relevant *) then + permute_layer (PNodeB(r3,leftm3,right3)) dglist (subrel,tsubrel) + else (* r3 redundant *) + leftm3 + in + PNodeB(r2,plleft,pbright) (* further opt. NOT possible *) + | _ -> raise jprover_bug + ) + else (* rule is not relevant *) + permute_layer (PNodeB(o,left1,right1)) dglist (subrel,tsubrel) (* further opt. possible *) + (* combine with orl_free *) + | PNodeB(o,left1,PNodeB(rule,left,right)),"r" -> (* two-over-two, right *) +(* print_endline " two-over-two, right"; *) + let leftm1,bool = weak_modify o left1 (subrel,tsubrel) in (* left1 is or_l free *) + if bool then (* o is relevant, even after permutations *) + if rule = r then (* left, right or_l free *) + permute o rule (PNodeB(o,leftm1,PNodeB(rule,left,right))) la tsubrel + else + let d = next_direction addr act_addr in + let newadd = change_last act_addr d in + if d = "l" then + let permute_result = + permute o rule (PNodeB(o,leftm1,PNodeB(rule,left,right))) la tsubrel in + (match permute_result with + PNodeB(r2,left2,right2) -> + let pbleft = permute_branch r addr newadd left2 dglist (subrel,tsubrel) in + let plright = permute_layer right2 dglist (subrel,tsubrel) in + PNodeB(r2,pbleft,plright) + | _ -> raise jprover_bug + ) + else (* d = "r", that is left is or_l free *) + let leftm,bool = weak_modify rule left (subrel,tsubrel) in + if bool then (* rule is relevant *) + let permute_result = + permute o rule (PNodeB(o,leftm1,PNodeB(rule,left,right))) la tsubrel in + (match permute_result with + PNodeB(r2,left2,right2) -> + let pbright = permute_branch r addr newadd right2 dglist (subrel,tsubrel) in + PNodeB(r2,left2,pbright) (* left2 or_l free *) + | _ -> raise jprover_bug + ) + else (* rule is not relevant *) + PNodeB(o,leftm1,leftm) + + else + leftm1 + | _ -> raise jprover_bug + in + let rec trans_add_branch r o addr act_addr ptree dglist (subrel,tsubrel) = + match ptree with + (PEmpty| PNodeAx(_)) -> raise jprover_bug + | PNodeA(rule,left) -> + if (dgenerative rule dglist left tsubrel) then + let newdg = (@) [rule] dglist in + if rule = o then + begin +(* print_endline "one-rule is o"; *) + permute_branch r addr act_addr ptree dglist (subrel,tsubrel) + end + else + begin +(* print_endline "alpha - but not o"; *) + let tptree = trans_add_branch r o addr act_addr left newdg (subrel,tsubrel) in + permute_layer (PNodeA(rule,tptree)) dglist (subrel,tsubrel) + (* r may not longer be valid for rule *) + end + else + let tptree = trans_add_branch r o addr act_addr left dglist (subrel,tsubrel) in + PNodeA(rule,tptree) + | PNodeB(rule,left,right) -> + let d = next_direction addr act_addr in + let bool = (dgenerative rule dglist left tsubrel) in + if rule = o then + begin +(* print_endline "two-rule is o"; *) + permute_branch r addr (act_addr^d) ptree dglist (subrel,tsubrel) + end + else + begin +(* print_endline ("beta - but not o: address "^d); *) + let dbranch = + if d = "l" then + left + else (* d = "r" *) + right + in + let tptree = + if bool then + let newdg = (@) [rule] dglist in + (trans_add_branch r o addr (act_addr^d) dbranch newdg (subrel,tsubrel)) + else + (trans_add_branch r o addr (act_addr^d) dbranch dglist (subrel,tsubrel)) + in + if d = "l" then + permute_layer (PNodeB(rule,tptree,right)) dglist (subrel,tsubrel) + else (* d = "r" *) + begin +(* print_endline "prob. a redundant call"; *) + let back = permute_layer (PNodeB(rule,left,tptree)) dglist (subrel,tsubrel) in +(* print_endline "SURELY a redundant call"; *) + back + end + end + in +(* print_endline "permute_layer in"; *) + let dummyt = mk_var_term "dummy" in + let r,o,addr = + top_addmissible_pair ptree dglist ("",Orl,dummyt,dummyt) ("",Orr,dummyt,dummyt) "" tsubrel dummyt in + if r = ("",Orl,dummyt,dummyt) then + ptree + else if o = ("",Orr,dummyt,dummyt) then (* Orr is a dummy for no d-gen. rule *) + ptree + else + let (x1,x2,x3,x4) = r + and (y1,y2,y3,y4) = o in +(* print_endline ("top or_l: "^x1); + print_endline ("or_l address: "^addr); + print_endline ("top dgen-rule: "^y1); *) + trans_add_branch r o addr "" ptree dglist (subrel,tsubrel) + +(* Isolate layer and outer recursion structure *) +(* uses weaker layer boundaries: ONLY critical inferences *) + + let rec trans_layer ptree (subrel,tsubrel) = + let rec isol_layer ptree (subrel,tsubrel) = + match ptree with + PEmpty -> raise jprover_bug + | PNodeAx(inf) -> + ptree + | PNodeA((pos,rule,formula,term),left) -> + if List.mem rule [Allr;Impr;Negr] then + let tptree = trans_layer left (subrel,tsubrel) in + PNodeA((pos,rule,formula,term),tptree) + else + let tptree = isol_layer left (subrel,tsubrel) in + PNodeA((pos,rule,formula,term),tptree) + | PNodeB(rule,left,right) -> + let tptree_l = isol_layer left (subrel,tsubrel) + and tptree_r = isol_layer right (subrel,tsubrel) in + PNodeB(rule,tptree_l,tptree_r) + in + begin +(* print_endline "trans_layer in"; *) + let top_tree = isol_layer ptree (subrel,tsubrel) in + let back = permute_layer top_tree [] (subrel,tsubrel) in +(* print_endline "translauer out"; *) + back + end + +(* REAL PERMUTATION STAFF --- End *) + +(* build the proof tree from a list of inference rules *) + + let rec unclosed subtree = + match subtree with + PEmpty -> true + | PNodeAx(y) -> false + | PNodeA(y,left) -> (unclosed left) + | PNodeB(y,left,right) -> (or) (unclosed left) (unclosed right) + + let rec extend prooftree element = + match prooftree with + PEmpty -> + let (pos,rule,formula,term) = element in + if rule = Ax then + PNodeAx(element) + else + if List.mem rule [Andr; Orl; Impl] then + PNodeB(element,PEmpty,PEmpty) + else + PNodeA(element,PEmpty) + | PNodeAx(y) -> + PEmpty (* that's only for exhaustive pattern matching *) + | PNodeA(y, left) -> + PNodeA(y, (extend left element)) + | PNodeB(y, left, right) -> + if (unclosed left) then + PNodeB(y, (extend left element), right) + else + PNodeB(y, left, (extend right element)) + + let rec bptree prooftree nodelist nax= + match nodelist with + [] -> prooftree,nax + | ((_,pos),(rule,formula,term))::rest -> (* kick away the first argument *) + let newax = + if rule = Ax then + 1 + else + 0 + in + bptree (extend prooftree (pos,rule,formula,term)) rest (nax+newax) + + + let bproof nodelist = + bptree PEmpty nodelist 0 + + let rec get_successor_pos treelist = + match treelist with + [] -> [] + | f::r -> + ( + match f with + Empty -> get_successor_pos r + | NodeAt(_) -> raise jprover_bug + | NodeA(pos,_) -> + pos::(get_successor_pos r) + ) + + let rec get_formula_tree ftreelist f predflag = + match ftreelist with + [] -> raise jprover_bug + | ftree::rest_trees -> + (match ftree with + Empty -> get_formula_tree rest_trees f predflag + | NodeAt(_) -> get_formula_tree rest_trees f predflag + | NodeA(pos,suctrees) -> + if predflag = "pred" then + if pos.pt = Gamma then + let succs = get_successor_pos (Array.to_list suctrees) in + if List.mem f succs then + NodeA(pos,suctrees),succs + else + get_formula_tree ((Array.to_list suctrees) @ rest_trees) f predflag + else + get_formula_tree ((Array.to_list suctrees) @ rest_trees) f predflag + else (* predflag = "" *) + if pos = f then + NodeA(pos,suctrees),[] + else + get_formula_tree ((Array.to_list suctrees) @ rest_trees) f predflag + ) + + let rec get_formula_treelist ftree po = + match po with + [] -> [] + | f::r -> +(* a posistion in po has either stype Gamma_0,Psi_0,Phi_0 (non-atomic), or it has *) +(* ptype Alpha (or on the right), since there was a deadlock for proof reconstruction in LJ*) + if List.mem f.st [Phi_0;Psi_0] then + let (stree,_) = get_formula_tree [ftree] f "" in + stree::(get_formula_treelist ftree r) + else + if f.st = Gamma_0 then + let (predtree,succs) = get_formula_tree [ftree] f "pred" in + let new_po = list_diff r succs in + predtree::(get_formula_treelist ftree new_po) + else + if f.pt = Alpha then (* same as first case, or on the right *) + let (stree,_) = get_formula_tree [ftree] f "" in + stree::(get_formula_treelist ftree r) + else raise (Invalid_argument "Jprover bug: non-admissible open position") + + let rec build_formula_rel dir_treelist slist predname = + + let rec build_renamed_gamma_rel dtreelist predname posname d = + match dtreelist with + [] -> [],[] + | (x,ft)::rdtlist -> + let rest_rel,rest_ren = build_renamed_gamma_rel rdtlist predname posname d in + ( + match ft with + Empty -> (* may have empty successors due to purity in former reconstruction steps *) + rest_rel,rest_ren + | NodeAt(_) -> + raise jprover_bug (* gamma_0 position never is atomic *) + | NodeA(spos,suctrees) -> + if List.mem spos.name slist then +(* the gamma_0 position is really unsolved *) +(* this is only relevant for the gamma_0 positions in po *) + let new_name = (posname^"_"^spos.name) (* make new unique gamma name *) in + let new_srel_el = ((predname,new_name),d) + and new_rename_el = (spos.name,new_name) (* gamma_0 position as key first *) in + let (srel,sren) = build_formula_rel [(x,ft)] slist new_name in + ((new_srel_el::srel) @ rest_rel),((new_rename_el::sren) @ rest_ren) + else + rest_rel,rest_ren + ) + + + in + match dir_treelist with + [] -> [],[] + | (d,f)::dir_r -> + let (rest_rel,rest_renlist) = build_formula_rel dir_r slist predname in + match f with + Empty -> + print_endline "Hello, an empty subtree!!!!!!"; + rest_rel,rest_renlist + | NodeAt(pos) -> + (((predname,pos.name),d)::rest_rel),rest_renlist + | NodeA(pos,suctrees) -> + (match pos.pt with + Alpha | Beta -> + let dtreelist = + if (pos.pt = Alpha) & (pos.op = Neg) then + [(1,suctrees.(0))] + else + let st1 = suctrees.(0) + and st2 = suctrees.(1) in + [(1,st1);(2,st2)] + in + let (srel,sren) = build_formula_rel dtreelist slist pos.name in + ((((predname,pos.name),d)::srel) @ rest_rel),(sren @ rest_renlist) + | Delta -> + let st1 = suctrees.(0) in + let (srel,sren) = build_formula_rel [(1,st1)] slist pos.name in + ((((predname,pos.name),d)::srel) @ rest_rel),(sren @ rest_renlist) + | Psi| Phi -> + let succlist = Array.to_list suctrees in + let dtreelist = (List.map (fun x -> (d,x)) succlist) in + let (srel,sren) = build_formula_rel dtreelist slist predname in + (srel @ rest_rel),(sren @ rest_renlist) + | Gamma -> + let n = Array.length suctrees + and succlist = (Array.to_list suctrees) in + let dtreelist = (List.map (fun x -> (1,x)) succlist) in +(* if (nonemptys suctrees 0 n) = 1 then + let (srel,sren) = build_formula_rel dtreelist slist pos.name in + ((((predname,pos.name),d)::srel) @ rest_rel),(sren @ rest_renlist) + else (* we have more than one gamma instance, which means renaming *) +*) + let (srel,sren) = build_renamed_gamma_rel dtreelist predname pos.name d in + (srel @ rest_rel),(sren @ rest_renlist) + | PNull -> + raise jprover_bug + ) + + let rec rename_gamma ljmc_proof rename_list = + match ljmc_proof with + [] -> [] + | ((inst,pos),(rule,formula,term))::r -> + if List.mem rule [Alll;Exr] then + let new_gamma = List.assoc inst rename_list in + ((inst,new_gamma),(rule,formula,term))::(rename_gamma r rename_list) + else + ((inst,pos),(rule,formula,term))::(rename_gamma r rename_list) + + let rec compare_pair (s,sf) list = + if list = [] then + list + else + let (s_1,sf_1),restlist = (List.hd list),(List.tl list) in + if sf = s_1 then + (@) [(s,sf_1)] (compare_pair (s,sf) restlist) + else + compare_pair (s,sf) restlist + + let rec compare_pairlist list1 list2 = + if list1 = [] then + list1 + else + let (s1,sf1),restlist1 = (List.hd list1),(List.tl list1) in + (@) (compare_pair (s1,sf1) list2) (compare_pairlist restlist1 list2) + + let rec trans_rec pairlist translist = + let tlist = compare_pairlist pairlist translist in + if tlist = [] then + translist + else + (@) (trans_rec pairlist tlist) translist + + let transitive_closure subrel = + let pairlist,nlist = List.split subrel in + trans_rec pairlist pairlist + + let pt ptree subrel = + let tsubrel = transitive_closure subrel in + let transptree = trans_layer ptree (subrel,tsubrel) in + print_endline ""; + fst (modify transptree (subrel,tsubrel)) +(* let mtree = fst (modify transptree (subrel,tsubrel)) in *) +(* pretty_print mtree ax *) + + let rec make_node_list ljproof = + match ljproof with + PEmpty -> + raise jprover_bug + | PNodeAx((pos,inf,form,term)) -> + [(("",pos),(inf,form,term))] + | PNodeA((pos,inf,form,term),left) -> + let left_list = make_node_list left in + (("",pos),(inf,form,term))::left_list + | PNodeB((pos,inf,form,term),left,right) -> + let left_list = make_node_list left + and right_list = make_node_list right in + (("",pos),(inf,form,term))::(left_list @ right_list) + + let permute_ljmc ftree po slist ljmc_proof = + (* ftree/po are the formula tree / open positions of the sequent that caused deadlock and permutation *) +(* print_endline "!!!!!!!!!!!!!Permutation TO DO!!!!!!!!!"; *) + (* the open positions in po are either phi_0, psi_0, or gamma_0 positions *) + (* since proof reconstruction was a deadlock in LJ *) + let po_treelist = get_formula_treelist ftree po in + let dir_treelist = List.map (fun x -> (1,x)) po_treelist in + let (formula_rel,rename_list) = build_formula_rel dir_treelist slist "dummy" in + let renamed_ljmc_proof = rename_gamma ljmc_proof rename_list in + let (ptree,ax) = bproof renamed_ljmc_proof in + let ljproof = pt ptree formula_rel in + (* this is a direct formula relation, comprising left/right subformula *) + begin +(* print_treelist po_treelist; *) +(* print_endline ""; + print_endline ""; +*) +(* print_triplelist formula_rel; *) +(* print_endline ""; + print_endline ""; + tt ljproof; +*) +(* print_pairlist rename_list; *) +(* print_endline ""; + print_endline ""; +*) + make_node_list ljproof + end + +(************** PROOF RECONSTRUCTION without redundancy deletion ******************************) + + let rec init_unsolved treelist = + match treelist with + [] -> [] + | f::r -> + begin match f with + Empty -> [] + | NodeAt(pos) -> + (pos.name)::(init_unsolved r) + | NodeA(pos,suctrees) -> + let new_treelist = (Array.to_list suctrees) @ r in + (pos.name)::(init_unsolved new_treelist) + end + +(* only the unsolved positions will be represented --> skip additional root position *) + + let build_unsolved ftree = + match ftree with + Empty | NodeAt _ -> + raise jprover_bug + | NodeA(pos,suctrees) -> + ((pos.name),init_unsolved (Array.to_list suctrees)) + +(* + let rec collect_variables tree_list = + match tree_list with + [] -> [] + | f::r -> + begin match f with + Empty -> [] + | NodeAt(pos) -> + if pos.st = Gamma_0 then + pos.name::collect_variables r + else + collect_variables r + | NodeA(pos,suctrees) -> + let new_tree_list = (Array.to_list suctrees) @ r in + if pos.st = Gamma_0 then + pos.name::collect_variables new_tree_list + else + collect_variables new_tree_list + end + + let rec extend_sigmaQ sigmaQ vlist = + match vlist with + [] -> [] + | f::r -> + let vf = mk_var_term f in + if List.exists (fun x -> (fst x = vf)) sigmaQ then + extend_sigmaQ sigmaQ r + else +(* first and second component are var terms in meta-prl *) + [(vf,vf)] @ (extend_sigmaQ sigmaQ r) + + let build_sigmaQ sigmaQ ftree = + let vlist = collect_variables [ftree] in + sigmaQ @ (extend_sigmaQ sigmaQ vlist) +*) + +(* subformula relation subrel is assumed to be represented in pairs + (a,b) *) + + let rec delete e list = (* e must not necessarily occur in list *) + match list with + [] -> [] (* e must not necessarily occur in list *) + | first::rest -> + if e = first then + rest + else + first::(delete e rest) + + let rec key_delete fname pos_list = (* in key_delete, f is a pos name (key) but sucs is a list of positions *) + match pos_list with + [] -> [] (* the position with name f must not necessarily occur in pos_list *) + | f::r -> + if fname = f.name then + r + else + f::(key_delete fname r) + + let rec get_roots treelist = + match treelist with + [] -> [] + | f::r -> + match f with + Empty -> (get_roots r) (* Empty is posible below alpha-nodes after purity *) + | NodeAt(pos) -> pos::(get_roots r) + | NodeA(pos,trees) -> pos::(get_roots r) + + let rec comp_ps padd ftree = + match ftree with + Empty -> raise (Invalid_argument "Jprover bug: empty formula tree") + | NodeAt(pos) -> + [] + | NodeA(pos,strees) -> + match padd with + [] -> get_roots (Array.to_list strees) + | f::r -> + if r = [] then + pos::(comp_ps r (Array.get strees (f-1))) + else + comp_ps r (Array.get strees (f-1)) + +(* computes a list: first element predecessor, next elements successoes of p *) + + let tpredsucc p ftree = + let padd = p.address in + comp_ps padd ftree + +(* set an element in an array, without side effects *) + + let myset array int element = + let length = Array.length array in + let firstpart = Array.sub array 0 (int) in + let secondpart = Array.sub array (int+1) (length-(int+1)) in + (Array.append firstpart (Array.append [|element|] secondpart)) + + let rec compute_open treelist slist = + match treelist with + [] -> [] + | first::rest -> + let elements = + match first with + Empty -> [] + | NodeAt(pos) -> + if (List.mem (pos.name) slist) then + [pos] + else + [] + | NodeA(pos,suctrees) -> + if (List.mem (pos.name) slist) then + [pos] + else + compute_open (Array.to_list suctrees) slist + in + elements @ (compute_open rest slist) + + let rec select_connection pname connections slist = + match connections with + [] -> ("none","none") + | f::r -> + let partner = + if (fst f) = pname then + (snd f) + else + if (snd f) = pname then + (fst f) + else + "none" + in + if ((partner = "none") or (List.mem partner slist)) then + select_connection pname r slist + else + f + + let rec replace_element element element_set redord = + match redord with + [] -> raise jprover_bug (* element occurs in redord *) + | (f,fset)::r -> + if f = element then + (f,element_set)::r + else + (f,fset)::(replace_element element element_set r) + + let rec collect_succ_sets sucs redord = + match redord with + [] -> StringSet.empty + | (f,fset)::r -> + let new_sucs = key_delete f sucs in + if (List.length sucs) = (List.length new_sucs) then (* position with name f did not occur in sucs -- no deletion *) + (collect_succ_sets sucs r) + else + StringSet.union (StringSet.add f fset) (collect_succ_sets new_sucs r) + + let replace_ordering psucc_name sucs redord = + let new_psucc_set = collect_succ_sets sucs redord in +(* print_string_set new_psucc_set; *) + replace_element psucc_name new_psucc_set redord + + let rec update pname redord = + match redord with + [] -> [] + | (f,fset)::r -> + if pname=f then + r + else + (f,fset)::(update pname r) + +(* rule construction *) + + let rec selectQ_rec spos_var csigmaQ = + match csigmaQ with + [] -> mk_var_term spos_var (* dynamic completion of csigmaQ *) + | (var,term)::r -> + if spos_var=var then + term + else + selectQ_rec spos_var r + + let selectQ spos_name csigmaQ = + let spos_var = spos_name^"_jprover" in + selectQ_rec spos_var csigmaQ + + let apply_sigmaQ term sigmaQ = + let sigma_vars,sigma_terms = List.split sigmaQ in + (subst term sigma_vars sigma_terms) + + let build_rule pos spos csigmaQ orr_flag calculus = + let inst_label = apply_sigmaQ (pos.label) csigmaQ in + match pos.op,pos.pol with + Null,_ -> raise (Invalid_argument "Jprover: no rule") + | At,O -> Ax,(inst_label),xnil_term (* to give back a term *) + | At,I -> Ax,(inst_label),xnil_term + | And,O -> Andr,(inst_label),xnil_term + | And,I -> Andl,(inst_label),xnil_term + | Or,O -> + if calculus = "LJ" then + let or_rule = + if orr_flag = 1 then + Orr1 + else + Orr2 + in + or_rule,(inst_label),xnil_term + else + Orr,(inst_label),xnil_term + | Or,I -> Orl,(inst_label),xnil_term + | Neg,O -> Negr,(inst_label),xnil_term + | Neg,I -> Negl,(inst_label),xnil_term + | Imp,O -> Impr,(inst_label),xnil_term + | Imp,I -> Impl,(inst_label),xnil_term + | All,I -> Alll,(inst_label),(selectQ spos.name csigmaQ) (* elements of csigmaQ is (string * term) *) + | Ex,O -> Exr,(inst_label), (selectQ spos.name csigmaQ) + | All,O -> Allr,(inst_label),(mk_string_term jprover_op spos.name) (* must be a proper term *) + | Ex,I -> Exl,(inst_label),(mk_string_term jprover_op spos.name) (* must be a proper term *) + + +(* %%%%%%%%%%%%%%%%%%%% Split begin %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% *) + + let rec nonemptys treearray j n = + if j = n then + 0 + else + let count = + if (Array.get treearray j) <> Empty then + 1 + else + 0 + in + count + (nonemptys treearray (j+1) n) + + let rec collect_pure ftreelist (flist,slist) = + + let rec collect_itpure ftree (flist,slist) = + match ftree with + Empty -> (* assumed that not all brother trees are Empty *) + [] + | NodeAt(pos) -> (* that may NOT longer be an inner node *) + if ((List.mem (pos.name) flist) or (List.mem (pos.name) slist)) then + [] + else + [pos] + | NodeA(pos,treearray) -> + collect_pure (Array.to_list treearray) (flist,slist) + in + match ftreelist with + [] -> [] + | f::r -> + (collect_itpure f (flist,slist)) @ (collect_pure r (flist,slist)) + + let rec update_list testlist list = + match testlist with + [] -> list + | f::r -> + let newlist = delete f list in (* f may not occur in list; then newlist=list *) + update_list r newlist + + let rec update_pairlist p pairlist = + match pairlist with + [] -> [] + | f::r -> + if ((fst f) = p) or ((snd f) = p) then + update_pairlist p r + else + f::(update_pairlist p r) + + let rec update_connections slist connections = + match slist with + [] -> connections + | f::r -> + let connew = update_pairlist f connections in + update_connections r connew + + let rec update_redord delset redord = (* delset is the set of positions to be deleted *) + match redord with + [] -> [] + | (f,fset)::r -> + if (StringSet.mem f delset) then + update_redord delset r (* delete all key elements f from redord which are in delset *) + else + let new_fset = StringSet.diff fset delset in (* no successor of f from delset should remain in fset *) + (f,new_fset)::(update_redord delset r) + + let rec get_position_names treelist = + match treelist with + [] -> [] + | deltree::rests -> + match deltree with + Empty -> get_position_names rests + | NodeAt(pos) -> + (pos.name)::get_position_names rests + | NodeA(pos,strees) -> + (pos.name)::(get_position_names ((Array.to_list strees) @ rests)) + + let rec slist_to_set slist = + match slist with + [] -> + StringSet.empty + | f::r -> + StringSet.add f (slist_to_set r) + + let rec print_purelist pr = + match pr with + [] -> + begin + print_string "."; + print_endline " "; + end + | f::r -> + print_string ((f.name)^", "); + print_purelist r + + let update_relations deltree redord connections unsolved_list = + let pure_names = get_position_names [deltree] in + begin +(* print_ftree deltree; + Format.open_box 0; + print_endline " "; + print_stringlist pure_names; + Format.force_newline (); + Format.print_flush (); +*) + let rednew = update_redord (slist_to_set pure_names) redord + and connew = update_connections pure_names connections + and unsolnew = update_list pure_names unsolved_list in + (rednew,connew,unsolnew) + end + + let rec collect_qpos ftreelist uslist = + match ftreelist with + [] -> [],[] + | ftree::rest -> + match ftree with + Empty -> + collect_qpos rest uslist + | NodeAt(pos) -> + let (rest_delta,rest_gamma) = collect_qpos rest uslist in + if (pos.st = Gamma_0) & (List.mem pos.name uslist) then + rest_delta,(pos.name::rest_gamma) + else + if (pos.st = Delta_0) & (List.mem pos.name uslist) then + (pos.name::rest_delta),rest_gamma + else + rest_delta,rest_gamma + | NodeA(pos,suctrees) -> + let (rest_delta,rest_gamma) = collect_qpos ((Array.to_list suctrees) @ rest) uslist in + if (pos.st = Gamma_0) & (List.mem pos.name uslist) then + rest_delta,(pos.name::rest_gamma) + else + if (pos.st = Delta_0) & (List.mem pos.name uslist) then + (pos.name::rest_delta),rest_gamma + else + rest_delta,rest_gamma + + let rec do_split gamma_diff sigmaQ = + match sigmaQ with + [] -> [] + | (v,term)::r -> + if (List.mem (String.sub v 0 (String.index v '_')) gamma_diff) then + do_split gamma_diff r + else + (v,term)::(do_split gamma_diff r) + +(* make a term list out of a bterm list *) + + let rec collect_subterms = function + [] -> [] + | bt::r -> + let dbt = dest_bterm bt in + (dbt.bterm)::(collect_subterms r) + + (*: Bug! :*) +(*: let rec collect_delta_terms = function + [] -> [] + | t::r -> + let dt = dest_term t in + let top = dt.term_op + and tterms = dt.term_terms in + let dop = dest_op top in + let don = dest_opname dop.op_name in + match don with + [] -> + let sub_terms = collect_subterms tterms in + collect_delta_terms (sub_terms @ r) + | op1::opr -> + if op1 = "jprover" then + match opr with + [] -> raise (Invalid_argument "Jprover: delta position missing") + | delta::_ -> + delta::(collect_delta_terms r) + else + let sub_terms = collect_subterms tterms in + collect_delta_terms (sub_terms @ r) +:*) + + let rec collect_delta_terms = function + [] -> [] + | t::r -> + let dt = dest_term t in + let top = dt.term_op + and tterms = dt.term_terms in + let dop = dest_op top in + let don = dest_opname dop.op_name in + let doa = dest_param dop.op_params in + match don with + [] -> + let sub_terms = collect_subterms tterms in + collect_delta_terms (sub_terms @ r) + | op1::opr -> + if op1 = "jprover" then + match doa with + [] -> raise (Invalid_argument "Jprover: delta position missing") + | String delta::_ -> + delta::(collect_delta_terms r) + | _ -> raise (Invalid_argument "Jprover: delta position error") + else + let sub_terms = collect_subterms tterms in + collect_delta_terms (sub_terms @ r) + + + + let rec check_delta_terms (v,term) ass_delta_diff dterms = + match ass_delta_diff with + [] -> term,[] + | (var,dname)::r -> + if List.mem dname dterms then + let new_var = + if var = "" then + v + else + var + in + let replace_term = mk_string_term jprover_op dname in + let next_term = var_subst term replace_term new_var in + let (new_term,next_diffs) = check_delta_terms (v,next_term) r dterms in + (new_term,((new_var,dname)::next_diffs)) + else + let (new_term,next_diffs) = check_delta_terms (v,term) r dterms in + (new_term,((var,dname)::next_diffs)) + + + let rec localize_sigma zw_sigma ass_delta_diff = + match zw_sigma with + [] -> [] + | (v,term)::r -> + let dterms = collect_delta_terms [term] in + let (new_term,new_ass_delta_diff) = check_delta_terms (v,term) ass_delta_diff dterms in + (v,new_term)::(localize_sigma r new_ass_delta_diff) + + let subst_split ft1 ft2 ftree uslist1 uslist2 uslist sigmaQ = + let delta,gamma = collect_qpos [ftree] uslist + and delta1,gamma1 = collect_qpos [ft1] uslist1 + and delta2,gamma2 = collect_qpos [ft2] uslist2 in + let delta_diff1 = list_diff delta delta1 + and delta_diff2 = list_diff delta delta2 + and gamma_diff1 = list_diff gamma gamma1 + and gamma_diff2 = list_diff gamma gamma2 in + let zw_sigma1 = do_split gamma_diff1 sigmaQ + and zw_sigma2 = do_split gamma_diff2 sigmaQ in + let ass_delta_diff1 = List.map (fun x -> ("",x)) delta_diff1 + and ass_delta_diff2 = List.map (fun x -> ("",x)) delta_diff2 in + let sigmaQ1 = localize_sigma zw_sigma1 ass_delta_diff1 + and sigmaQ2 = localize_sigma zw_sigma2 ass_delta_diff2 in + (sigmaQ1,sigmaQ2) + + let rec reduce_tree addr actual_node ftree beta_flag = + match addr with + [] -> (ftree,Empty,actual_node,beta_flag) + | a::radd -> + match ftree with + Empty -> + print_endline "Empty purity tree"; + raise jprover_bug + | NodeAt(_) -> + print_endline "Atom purity tree"; + raise jprover_bug + | NodeA(pos,strees) -> +(* print_endline pos.name; *) + (* the associated node occurs above f (or the empty address) and hence, is neither atom nor empty tree *) + + let nexttree = (Array.get strees (a-1)) in + if (nonemptys strees 0 (Array.length strees)) < 2 then + begin +(* print_endline "strees 1 or non-empties < 2"; *) + let (ft,dt,an,bf) = reduce_tree radd actual_node nexttree beta_flag in + let nstrees = myset strees (a-1) ft in +(* print_endline ("way back "^pos.name); *) + (NodeA(pos,nstrees),dt,an,bf) + end + else (* nonemptys >= 2 *) + begin +(* print_endline "nonempties >= 2 "; *) + let (new_act,new_bf) = + if pos.pt = Beta then + (actual_node,true) + else + ((pos.name),false) + in + let (ft,dt,an,bf) = reduce_tree radd new_act nexttree new_bf in + if an = pos.name then + let nstrees = myset strees (a-1) Empty in +(* print_endline ("way back assocnode "^pos.name); *) + (NodeA(pos,nstrees),nexttree,an,bf) + else (* has been replaced / will be replaced below / above pos *) + let nstrees = myset strees (a-1) ft in +(* print_endline ("way back "^pos.name); *) + (NodeA(pos,nstrees),dt,an,bf) + end + + let rec purity ftree redord connections unsolved_list = + + let rec purity_reduction pr ftree redord connections unsolved_list = + begin +(* Format.open_box 0; + print_endline " "; + print_purelist pr; + Format.force_newline (); + Format.print_flush (); +*) + match pr with + [] -> (ftree,redord,connections,unsolved_list) + | f::r -> +(* print_endline ("pure position "^(f.name)); *) + let (ftnew,deltree,assocn,beta_flag) = reduce_tree f.address "" ftree false + in +(* print_endline ("assoc node "^assocn); *) + if assocn = "" then + (Empty,[],[],[]) (* should not occur in the final version *) + else + let (rednew,connew,unsolnew) = update_relations deltree redord connections unsolved_list in + begin +(* Format.open_box 0; + print_endline " "; + print_pairlist connew; + Format.force_newline (); + Format.print_flush (); +*) + if beta_flag = true then + begin +(* print_endline "beta_flag true"; *) + purity ftnew rednew connew unsolnew + (* new pure positions may occur; old ones may not longer exist *) + end + else + purity_reduction r ftnew rednew connew unsolnew (* let's finish the old pure positions *) + end + end + + in + let flist,slist = List.split connections in + let pr = collect_pure [ftree] (flist,slist) in + purity_reduction pr ftree redord connections unsolved_list + + let rec betasplit addr ftree redord connections unsolved_list = + match ftree with + Empty -> + print_endline "bsplit Empty tree"; + raise jprover_bug + | NodeAt(_) -> + print_endline "bsplit Atom tree"; + raise jprover_bug (* the beta-node should actually occur! *) + | NodeA(pos,strees) -> + match addr with + [] -> (* we are at the beta node under consideration *) + let st1tree = (Array.get strees 0) + and st2tree = (Array.get strees 1) in + let (zw1red,zw1conn,zw1uslist) = update_relations st2tree redord connections unsolved_list + and (zw2red,zw2conn,zw2uslist) = update_relations st1tree redord connections unsolved_list in + ((NodeA(pos,[|st1tree;Empty|])),zw1red,zw1conn,zw1uslist), + ((NodeA(pos,[|Empty;st2tree|])),zw2red,zw2conn,zw2uslist) + | f::rest -> + let nexttree = Array.get strees (f-1) in + let (zw1ft,zw1red,zw1conn,zw1uslist),(zw2ft,zw2red,zw2conn,zw2uslist) = + betasplit rest nexttree redord connections unsolved_list in +(* let scopytrees = Array.copy strees in *) + let zw1trees = myset strees (f-1) zw1ft + and zw2trees = myset strees (f-1) zw2ft in + (NodeA(pos,zw1trees),zw1red,zw1conn,zw1uslist),(NodeA(pos,zw2trees),zw2red,zw2conn,zw2uslist) + + + + + let split addr pname ftree redord connections unsolved_list opt_bproof = + let (opt_bp1,min_con1),(opt_bp2,min_con2) = split_permutation pname opt_bproof in + begin +(* + print_endline "Beta proof 1: "; + print_endline ""; + print_beta_proof opt_bp1; + print_endline ""; + print_endline ("Beta proof 1 connections: "); + Format.open_box 0; + print_pairlist min_con1; + print_endline "."; + Format.print_flush(); + print_endline ""; + print_endline ""; + print_endline "Beta proof 2: "; + print_endline ""; + print_beta_proof opt_bp2; + print_endline ""; + print_endline ("Beta proof 2 connections: "); + Format.open_box 0; + print_pairlist min_con2; + print_endline "."; + Format.print_flush(); + print_endline ""; +*) + let (zw1ft,zw1red,zw1conn,zw1uslist),(zw2ft,zw2red,zw2conn,zw2uslist) = + betasplit addr ftree redord connections unsolved_list in +(* zw1conn and zw2conn are not longer needed when using beta proofs *) +(* print_endline "betasp_out"; *) + let ft1,red1,conn1,uslist1 = purity zw1ft zw1red min_con1 zw1uslist in +(* print_endline "purity_one_out"; *) + let ft2,red2,conn2,uslist2 = purity zw2ft zw2red min_con2 zw2uslist in +(* print_endline "purity_two_out"; *) +(* again, min_con1 = conn1 and min_con2 = conn2 should hold *) + begin +(* print_endline ""; + print_endline ""; + print_endline ("Purity 1 connections: "); + Format.open_box 0; + print_pairlist conn1; + print_endline "."; + print_endline ""; + Format.print_flush(); + print_endline ""; + print_endline ""; + print_endline ("Purity 2 connections: "); + Format.open_box 0; + print_pairlist conn2; + print_endline "."; + print_endline ""; + Format.print_flush(); + print_endline ""; + print_endline ""; +*) + (ft1,red1,conn1,uslist1,opt_bp1),(ft2,red2,conn2,uslist2,opt_bp2) + end + end + + +(* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Splitting end %%%%%%%%%%%%%%%% *) + + +(* for wait labels we collect all solved atoms with pol=0 *) + + let rec collect_solved_O_At ftreelist slist = + match ftreelist with + [] -> + [] + | f::r -> + match f with + Empty -> (* may become possible after purity *) + collect_solved_O_At r slist + | NodeAt(pos) -> + if ((List.mem (pos.name) slist) or (pos.pol = I)) then (* recall slist is the unsolved list *) + collect_solved_O_At r slist + else + (* here, we have pos solved and pos.pol = O) *) + pos::(collect_solved_O_At r slist) + | NodeA(pos,treearray) -> + collect_solved_O_At ((Array.to_list treearray) @ r) slist + + let rec red_ord_block pname redord = + match redord with + [] -> false + | (f,fset)::r -> + if ((f = pname) or (not (StringSet.mem pname fset))) then + red_ord_block pname r + else + true (* then, we have (StringSet.mem pname fset) *) + + let rec check_wait_succ_LJ faddress ftree = + match ftree with + Empty -> raise jprover_bug + | NodeAt(pos) -> raise jprover_bug (* we have an gamma_0 position or an or-formula *) + | NodeA(pos,strees) -> + match faddress with + [] -> + if pos.op = Or then + match (strees.(0),strees.(1)) with + (Empty,Empty) -> raise (Invalid_argument "Jprover: redundancies occur") + | (Empty,_) -> (false,2) (* determines the Orr2 rule *) + | (_,Empty) -> (false,1) (* determines the Orr1 ruke *) + | (_,_) -> (true,0) (* wait-label is set *) + else + (false,0) + | f::r -> + if r = [] then + if (pos.pt = Gamma) & ((nonemptys strees 0 (Array.length strees)) > 1) then + (true,0) (* we are at a gamma position (exr) with one than one successor -- wait label in LJ*) + else + check_wait_succ_LJ r (Array.get strees (f-1)) + else + check_wait_succ_LJ r (Array.get strees (f-1)) + + let blocked f po redord ftree connections slist logic calculus opt_bproof = +(* print_endline ("Blocking check "^(f.name)); *) + if (red_ord_block (f.name) redord) then + begin +(* print_endline "wait-1 check positive"; *) + true,0 + end + else + if logic = "C" then + false,0 (* ready, in C only redord counts *) + else + let pa_O = collect_solved_O_At [ftree] slist (* solved atoms in ftree *) + and po_test = (delete f po) in + if calculus = "LJmc" then (* we provide dynamic wait labels for both sequent calculi *) +(* print_endline "wait-2 check"; *) + if (f.st = Psi_0) & (f.pt <> PNull) & + ((pa_O <> []) or (List.exists (fun x -> x.pol = O) po_test)) then + begin +(* print_endline "wait-2 positive"; *) + true,0 (* wait_2 label *) + end + else + begin +(* print_endline "wait-2 negative"; *) + false,0 + end + else (* calculus is supposed to be LJ *) + if calculus = "LJ" then + if ((f.st = Phi_0) & ((f.op=Neg) or (f.op=Imp)) & + ((pa_O <> []) or (List.exists (fun x -> x.pol = O) po_test)) + ) + (* this would cause an impl or negl rule with an non-empty succedent *) + then + if (f.op=Neg) then + true,0 + else (* (f.op=Imp) *) + (* In case of an impl rule on A => B, the wait_label must NOT be set + iff all succedent formulae depend exclusively on B. For this, we + perform a split operation and determine, if in the A-subgoal + all succedent formulae are pure, i.e.~have been deleted from treds. + Otherwise, in case of A-dependent succedent formulae, the + wait_label must be set. + *) + let ((_,min_con1),_) = split_permutation f.name opt_bproof in + let slist_fake = delete f.name slist in + let ((zw1ft,zw1red,_,zw1uslist),_) = + betasplit (f.address) ftree redord connections slist_fake in + let ft1,_,_,uslist1 = purity zw1ft zw1red min_con1 zw1uslist in +(* print_endline "wait label purity_one_out"; *) + let ft1_root = (List.hd (List.tl (tpredsucc f ft1))) in +(* print_endline ("wait-root "^(ft1_root.name)); *) + let po_fake = compute_open [ft1] uslist1 in + let po_fake_test = delete ft1_root po_fake + and pa_O_fake = collect_solved_O_At [ft1] uslist1 in +(* print_purelist (po_fake_test @ pa_O_fake); *) + if ((pa_O_fake <> []) or (List.exists (fun x -> x.pol = O) po_fake_test)) then + true,0 + else + false,0 + else + if ((f.pol=O) & ((f.st=Gamma_0) or (f.op=Or))) then + let (bool,orr_flag) = check_wait_succ_LJ f.address ftree in + (bool,orr_flag) + (* here is determined if orr1 or orr2 will be performed, provided bool=false) *) + (* orr_flag can be 1 or 2 *) + else + false,0 + else + raise (Invalid_argument "Jprover: calculus should be LJmc or LJ") + + let rec get_beta_preference list actual = + match list with + [] -> actual + | (f,int)::r -> + if f.op = Imp then + (f,int) + else +(* if f.op = Or then + get_beta_preference r (f,int) + else +*) + get_beta_preference r actual + + exception Gamma_deadlock + + let rec select_pos search_po po redord ftree connections slist logic calculus candidates + opt_bproof = + match search_po with + [] -> + (match candidates with + [] -> + if calculus = "LJ" then + raise Gamma_deadlock (* permutation may be necessary *) + else + raise (Invalid_argument "Jprover bug: overall deadlock") (* this case should not occur *) + | c::rest -> + get_beta_preference (c::rest) c + ) + | f::r -> (* there exist an open position *) + let (bool,orr_flag) = (blocked f po redord ftree connections slist logic calculus + opt_bproof) + in + if (bool = true) then + select_pos r po redord ftree connections slist logic calculus candidates opt_bproof + else + if f.pt = Beta then + (* search for non-splitting rules first *) +(* let beta_candidate = + if candidates = [] + then + [(f,orr_flag)] + else + !!!! but preserve first found candidate !!!!!!! + candidates + in + !!!!!!! this strategy is not sure the best -- back to old !!!!!!!!! +*) + select_pos r po redord ftree connections slist logic calculus + ((f,orr_flag)::candidates) opt_bproof + else + (f,orr_flag) + +(* let rec get_position_in_tree pname treelist = + match treelist with + [] -> raise jprover_bug + | f::r -> + begin match f with + Empty -> get_position_in_tree pname r + | NodeAt(pos) -> + if pos.name = pname then + pos + else + get_position_in_tree pname r + | NodeA(pos,suctrees) -> + get_position_in_tree pname ((Array.to_list suctrees) @ r) + end +*) + +(* total corresponds to tot in the thesis, + tot simulates the while-loop, solve is the rest *) + + let rec total ftree redord connections csigmaQ slist logic calculus opt_bproof = + let rec tot ftree redord connections po slist = + let rec solve ftree redord connections p po slist (pred,succs) orr_flag = + let newslist = delete (p.name) slist in + let rback = + if p.st = Gamma_0 then + begin +(* print_endline "that's the gamma rule"; *) + [((p.name,pred.name),(build_rule pred p csigmaQ orr_flag calculus))] + end + else + [] + in +(* print_endline "gamma check finish"; *) + let pnew = + if p.pt <> Beta then + succs @ (delete p po) + else + po + in + match p.pt with + Gamma -> + rback @ (tot ftree redord connections pnew newslist) + | Psi -> + if p.op = At then + let succ = List.hd succs in + rback @ (solve ftree redord connections succ pnew newslist (p,[]) orr_flag) (* solve atoms immediately *) + else + rback @ (tot ftree redord connections pnew newslist) + | Phi -> + if p.op = At then + let succ = List.hd succs in + rback @ (solve ftree redord connections succ pnew newslist (p,[]) orr_flag) (* solve atoms immediately *) + else + rback @ (tot ftree redord connections pnew newslist) + | PNull -> + let new_redord = update p.name redord in + let (c1,c2) = select_connection (p.name) connections newslist in + if (c1= "none" & c2 ="none") then + rback @ (tot ftree new_redord connections pnew newslist) + else + let (ass_pos,inst_pos) = +(* need the pol=O position ass_pos of the connection for later permutation *) +(* need the pol=I position inst_pos for NuPRL instantiation *) + if p.name = c1 then + if p.pol = O then + (c1,c2) + else + (c2,c1) + else (* p.name = c2 *) + if p.pol = O then + (c2,c1) + else + (c1,c2) + in + rback @ [(("",ass_pos),(build_rule p p csigmaQ orr_flag calculus))] + (* one possibility of recursion end *) + | Alpha -> + rback @ ((("",p.name),(build_rule p p csigmaQ orr_flag calculus))::(tot ftree redord connections pnew newslist)) + | Delta -> + let sp = List.hd succs in + rback @ ((("",p.name),(build_rule p sp csigmaQ orr_flag calculus))::(tot ftree redord connections pnew newslist)) + | Beta -> +(* print_endline "split_in"; *) + let (ft1,red1,conn1,uslist1,opt_bproof1),(ft2,red2,conn2,uslist2,opt_bproof2) = + split (p.address) (p.name) ftree redord connections newslist opt_bproof in + let (sigmaQ1,sigmaQ2) = subst_split ft1 ft2 ftree uslist1 uslist2 newslist csigmaQ in +(* print_endline "split_out"; *) + let p1 = total ft1 red1 conn1 sigmaQ1 uslist1 logic calculus opt_bproof1 in +(* print_endline "compute p1 out"; *) + let p2 = total ft2 red2 conn2 sigmaQ2 uslist2 logic calculus opt_bproof2 in +(* print_endline "compute p2 out"; *) + rback @ [(("",p.name),(build_rule p p csigmaQ orr_flag calculus))] @ p1 @ p2 (* second possibility of recursion end *) + in + begin try + let (p,orr_flag) = select_pos po po redord ftree connections slist logic + calculus [] opt_bproof + (* last argument for guiding selection strategy *) + in +(* print_endline ((p.name)^" "^(string_of_int orr_flag)); *) + let predsuccs = tpredsucc p ftree in + let pred = List.hd predsuccs + and succs = List.tl predsuccs in + let redpo = update (p.name) redord in (* deletes the entry (p,psuccset) from the redord *) + let rednew = + if (p.pt = Delta) then (* keep the tree ordering for the successor position only *) + let psucc = List.hd succs in + let ppsuccs = tpredsucc psucc ftree in + let pre = List.hd ppsuccs + and sucs = List.tl ppsuccs in + replace_ordering (psucc.name) sucs redpo (* union the succsets of psucc *) + else + redpo + in +(* print_endline "update ok"; *) + solve ftree rednew connections p po slist (pred,succs) orr_flag + with Gamma_deadlock -> + let ljmc_subproof = total ftree redord connections csigmaQ slist "J" "LJmc" opt_bproof + in + eigen_counter := 1; + permute_ljmc ftree po slist ljmc_subproof + (* the permuaiton result will be appended to the lj proof constructed so far *) + end + in + let po = compute_open [ftree] slist in + tot ftree redord connections po slist + + let reconstruct ftree redord sigmaQ ext_proof logic calculus = + let min_connections = remove_dups_connections ext_proof in + let (opt_bproof,beta_exp,closures) = construct_opt_beta_proof ftree ext_proof in +(* let connections = remove_dups_connections ext_proof in + let bproof,beta_exp,closures = construct_beta_proof ftree connections in + let (opt_bproof,min_connections) = bproof_purity bproof in +*) + if !debug_jprover then + begin + print_endline ""; + print_endline ("Beta proof with number of closures = "^(string_of_int closures)^" and number of beta expansions = "^(string_of_int beta_exp)); +(* print_endline ""; + print_endline ""; + print_beta_proof bproof; + print_endline ""; + print_endline ""; + print_endline "Optimal beta proof: "; + print_endline ""; + print_endline ""; + print_beta_proof opt_bproof; + print_endline ""; + print_endline ""; + print_endline ("Beta proof connections: "); + Format.open_box 0; + print_pairlist min_connections; + print_endline "."; + Format.print_flush(); *) + print_endline ""; + end; + let (newroot_name,unsolved_list) = build_unsolved ftree in + let redord2 = (update newroot_name redord) in (* otherwise we would have a deadlock *) + let (init_tree,init_redord,init_connections,init_unsolved_list) = + purity ftree redord2 min_connections unsolved_list in + begin +(* print_endline ""; + print_endline ""; + print_endline ("Purity connections: "); + Format.open_box 0; + print_pairlist init_connections; + print_endline "."; + print_endline ""; + Format.print_flush(); + print_endline ""; + print_endline ""; +*) +(* it should hold: min_connections = init_connections *) + total init_tree init_redord init_connections sigmaQ + init_unsolved_list logic calculus opt_bproof + end + +(* ***************** REDUCTION ORDERING -- both types **************************** *) + + exception Reflexive + + let rec transitive_irreflexive_closure addset const ordering = + match ordering with + [] -> + [] + | (pos,fset)::r -> + if (pos = const) or (StringSet.mem const fset) then +(* check reflexsivity during transitive closure wrt. addset ONLY!!! *) + if StringSet.mem pos addset then + raise Reflexive + else + (pos,(StringSet.union fset addset))::(transitive_irreflexive_closure addset const r) + else + (pos,fset)::(transitive_irreflexive_closure addset const r) + + let rec search_set var ordering = +(* print_endline var; *) + match ordering with + [] -> + raise (Invalid_argument "Jprover: element in ordering missing") + | (pos,fset)::r -> + if pos = var then + StringSet.add pos fset + else + search_set var r + + let add_sets var const ordering = + let addset = search_set var ordering in + transitive_irreflexive_closure addset const ordering + +(* ************* J ordering ********************************************** *) + + let rec add_arrowsJ (v,vlist) ordering = + match vlist with + [] -> ordering + | f::r -> + if ((String.get f 0)='c') then + let new_ordering = add_sets v f ordering in + add_arrowsJ (v,r) new_ordering + else + add_arrowsJ (v,r) ordering + + let rec add_substJ replace_vars replace_string ordering atom_rel = + match replace_vars with + [] -> ordering + | v::r -> + if (String.get v 1 = 'n') (* don't integrate new variables *) + or (List.exists (fun (x,_,_) -> (x.aname = v)) atom_rel) then (* no reduction ordering at atoms *) + (add_substJ r replace_string ordering atom_rel) + else + let next_ordering = add_arrowsJ (v,replace_string) ordering in + (add_substJ r replace_string next_ordering atom_rel) + + let build_orderingJ replace_vars replace_string ordering atom_rel = + try + add_substJ replace_vars replace_string ordering atom_rel + with Reflexive -> (* only possible in the FO case *) + raise Not_unifiable (*search for alternative string unifiers *) + + let rec build_orderingJ_list substJ ordering atom_rel = + match substJ with + [] -> ordering + | (v,vlist)::r -> + let next_ordering = build_orderingJ [v] vlist ordering atom_rel in + build_orderingJ_list r next_ordering atom_rel + +(* ************* J ordering END ********************************************** *) + +(* ************* quantifier ordering ********************************************** *) + + let rec add_arrowsQ v clist ordering = + match clist with + [] -> ordering + | f::r -> + let new_ordering = add_sets v f ordering in + add_arrowsQ v r new_ordering + + let rec print_sigmaQ sigmaQ = + match sigmaQ with + [] -> + print_endline "." + | (v,term)::r -> + begin + Format.open_box 0; + print_endline " "; + print_string (v^" = "); + print_term stdout term; + Format.force_newline (); + Format.print_flush (); + print_sigmaQ r + end + + let rec print_term_list tlist = + match tlist with + [] -> print_string "." + | t::r -> + begin + print_term stdout t; + print_string " "; + print_term_list r + end + + let rec add_sigmaQ new_elements ordering = + match new_elements with + [] -> ([],ordering) + | (v,termlist)::r -> + let dterms = collect_delta_terms termlist in + begin +(*: print_stringlist dterms; + mbreak "add_sigmaQ:1\n"; + Format.open_box 0; + print_endline " "; + print_endline "sigmaQ: "; + print_string (v^" = "); + print_term_list termlist; + Format.force_newline (); + print_stringlist dterms; + Format.force_newline (); + Format.print_flush (); + mbreak "add_sigmaQ:2\n"; +:*) + let new_ordering = add_arrowsQ v dterms ordering in +(*: print_ordering new_ordering; + mbreak "add_sigmaQ:3\n"; +:*) + let (rest_pairs,rest_ordering) = add_sigmaQ r new_ordering in + ((v,dterms)::rest_pairs),rest_ordering + end + + let build_orderingQ new_elements ordering = +(* new_elements is of type (string * term list) list, since one variable can receive more than *) +(* a single term due to substitution multiplication *) + try +(* print_endline "build orderingQ in"; *) (* apple *) + add_sigmaQ new_elements ordering; + with Reflexive -> + raise Failed (* new connection, please *) + + +(* ************* quantifier ordering END ********************************************** *) + +(* ****** Quantifier unification ************** *) + +(* For multiplication we assume always idempotent substitutions sigma, tau! *) + + let rec collect_assoc inst_vars tauQ = + match inst_vars with + [] -> [] + | f::r -> + let f_term = List.assoc f tauQ in + f_term::(collect_assoc r tauQ) + + let rec rec_apply sigmaQ tauQ tau_vars tau_terms = + match sigmaQ with + [] -> [],[] + | (v,term)::r -> + let app_term = subst term tau_vars tau_terms in + let old_free = free_vars_list term + and new_free = free_vars_list app_term in + let inst_vars = list_diff old_free new_free in + let inst_terms = collect_assoc inst_vars tauQ in + let (rest_sigma,rest_sigma_ordering) = rec_apply r tauQ tau_vars tau_terms in + if inst_terms = [] then + ((v,app_term)::rest_sigma),rest_sigma_ordering + else + let ordering_v = String.sub v 0 (String.index v '_') in + ((v,app_term)::rest_sigma),((ordering_v,inst_terms)::rest_sigma_ordering) + +(* let multiply sigmaQ tauQ = + let tau_vars,tau_terms = List.split tauQ + and sigma_vars,sigma_terms = List.split sigmaQ in + let apply_terms = rec_apply sigma_terms tau_vars tau_terms in + (List.combine sigma_vars apply_terms) @ tauQ +*) + + let multiply sigmaQ tauQ = + let (tau_vars,tau_terms) = List.split tauQ in + let (new_sigmaQ,sigma_ordering) = rec_apply sigmaQ tauQ tau_vars tau_terms in + let tau_ordering_terms = (List.map (fun x -> [x]) tau_terms) (* for extending ordering_elements *) in + let tau_ordering_vars = (List.map (fun x -> String.sub x 0 (String.index x '_')) tau_vars) in + let tau_ordering = (List.combine tau_ordering_vars tau_ordering_terms) in + ((new_sigmaQ @ tauQ), + (sigma_ordering @ tau_ordering) + ) + + let apply_2_sigmaQ term1 term2 sigmaQ = + let sigma_vars,sigma_terms = List.split sigmaQ in + (subst term1 sigma_vars sigma_terms),(subst term2 sigma_vars sigma_terms) + + let jqunify term1 term2 sigmaQ = + let app_term1,app_term2 = apply_2_sigmaQ term1 term2 sigmaQ in + try +(*: let tauQ = unify_mm app_term1 app_term2 String_set.StringSet.empty in :*) + let tauQ = unify_mm app_term1 app_term2 StringSet.empty in + let (mult,oel) = multiply sigmaQ tauQ in + (mult,oel) + with + RefineError _ -> (* any unification failure *) +(* print_endline "fo-unification fail"; *) + raise Failed (* new connection, please *) + +(* ************ T-STRING UNIFICATION ******************************** *) + + let rec combine subst (ov,oslist) = + match subst with + [] -> [],[] + | f::r -> + let (v,slist) = f in + let rest_vlist,rest_combine = (combine r (ov,oslist)) in + if (List.mem ov slist) then (* subst assumed to be idemponent *) + let com_element = com_subst slist (ov,oslist) in + (v::rest_vlist),((v,com_element)::rest_combine) + else + (rest_vlist,(f::rest_combine)) + + let compose sigma one_subst = + let (n,subst)=sigma + and (ov,oslist) = one_subst in + let (trans_vars,com) = combine subst (ov,oslist) + in +(* begin + print_endline "!!!!!!!!!test print!!!!!!!!!!"; + print_subst [one_subst]; + print_subst subst; + print_endline "!!!!!!!!! END test print!!!!!!!!!!"; +*) + if List.mem one_subst subst then + (trans_vars,(n,com)) + else +(* ov may multiply as variable in subst with DIFFERENT values *) +(* in order to avoid explicit atom instances!!! *) + (trans_vars,(n,(com @ [one_subst]))) +(* end *) + + let rec apply_element fs ft (v,slist) = + match (fs,ft) with + ([],[]) -> + ([],[]) + | ([],(ft_first::ft_rest)) -> + let new_ft_first = + if ft_first = v then + slist + else + [ft_first] + in + let (emptylist,new_ft_rest) = apply_element [] ft_rest (v,slist) in + (emptylist,(new_ft_first @ new_ft_rest)) + | ((fs_first::fs_rest),[]) -> + let new_fs_first = + if fs_first = v then + slist + else + [fs_first] + in + let (new_fs_rest,emptylist) = apply_element fs_rest [] (v,slist) in + ((new_fs_first @ new_fs_rest),emptylist) + | ((fs_first::fs_rest),(ft_first::ft_rest)) -> + let new_fs_first = + if fs_first = v then + slist + else + [fs_first] + and new_ft_first = + if ft_first = v then + slist + else + [ft_first] + in + let (new_fs_rest,new_ft_rest) = apply_element fs_rest ft_rest (v,slist) in + ((new_fs_first @ new_fs_rest),(new_ft_first @ new_ft_rest)) + + let rec shorten us ut = + match (us,ut) with + ([],_) -> (us,ut) + | (_,[]) -> (us,ut) + | ((fs::rs),(ft::rt)) -> + if fs = ft then + shorten rs rt + else + (us,ut) + + let rec apply_subst_list eq_rest (v,slist) = + + match eq_rest with + [] -> + (true,[]) + | (atomnames,(fs,ft))::r -> + let (n_fs,n_ft) = apply_element fs ft (v,slist) in + let (new_fs,new_ft) = shorten n_fs n_ft in (* delete equal first elements *) + match (new_fs,new_ft) with + [],[] -> + let (bool,new_eq_rest) = apply_subst_list r (v,slist) in + (bool,((atomnames,([],[]))::new_eq_rest)) + | [],(fft::rft) -> + if (is_const fft) then + (false,[]) + else + let (bool,new_eq_rest) = apply_subst_list r (v,slist) in + (bool,((atomnames,([],new_ft))::new_eq_rest)) + | (ffs::rfs),[] -> + if (is_const ffs) then + (false,[]) + else + let (bool,new_eq_rest) = apply_subst_list r (v,slist) in + (bool,((atomnames,(new_fs,[]))::new_eq_rest)) + | (ffs::rfs),(fft::rft) -> + if (is_const ffs) & (is_const fft) then + (false,[]) + (* different first constants cause local fail *) + else + (* at least one of firsts is a variable *) + let (bool,new_eq_rest) = apply_subst_list r (v,slist) in + (bool,((atomnames,(new_fs,new_ft))::new_eq_rest)) + + let apply_subst eq_rest (v,slist) atomnames = + if (List.mem v atomnames) then (* don't apply subst to atom variables !! *) + (true,eq_rest) + else + apply_subst_list eq_rest (v,slist) + + let all_variable_check eqlist = false (* needs some discussion with Jens! -- NOT done *) + +(* + let rec all_variable_check eqlist = + match eqlist with + [] -> true + | ((_,(fs,ft))::rest_eq) -> + if (fs <> []) & (ft <> []) then + let fs_first = List.hd fs + and ft_first = List.hd ft + in + if (is_const fs_first) or (is_const ft_first) then + false + else + all_variable_check rest_eq + else + false +*) + + let rec tunify_list eqlist init_sigma orderingQ atom_rel = + + let rec tunify atomnames fs ft rt rest_eq sigma ordering = + + let apply_r1 fs ft rt rest_eq sigma = +(* print_endline "r1"; *) + tunify_list rest_eq sigma ordering atom_rel + + in + let apply_r2 fs ft rt rest_eq sigma = +(* print_endline "r2"; *) + tunify atomnames rt fs ft rest_eq sigma ordering + + in + let apply_r3 fs ft rt rest_eq sigma = +(* print_endline "r3"; *) + let rfs = (List.tl fs) + and rft = (List.tl rt) in + tunify atomnames rfs ft rft rest_eq sigma ordering + + in + let apply_r4 fs ft rt rest_eq sigma = +(* print_endline "r4"; *) + tunify atomnames rt ft fs rest_eq sigma ordering + + in + let apply_r5 fs ft rt rest_eq sigma = +(* print_endline "r5"; *) + let v = (List.hd fs) in + let (compose_vars,new_sigma) = compose sigma (v,ft) in + let (bool,new_rest_eq) = apply_subst rest_eq (v,ft) atomnames in + if (bool=false) then + raise Not_unifiable + else + let new_ordering = build_orderingJ (v::compose_vars) ft ordering atom_rel in + tunify atomnames (List.tl fs) rt rt new_rest_eq new_sigma new_ordering + + in + let apply_r6 fs ft rt rest_eq sigma = +(* print_endline "r6"; *) + let v = (List.hd fs) in + let (_,new_sigma) = (compose sigma (v,[])) in + let (bool,new_rest_eq) = apply_subst rest_eq (v,[]) atomnames in + if (bool=false) then + raise Not_unifiable + else + (* no relation update since [] has been replaced for v *) + tunify atomnames (List.tl fs) ft rt new_rest_eq new_sigma ordering + + in + let apply_r7 fs ft rt rest_eq sigma = +(* print_endline "r7"; *) + let v = (List.hd fs) + and c1 = (List.hd rt) + and c2t =(List.tl rt) in + let (compose_vars,new_sigma) = (compose sigma (v,(ft @ [c1]))) in + let (bool,new_rest_eq) = apply_subst rest_eq (v,(ft @ [c1])) atomnames in + if bool=false then + raise Not_unifiable + else + let new_ordering = build_orderingJ (v::compose_vars) (ft @ [c1]) ordering atom_rel in + tunify atomnames (List.tl fs) [] c2t new_rest_eq new_sigma new_ordering + + + in + let apply_r8 fs ft rt rest_eq sigma = +(* print_endline "r8"; *) + tunify atomnames rt [(List.hd fs)] (List.tl fs) rest_eq sigma ordering + + in + let apply_r9 fs ft rt rest_eq sigma = +(* print_endline "r9"; *) + let v = (List.hd fs) + and (max,subst) = sigma in + let v_new = ("vnew"^(string_of_int max)) in + let (compose_vars,new_sigma) = (compose ((max+1),subst) (v,(ft @ [v_new]))) in + let (bool,new_rest_eq) = apply_subst rest_eq (v,(ft @ [v_new])) atomnames in + if (bool=false) then + raise Not_unifiable + else + let new_ordering = + build_orderingJ (v::compose_vars) (ft @ [v_new]) ordering atom_rel in + tunify atomnames rt [v_new] (List.tl fs) new_rest_eq new_sigma new_ordering + + in + let apply_r10 fs ft rt rest_eq sigma = +(* print_endline "r10"; *) + let x = List.hd rt in + tunify atomnames fs (ft @ [x]) (List.tl rt) rest_eq sigma ordering + + in + if r_1 fs ft rt then + apply_r1 fs ft rt rest_eq sigma + else if r_2 fs ft rt then + apply_r2 fs ft rt rest_eq sigma + else if r_3 fs ft rt then + apply_r3 fs ft rt rest_eq sigma + else if r_4 fs ft rt then + apply_r4 fs ft rt rest_eq sigma + else if r_5 fs ft rt then + apply_r5 fs ft rt rest_eq sigma + else if r_6 fs ft rt then + (try + apply_r6 fs ft rt rest_eq sigma + with Not_unifiable -> + if r_7 fs ft rt then (* r7 applicable if r6 was and tr6 = C2t' *) + (try + apply_r7 fs ft rt rest_eq sigma + with Not_unifiable -> + apply_r10 fs ft rt rest_eq sigma (* r10 always applicable if r6 was *) + ) + else +(* r10 could be represented only once if we would try it before r7.*) +(* but looking at the transformation rules, r10 should be tried at last in any case *) + apply_r10 fs ft rt rest_eq sigma (* r10 always applicable r6 was *) + ) + else if r_7 fs ft rt then (* not r6 and r7 possible if z <> [] *) + (try + apply_r7 fs ft rt rest_eq sigma + with Not_unifiable -> + apply_r10 fs ft rt rest_eq sigma (* r10 always applicable if r7 was *) + ) + else if r_8 fs ft rt then + (try + apply_r8 fs ft rt rest_eq sigma + with Not_unifiable -> + if r_10 fs ft rt then (* r10 applicable if r8 was and tr8 <> [] *) + apply_r10 fs ft rt rest_eq sigma + else + raise Not_unifiable (* simply back propagation *) + ) + else if r_9 fs ft rt then + (try + apply_r9 fs ft rt rest_eq sigma + with Not_unifiable -> + if r_10 fs ft rt then (* r10 applicable if r9 was and tr9 <> [] *) + apply_r10 fs ft rt rest_eq sigma + else + raise Not_unifiable (* simply back propagation *) + ) + + + else + if r_10 fs ft rt then (* not ri, i<10, and r10 possible if for instance *) + (* (s=[] and x=v1) or (z<>[] and xt=C1V1t') *) + apply_r10 fs ft rt rest_eq sigma + else (* NO rule applicable *) + raise Not_unifiable + in + match eqlist with + [] -> + init_sigma,orderingQ + | f::rest_eq -> + begin +(* Format.open_box 0; + print_equations [f]; + Format.print_flush (); +*) + let (atomnames,(fs,ft)) = f in + tunify atomnames fs [] ft rest_eq init_sigma orderingQ + end + +let rec test_apply_eq atomnames eqs eqt subst = + match subst with + [] -> (eqs,eqt) + | (f,flist)::r -> + let (first_appl_eqs,first_appl_eqt) = + if List.mem f atomnames then + (eqs,eqt) + else + (apply_element eqs eqt (f,flist)) + in + test_apply_eq atomnames first_appl_eqs first_appl_eqt r + +let rec test_apply_eqsubst eqlist subst = + match eqlist with + [] -> [] + | f::r -> + let (atomnames,(eqs,eqt)) = f in + let applied_element = test_apply_eq atomnames eqs eqt subst in + (atomnames,applied_element)::(test_apply_eqsubst r subst) + +let ttest us ut ns nt eqlist orderingQ atom_rel = + let (short_us,short_ut) = shorten us ut in (* apply intial rule R3 *) + (* to eliminate common beginning *) + let new_element = ([ns;nt],(short_us,short_ut)) in + let full_eqlist = + if List.mem new_element eqlist then + eqlist + else + new_element::eqlist + in + let (sigma,_) = tunify_list full_eqlist (1,[]) orderingQ atom_rel in + let (n,subst) = sigma in + let test_apply = test_apply_eqsubst full_eqlist subst in + begin + print_endline ""; + print_endline "Final equations:"; + print_equations full_eqlist; + print_endline ""; + print_endline "Final substitution:"; + print_tunify sigma; + print_endline ""; + print_endline "Applied equations:"; + print_equations test_apply + end + +let do_stringunify us ut ns nt equations fo_eqlist orderingQ atom_rel qmax = + let (short_us,short_ut) = shorten us ut in (* apply intial rule R3 to eliminate common beginning *) + let new_element = ([ns;nt],(short_us,short_ut)) in + let full_eqlist = + if List.mem new_element equations then + equations @ fo_eqlist + else + (new_element::equations) @ fo_eqlist + in + try +(* print_equations full_eqlist; *) +(* max-1 new variables have been used for the domain equations *) + let (new_sigma,new_ordering) = tunify_list full_eqlist (1,[]) orderingQ atom_rel in +(* sigmaQ will not be returned in eqlist *) + (new_sigma,(qmax,full_eqlist),new_ordering) + with Not_unifiable -> + raise Failed (* new connection please *) + +let rec one_equation gprefix dlist delta_0_prefixes n = + match dlist with + [] -> ([],n) + | f::r -> + let fprefix = List.assoc f delta_0_prefixes in + let (sf1,sg) = shorten fprefix gprefix + and v_new = ("vnewq"^(string_of_int n)) in + let fnew = sf1 @ [v_new] in + let (rest_equations,new_n) = one_equation gprefix r delta_0_prefixes (n+1) in + (([],(fnew,sg))::rest_equations),new_n + +let rec make_domain_equations fo_pairs (gamma_0_prefixes,delta_0_prefixes) n = + match fo_pairs with + [] -> ([],n) + | (g,dlist)::r -> + let gprefix = List.assoc g gamma_0_prefixes in + let (gequations,max) = one_equation gprefix dlist delta_0_prefixes n in + let (rest_equations,new_max) = + make_domain_equations r (gamma_0_prefixes,delta_0_prefixes) max in + (gequations @ rest_equations),new_max + +(* type of one unifier: int * ((string * string list) list) *) +(* global failure: (0,[]) *) + +let stringunify ext_atom try_one eqlist fo_pairs logic orderingQ atom_rel qprefixes = + if logic = "C" then + ((0,[]),(0,[]),orderingQ) + else + let (qmax,equations) = eqlist + and us = ext_atom.aprefix + and ut = try_one.aprefix + and ns = ext_atom.aname + and nt = try_one.aname in + if qprefixes = ([],[]) then (* prop case *) + begin +(* print_endline "This is the prop case"; *) + let (new_sigma,new_eqlist) = Jtunify.do_stringunify us ut ns nt equations + (* prop unification only *) + in + (new_sigma,new_eqlist,[]) (* assume the empty reduction ordering during proof search *) + end + else + begin +(* print_endline "This is the FO case"; *) +(* fo_eqlist encodes the domain condition on J quantifier substitutions *) +(* Again, always computed for the whole substitution sigmaQ *) + let (fo_eqlist,new_max) = make_domain_equations fo_pairs qprefixes qmax in + begin +(* Format.open_box 0; + print_string "domain equations in"; + print_equations fo_eqlist; + print_string "domain equations out"; + Format.print_flush (); +*) + do_stringunify us ut ns nt equations fo_eqlist orderingQ atom_rel new_max + end + end + +(**************************************** add multiplicity *********************************) + +let rec subst_replace subst_list t = + match subst_list with + [] -> t + | (old_t,new_t)::r -> + let inter_term = var_subst t old_t "dummy" in +(*: print_string "("; + print_term stdout old_t; + print_string " --> "; + print_term stdout new_t; + print_string ")\n"; + print_term stdout t; + print_newline (); + print_term stdout inter_term; + print_newline (); :*) + let new_term = subst1 inter_term "dummy" new_t in +(*: print_term stdout new_term; + print_newline (); + mbreak "\n+++========----- ---------..........\n"; :*) + subst_replace r new_term + +let rename_pos x m = + let pref = String.get x 0 in + (Char.escaped pref)^(string_of_int m) + +let update_position position m replace_n subst_list mult = + let ({name=x; address=y; op=z; pol=p; pt=a; st=b; label=t}) = position in + let nx = rename_pos x m in + let nsubst_list = + if b=Gamma_0 then + let vx = mk_var_term (x^"_jprover") + and vnx = mk_var_term (nx^"_jprover") in + (vx,vnx)::subst_list + else + if b=Delta_0 then + let sx = mk_string_term jprover_op x + and snx = mk_string_term jprover_op nx in + (sx,snx)::subst_list + else + subst_list + in + let nt = subst_replace nsubst_list t in + let add_array = Array.of_list y in + let _ = (add_array.(replace_n) <- mult) in + let new_add = Array.to_list add_array in + ({name=nx; address=new_add; op=z; pol=p; pt=a; st=b; label=nt},m,nsubst_list) + +let rec append_orderings list_of_lists = + match list_of_lists with + [] -> + [] + | f::r -> + f @ (append_orderings r) + +let rec union_orderings first_orderings = + match first_orderings with + [] -> + StringSet.empty + | (pos,fset)::r -> + StringSet.union (StringSet.add pos fset) (union_orderings r) + +let rec select_orderings add_orderings = + match add_orderings with + [] -> [] + | f::r -> + (List.hd f)::select_orderings r + +let combine_ordering_list add_orderings pos_name = + let first_orderings = select_orderings add_orderings in + let pos_succs = union_orderings first_orderings in + let rest_orderings = append_orderings add_orderings in + (pos_name,pos_succs)::rest_orderings + +let rec copy_and_rename_tree last_tree replace_n pos_n mult subst_list = + + let rec rename_subtrees tree_list nposition s_pos_n nsubst_list = + match tree_list with + [] -> ([||],[],s_pos_n) + | f::r -> + let (f_subtree,f_ordering,f_pos_n) = + copy_and_rename_tree f replace_n s_pos_n mult nsubst_list in + let (r_subtrees,r_ordering_list,r_pos_n) = rename_subtrees r nposition f_pos_n nsubst_list in + ((Array.append [|f_subtree|] r_subtrees),(f_ordering::r_ordering_list),r_pos_n) + + in + match last_tree with + Empty -> raise (Invalid_argument "Jprover: copy tree") + | NodeAt(position) -> (* can never be a Gamma_0 position -> no replacements *) + let (nposition,npos_n,_) = update_position position (pos_n+1) replace_n subst_list mult in + ((NodeAt(nposition)),[(nposition.name,StringSet.empty)],npos_n) + | NodeA(position, suctrees) -> + let (nposition,npos_n,nsubst_list) = update_position position (pos_n+1) replace_n subst_list mult in + let (new_suctrees, new_ordering_list, new_pos_n) = + rename_subtrees (Array.to_list suctrees) nposition npos_n nsubst_list in + let new_ordering = combine_ordering_list new_ordering_list (nposition.name) in + ((NodeA(nposition,new_suctrees)),new_ordering,new_pos_n) + +(* we construct for each pos a list orderings representing and correspondning to the array of succtrees *) + +let rec add_multiplicity ftree pos_n mult logic = + let rec parse_subtrees tree_list s_pos_n = + match tree_list with + [] -> ([||],[],s_pos_n) + | f::r -> + let (f_subtree,f_ordering,f_pos_n) = add_multiplicity f s_pos_n mult logic in + let (r_subtrees,r_ordering_list,r_pos_n) = parse_subtrees r f_pos_n in + ((Array.append [|f_subtree|] r_subtrees),(f_ordering::r_ordering_list),r_pos_n) + + in + match ftree with + Empty -> raise (Invalid_argument "Jprover: add mult") + | NodeAt(pos) -> (ftree,[(pos.name,StringSet.empty)],pos_n) + | NodeA(pos,suctrees) -> + let (new_suctrees, new_ordering_list, new_pos_n) = parse_subtrees (Array.to_list suctrees) pos_n in + if (((pos.pt = Phi) & (((pos.op <> At) & (logic="J")) or ((pos.op = All) & (logic = "C")))) + (* no explicit atom-instances *) + or ((pos.pt = Gamma) & (pos.st <> Phi_0))) then (* universal quantifiers are copied *) + (* at their Phi positions *) + let replace_n = (List.length pos.address) (* points to the following argument in the array_of_address *) + and last = (Array.length new_suctrees) - 1 in (* array first element has index 0 *) + let last_tree = new_suctrees.(last) in + let (add_tree,add_ordering,final_pos_n) = + copy_and_rename_tree last_tree replace_n new_pos_n mult [] in + let final_suctrees = Array.append new_suctrees [|add_tree|] + and add_orderings = List.append new_ordering_list [add_ordering] in + let final_ordering = combine_ordering_list add_orderings (pos.name) in + ((NodeA(pos,final_suctrees)),final_ordering,final_pos_n) + else + let final_ordering = combine_ordering_list new_ordering_list (pos.name) in + ((NodeA(pos,new_suctrees)),final_ordering,new_pos_n) + + +(************** Path checker ****************************************************) + +let rec get_sets atom atom_sets = + match atom_sets with + [] -> raise (Invalid_argument "Jprover bug: atom not found") + | f::r -> + let (a,b,c) = f in + if atom = a then f + else + get_sets atom r + +let rec get_connections a alpha tabulist = + match alpha with + [] -> [] + | f::r -> + if (a.apredicate = f.apredicate) & (a.apol <> f.apol) & (not (List.mem f tabulist)) then + (a,f)::(get_connections a r tabulist) + else + (get_connections a r tabulist) + +let rec connections atom_rel tabulist = + match atom_rel with + [] -> [] + | f::r -> + let (a,alpha,beta) = f in + (get_connections a alpha tabulist) @ (connections r (a::tabulist)) + +let check_alpha_relation atom set atom_sets = + let (a,alpha,beta) = get_sets atom atom_sets in + AtomSet.subset set alpha + +let rec extset atom_sets path closed = + match atom_sets with + [] -> AtomSet.empty + | f::r -> + let (at,alpha,beta) = f in + if (AtomSet.subset path alpha) & (AtomSet.subset closed beta) then + AtomSet.add at (extset r path closed) + else + (extset r path closed) + +let rec check_ext_list ext_list fail_set atom_sets = (* fail_set consists of one atom only *) + match ext_list with + [] -> AtomSet.empty + | f::r -> + if (check_alpha_relation f fail_set atom_sets) then + AtomSet.add f (check_ext_list r fail_set atom_sets) + else + (check_ext_list r fail_set atom_sets) + +let fail_ext_set ext_atom ext_set atom_sets = + let ext_list = AtomSet.elements ext_set + and fail_set = AtomSet.add ext_atom AtomSet.empty in + check_ext_list ext_list fail_set atom_sets + +let rec ext_partners con path ext_atom (reduction_partners,extension_partners) atom_sets = + match con with + [] -> + (reduction_partners,extension_partners) + | f::r -> + let (a,b) = f in + if List.mem ext_atom [a;b] then + let ext_partner = + if ext_atom = a then b else a + in + let (new_red_partners,new_ext_partners) = +(* force reduction steps first *) + if (AtomSet.mem ext_partner path) then + ((AtomSet.add ext_partner reduction_partners),extension_partners) + else + if (check_alpha_relation ext_partner path atom_sets) then + (reduction_partners,(AtomSet.add ext_partner extension_partners)) + else + (reduction_partners,extension_partners) + in + ext_partners r path ext_atom (new_red_partners,new_ext_partners) atom_sets + else + ext_partners r path ext_atom (reduction_partners,extension_partners) atom_sets + +exception Failed_connections + +let path_checker atom_rel atom_sets qprefixes init_ordering logic = + + let con = connections atom_rel [] in +(*: print_endline ""; + print_endline ("number of connections: "^(string_of_int (List.length con))); + mbreak "#connec\n"; +:*) + let rec provable path closed (orderingQ,reduction_ordering) eqlist (sigmaQ,sigmaJ) = + + let rec check_connections (reduction_partners,extension_partners) ext_atom = + let try_one = + if reduction_partners = AtomSet.empty then + if extension_partners = AtomSet.empty then + raise Failed_connections + else + AtomSet.choose extension_partners + else + (* force reduction steps always first!! *) + AtomSet.choose reduction_partners + in +(* print_endline ("connection partner "^(try_one.aname)); *) +(* print_endline ("partner path "^(print_set path)); +*) + (try + let (new_sigmaQ,new_ordering_elements) = jqunify (ext_atom.alabel) (try_one.alabel) sigmaQ in +(* build the orderingQ incrementally from the new added substitution tau of new_sigmaQ *) + let (relate_pairs,new_orderingQ) = build_orderingQ new_ordering_elements orderingQ in +(* we make in incremental reflexivity test during the string unification *) + let (new_sigmaJ,new_eqlist,new_red_ordering) = +(* new_red_ordering = [] in propositional case *) + stringunify ext_atom try_one eqlist relate_pairs logic new_orderingQ atom_rel qprefixes + in +(* print_endline ("make reduction ordering "^((string_of_int (List.length new_ordering)))); *) + let new_closed = AtomSet.add ext_atom closed in + let ((next_orderingQ,next_red_ordering),next_eqlist,(next_sigmaQ,next_sigmaJ),subproof) = + if AtomSet.mem try_one path then + provable path new_closed (new_orderingQ,new_red_ordering) new_eqlist (new_sigmaQ,new_sigmaJ) + (* always use old first-order ordering for recursion *) + else + let new_path = AtomSet.add ext_atom path + and extension = AtomSet.add try_one AtomSet.empty in + let ((norderingQ,nredordering),neqlist,(nsigmaQ,nsigmaJ),p1) = + provable new_path extension (new_orderingQ,new_red_ordering) new_eqlist (new_sigmaQ,new_sigmaJ) in + let ((nnorderingQ,nnredordering),nneqlist,(nnsigmaQ,nnsigmaJ),p2) = + provable path new_closed (norderingQ,nredordering) neqlist (nsigmaQ,nsigmaJ) in + ((nnorderingQ,nnredordering),nneqlist,(nnsigmaQ,nnsigmaJ),(p1 @ p2)) + (* first the extension subgoals = depth first; then other subgoals in same clause *) + in + ((next_orderingQ,next_red_ordering),next_eqlist,(next_sigmaQ,next_sigmaJ),(((ext_atom.aname),(try_one.aname))::subproof)) + with Failed -> +(* print_endline ("new connection for "^(ext_atom.aname)); *) +(* print_endline ("Failed"); *) + check_connections ((AtomSet.remove try_one reduction_partners), + (AtomSet.remove try_one extension_partners) + ) ext_atom + ) + + in + let rec check_extension extset = + if extset = AtomSet.empty then + raise Failed (* go directly to a new entry connection *) + else + let select_one = AtomSet.choose extset in +(* print_endline ("extension literal "^(select_one.aname)); *) +(* print_endline ("extension path "^(print_set path));*) + let (reduction_partners,extension_partners) = + ext_partners con path select_one (AtomSet.empty,AtomSet.empty) atom_sets in + (try + check_connections (reduction_partners,extension_partners) select_one + with Failed_connections -> +(* print_endline ("no connections for subgoal "^(select_one.aname)); *) +(* print_endline ("Failed_connections"); *) + let fail_ext_set = fail_ext_set select_one extset atom_sets in + check_extension fail_ext_set + ) + + in + let extset = extset atom_sets path closed in + if extset = AtomSet.empty then + ((orderingQ,reduction_ordering),eqlist,(sigmaQ,sigmaJ),[]) + else + check_extension extset + in + if qprefixes = ([],[]) then + begin +(* print_endline "!!!!!!!!!!! prop prover !!!!!!!!!!!!!!!!!!"; *) +(* in the propositional case, the reduction ordering will be computed AFTER proof search *) + let (_,eqlist,(_,(n,substJ)),ext_proof) = + provable AtomSet.empty AtomSet.empty ([],[]) (1,[]) ([],(1,[])) in + let orderingJ = build_orderingJ_list substJ init_ordering atom_rel in + ((init_ordering,orderingJ),eqlist,([],(n,substJ)),ext_proof) + end + else + provable AtomSet.empty AtomSet.empty (init_ordering,[]) (1,[]) ([],(1,[])) + +(*************************** prepare and init prover *******************************************************) + +let rec list_to_set list = + match list with + [] -> AtomSet.empty + | f::r -> + let rest_set = list_to_set r in + AtomSet.add f rest_set + +let rec make_atom_sets atom_rel = + match atom_rel with + [] -> [] + | f::r -> + let (a,alpha,beta) = f in + (a,(list_to_set alpha),(list_to_set beta))::(make_atom_sets r) + +let rec predecessor address_1 address_2 ftree = + match ftree with + Empty -> PNull (* should not occur since every pair of atoms have a common predecessor *) + | NodeAt(position) -> PNull (* should not occur as above *) + | NodeA(position,suctrees) -> + match address_1,address_2 with + [],_ -> raise (Invalid_argument "Jprover: predecessors left") + | _,[] -> raise (Invalid_argument "Jprover: predecessors right") + | (f1::r1),(f2::r2) -> + if f1 = f2 then + predecessor r1 r2 (suctrees.(f1-1)) + else + position.pt + +let rec compute_sets element ftree alist = + match alist with + [] -> [],[] + | first::rest -> + if first = element then + compute_sets element ftree rest (* element is neithes alpha- nor beta-related to itself*) + else + let (alpha_rest,beta_rest) = compute_sets element ftree rest in + if predecessor (element.aaddress) (first.aaddress) ftree = Beta then + (alpha_rest,(first::beta_rest)) + else + ((first::alpha_rest),beta_rest) + +let rec compute_atomlist_relations worklist ftree alist = (* last version of alist for total comparison *) + let rec compute_atom_relations element ftree alist = + let alpha_set,beta_set = compute_sets element ftree alist in + (element,alpha_set,beta_set) + in + match worklist with + [] -> [] + | first::rest -> + let first_relations = compute_atom_relations first ftree alist in + first_relations::(compute_atomlist_relations rest ftree alist) + +let atom_record position prefix = + let aname = (position.name) in + let aprefix = (List.append prefix [aname]) in (* atom position is last element in prefix *) + let aop = (dest_term position.label).term_op in + ({aname=aname; aaddress=(position.address); aprefix=aprefix; apredicate=aop; + apol=(position.pol); ast=(position.st); alabel=(position.label)}) + +let rec select_atoms_treelist treelist prefix = + let rec select_atoms ftree prefix = + match ftree with + Empty -> [],[],[] + | NodeAt(position) -> + [(atom_record position prefix)],[],[] + | NodeA(position,suctrees) -> + let treelist = Array.to_list suctrees in + let new_prefix = + let prefix_element = + if List.mem (position.st) [Psi_0;Phi_0] then + [(position.name)] + else + [] + in + (List.append prefix prefix_element) + in + let (gamma_0_element,delta_0_element) = + if position.st = Gamma_0 then + begin +(* Format.open_box 0; + print_endline "gamma_0 prefixes "; + print_string (position.name^" :"); + print_stringlist prefix; + print_endline " "; + Format.force_newline (); + Format.print_flush (); +*) + [(position.name,prefix)],[] + end + else + if position.st = Delta_0 then + begin +(* Format.open_box 0; + print_endline "delta_0 prefixes "; + print_string (position.name^" :"); + print_stringlist prefix; + print_endline " "; + Format.force_newline (); + Format.print_flush (); +*) + [],[(position.name,prefix)] + end + else + [],[] + in + let (rest_alist,rest_gamma_0_prefixes,rest_delta_0_prefixes) = + select_atoms_treelist treelist new_prefix in + (rest_alist,(rest_gamma_0_prefixes @ gamma_0_element), + (rest_delta_0_prefixes @ delta_0_element)) + + in + match treelist with + [] -> [],[],[] + | first::rest -> + let (first_alist,first_gprefixes,first_dprefixes) = select_atoms first prefix + and (rest_alist,rest_gprefixes,rest_dprefixes) = select_atoms_treelist rest prefix in + ((first_alist @ rest_alist),(first_gprefixes @ rest_gprefixes), + (first_dprefixes @ rest_dprefixes)) + +let prepare_prover ftree = + let alist,gamma_0_prefixes,delta_0_prefixes = select_atoms_treelist [ftree] [] in + let atom_rel = compute_atomlist_relations alist ftree alist in + (atom_rel,(gamma_0_prefixes,delta_0_prefixes)) + +(* ************************ Build intial formula tree and relations *********************************** *) +(* Building a formula tree and the tree ordering from the input formula, i.e. OCaml term *) + +let make_position_name stype pos_n = + let prefix = + if List.mem stype [Phi_0;Gamma_0] + then "v" + else + if List.mem stype [Psi_0;Delta_0] + then "c" + else + "a" + in + prefix^(string_of_int pos_n) + +let dual_pol pol = + if pol = O then I else O + +let check_subst_term (variable,old_term) pos_name stype = + if (List.mem stype [Gamma_0;Delta_0]) then + let new_variable = + if stype = Gamma_0 then (mk_var_term (pos_name^"_jprover")) + else + (mk_string_term jprover_op pos_name) + in + (subst1 old_term variable new_variable) (* replace variable (non-empty) in t by pos_name *) + (* pos_name is either a variable term or a constant, f.i. a string term *) + (* !!! check unification module how handling eingenvariables as constants !!! *) + else + old_term + +let rec build_ftree (variable,old_term) pol stype address pos_n = + let pos_name = make_position_name stype pos_n in + let term = check_subst_term (variable,old_term) pos_name stype in + if JLogic.is_and_term term then + let s,t = JLogic.dest_and term in + let ptype,stype_1,stype_2 = + if pol = O + then Beta,Beta_1,Beta_2 + else + Alpha,Alpha_1,Alpha_2 + in + let position = {name=pos_name; address=address; op=And; pol=pol; pt=ptype; st=stype; label=term} in + let subtree_left,ordering_left,posn_left = build_ftree ("",s) pol stype_1 (address@[1]) (pos_n+1) in + let subtree_right,ordering_right,posn_right = build_ftree ("",t) pol stype_2 (address@[2]) + (posn_left+1) in + let (succ_left,whole_left) = List.hd ordering_left + and (succ_right,whole_right) = List.hd ordering_right in + let pos_succs = + (StringSet.add succ_left (StringSet.add succ_right (StringSet.union whole_left whole_right))) + in + (NodeA(position,[|subtree_left;subtree_right|]), + ((position.name,pos_succs)::(ordering_left @ ordering_right)), + posn_right + ) + else + if JLogic.is_or_term term then + let s,t = JLogic.dest_or term in + let ptype,stype_1,stype_2 = + if pol = O + then Alpha,Alpha_1,Alpha_2 + else + Beta,Beta_1,Beta_2 + in + let position = {name=pos_name; address=address; op=Or; pol=pol; pt=ptype; st=stype; label=term} in + let subtree_left,ordering_left,posn_left = build_ftree ("",s) pol stype_1 (address@[1]) (pos_n+1) in + let subtree_right,ordering_right,posn_right = build_ftree ("",t) pol stype_2 (address@[2]) + (posn_left+1) in + let (succ_left,whole_left) = List.hd ordering_left + and (succ_right,whole_right) = List.hd ordering_right in + let pos_succs = + StringSet.add succ_left (StringSet.add succ_right (StringSet.union whole_left whole_right)) in + (NodeA(position,[|subtree_left;subtree_right|]), + ((position.name),pos_succs) :: (ordering_left @ ordering_right), + posn_right + ) + else + if JLogic.is_implies_term term then + let s,t = JLogic.dest_implies term in + let ptype_0,stype_0,ptype,stype_1,stype_2 = + if pol = O + then Psi,Psi_0,Alpha,Alpha_1,Alpha_2 + else + Phi,Phi_0,Beta,Beta_1,Beta_2 + in + let pos2_name = make_position_name stype_0 (pos_n+1) in + let sposition = {name=pos_name; address=address; op=Imp; pol=pol; pt=ptype_0; st=stype; label=term} + and position = {name=pos2_name; address=address@[1]; op=Imp; pol=pol; pt=ptype; st=stype_0; label=term} in + let subtree_left,ordering_left,posn_left = build_ftree ("",s) (dual_pol pol) stype_1 (address@[1;1]) + (pos_n+2) in + let subtree_right,ordering_right,posn_right = build_ftree ("",t) pol stype_2 (address@[1;2]) + (posn_left+1) in + let (succ_left,whole_left) = List.hd ordering_left + and (succ_right,whole_right) = List.hd ordering_right in + let pos_succs = + StringSet.add succ_left (StringSet.add succ_right (StringSet.union whole_left whole_right)) in + let pos_ordering = (position.name,pos_succs) :: (ordering_left @ ordering_right) in + (NodeA(sposition,[|NodeA(position,[|subtree_left;subtree_right|])|]), + ((sposition.name,(StringSet.add position.name pos_succs))::pos_ordering), + posn_right + ) + else + if JLogic.is_not_term term then + let s = JLogic.dest_not term in + let ptype_0,stype_0,ptype,stype_1= + if pol = O + then Psi,Psi_0,Alpha,Alpha_1 + else + Phi,Phi_0,Alpha,Alpha_1 + in + let pos2_name = make_position_name stype_0 (pos_n+1) in + let sposition = {name=pos_name; address=address; op=Neg; pol=pol; pt=ptype_0; st=stype; label=term} + and position = {name=pos2_name; address=address@[1]; op=Neg; pol=pol; pt=ptype; st=stype_0; label=term} in + let subtree_left,ordering_left,posn_left = build_ftree ("",s) (dual_pol pol) stype_1 (address@[1;1]) + (pos_n+2) in + let (succ_left,whole_left) = List.hd ordering_left in + let pos_succs = + StringSet.add succ_left whole_left in + let pos_ordering = (position.name,pos_succs) :: ordering_left in + (NodeA(sposition,[|NodeA(position,[| subtree_left|])|]), + ((sposition.name,(StringSet.add position.name pos_succs))::pos_ordering), + posn_left + ) + else + if JLogic.is_exists_term term then + let v,s,t = JLogic.dest_exists term in (* s is type of v and will be supressed here *) + let ptype,stype_1 = + if pol = O + then Gamma,Gamma_0 + else + Delta,Delta_0 + in + let position = {name=pos_name; address=address; op=Ex; pol=pol; pt=ptype; st=stype; label=term} in + let subtree_left,ordering_left,posn_left = build_ftree (v,t) pol stype_1 (address@[1]) (pos_n+1) in + let (succ_left,whole_left) = List.hd ordering_left in + let pos_succs = + StringSet.add succ_left whole_left in + (NodeA(position,[|subtree_left|]), + ((position.name,pos_succs) :: ordering_left), + posn_left + ) + else + if JLogic.is_all_term term then + let v,s,t = JLogic.dest_all term in + (* s is type of v and will be supressed here *) + let ptype_0,stype_0,ptype,stype_1= + if pol = O + then Psi,Psi_0,Delta,Delta_0 + else + Phi,Phi_0,Gamma,Gamma_0 + in + let pos2_name = make_position_name stype_0 (pos_n+1) in + let sposition = {name=pos_name; address=address; op=All; pol=pol; pt=ptype_0; st=stype; label=term} + and position = {name=pos2_name; address=address@[1]; op=All; pol=pol; pt=ptype; st=stype_0; label=term} in + let subtree_left,ordering_left,posn_left = build_ftree (v,t) pol stype_1 (address@[1;1]) + (pos_n+2) in + let (succ_left,whole_left) = List.hd ordering_left in + let pos_succs = + StringSet.add succ_left whole_left in + let pos_ordering = (position.name,pos_succs) :: ordering_left in + (NodeA(sposition,[|NodeA(position,[|subtree_left|])|]), + ((sposition.name,(StringSet.add position.name pos_succs))::pos_ordering), + posn_left + ) + else (* finally, term is atomic *) + let ptype_0,stype_0 = + if pol = O + then Psi,Psi_0 + else + Phi,Phi_0 + in + let pos2_name = make_position_name stype_0 (pos_n+1) in + let sposition = {name=pos_name; address=address; op=At; pol=pol; pt=ptype_0; st=stype; label=term} + and position = {name=pos2_name; address=address@[1]; op=At; pol=pol; pt=PNull; st=stype_0; label=term} in + (NodeA(sposition,[|NodeAt(position)|]), + [(sposition.name,(StringSet.add position.name StringSet.empty));(position.name,StringSet.empty)], + pos_n+1 + ) + +let rec construct_ftree termlist treelist orderinglist pos_n goal = + match termlist with + [] -> + let new_root = {name="w"; address=[]; op=Null; pol=O; pt=Psi; st=PNull_0; label=goal} + and treearray = Array.of_list treelist in + NodeA(new_root,treearray),(("w",(union_orderings orderinglist))::orderinglist),pos_n + | ft::rest_terms -> + let next_address = [((List.length treelist)+1)] + and next_pol,next_goal = + if rest_terms = [] then + O,ft (* construct tree for the conclusion *) + else + I,goal + in + let new_tree,new_ordering,new_pos_n = + build_ftree ("",ft) next_pol Alpha_1 next_address (pos_n+1) in + construct_ftree rest_terms (treelist @ [new_tree]) + (orderinglist @ new_ordering) new_pos_n next_goal + +(*************************** Main LOOP ************************************) +let unprovable = RefineError ("Jprover", StringError "formula is not provable") +let mult_limit_exn = RefineError ("Jprover", StringError "multiplicity limit reached") +let coq_exn = RefineError ("Jprover", StringError "interface for coq: error on ") + +let init_prover ftree = + let atom_relation,qprefixes = prepare_prover ftree in +(* print_atom_info atom_relation; *) (* apple *) + let atom_sets = make_atom_sets atom_relation in + (atom_relation,atom_sets,qprefixes) + + +let rec try_multiplicity mult_limit ftree ordering pos_n mult logic = + try + let (atom_relation,atom_sets,qprefixes) = init_prover ftree in + let ((orderingQ,red_ordering),eqlist,unifier,ext_proof) = + path_checker atom_relation atom_sets qprefixes ordering logic in + (ftree,red_ordering,eqlist,unifier,ext_proof) (* orderingQ is not needed as return value *) + with Failed -> + match mult_limit with + Some m when m == mult -> + raise mult_limit_exn + | _ -> + let new_mult = mult+1 in + begin + Pp.msgnl (Pp.(++) (Pp.str "Multiplicity Fail: Trying new multiplicity ") + (Pp.int new_mult)); +(* + Format.open_box 0; + Format.force_newline (); + Format.print_string "Multiplicity Fail: "; + Format.print_string ("Try new multiplicity "^(string_of_int new_mult)); + Format.force_newline (); + Format.print_flush (); +*) + let (new_ftree,new_ordering,new_pos_n) = + add_multiplicity ftree pos_n new_mult logic in + if (new_ftree = ftree) then + raise unprovable + else +(* print_formula_info new_ftree new_ordering new_pos_n; *) (* apple *) + try_multiplicity mult_limit new_ftree new_ordering new_pos_n new_mult logic + end + +let prove mult_limit termlist logic = + let (ftree,ordering,pos_n) = construct_ftree termlist [] [] 0 (mk_var_term "dummy") in +(* pos_n = number of positions without new root "w" *) +(* print_formula_info ftree ordering pos_n; *) (* apple *) + try_multiplicity mult_limit ftree ordering pos_n 1 logic + +(********** first-order type theory interface *******************) + +let rec renam_free_vars termlist = + match termlist + with [] -> [],[] + | f::r -> + let var_names = free_vars_list f in + let string_terms = + List.map (fun x -> (mk_string_term free_var_op x)) var_names + in + let mapping = List.combine var_names string_terms + and new_f = subst f var_names string_terms in + let (rest_mapping,rest_renamed) = renam_free_vars r in + let unique_mapping = remove_dups_list (mapping @ rest_mapping) in + (unique_mapping,(new_f::rest_renamed)) + +let rec apply_var_subst term var_subst_list = + match var_subst_list with + [] -> term + | (v,t)::r -> + let next_term = var_subst term t v in + apply_var_subst next_term r + +let rec make_equal_list n list_object = + if n = 0 then + [] + else + list_object::(make_equal_list (n-1) list_object) + +let rec create_output rule_list input_map = + match rule_list with + [] -> JLogic.empty_inf + | f::r -> + let (pos,(rule,term1,term2)) = f in + let delta1_names = collect_delta_terms [term1] + and delta2_names = collect_delta_terms [term2] in + let unique_deltas = remove_dups_list (delta1_names @ delta2_names) in + let delta_terms = + List.map (fun x -> (mk_string_term jprover_op x)) unique_deltas in + let delta_vars = List.map (fun x -> (x^"_jprover")) unique_deltas in + let delta_map = List.combine delta_vars delta_terms in + let var_mapping = (input_map @ delta_map) in + let frees1 = free_vars_list term1 + and frees2 = free_vars_list term2 in + let unique_object = mk_var_term "v0_jprover" in + let unique_list1 = make_equal_list (List.length frees1) unique_object + and unique_list2 = make_equal_list (List.length frees2) unique_object + in + let next_term1 = subst term1 frees1 unique_list1 + and next_term2 = subst term2 frees2 unique_list2 in + let new_term1 = apply_var_subst next_term1 var_mapping + and new_term2 = apply_var_subst next_term2 var_mapping + and (a,b) = pos + in +(*: print_string (a^"+++"^b^"\n"); :*) + +(* kick away the first argument, the position *) + (JLogic.append_inf (create_output r input_map) (b,new_term1) (a,new_term2) rule) + +let rec make_test_interface rule_list input_map = + match rule_list with + [] -> [] + | f::r -> + let (pos,(rule,term1,term2)) = f in + let delta1_names = collect_delta_terms [term1] + and delta2_names = collect_delta_terms [term2] in + let unique_deltas = remove_dups_list (delta1_names @ delta2_names) in + let delta_terms = + List.map (fun x -> (mk_string_term jprover_op x)) unique_deltas in + let delta_vars = List.map (fun x -> (x^"_jprover")) unique_deltas in + let delta_map = List.combine delta_vars delta_terms in + let var_mapping = (input_map @ delta_map) in + let frees1 = free_vars_list term1 + and frees2 = free_vars_list term2 in + let unique_object = mk_var_term "v0_jprover" in + let unique_list1 = make_equal_list (List.length frees1) unique_object + and unique_list2 = make_equal_list (List.length frees2) unique_object + in + begin +(* + print_endline ""; + print_endline ""; + print_stringlist frees1; + print_endline ""; + print_stringlist frees2; + print_endline ""; + print_endline ""; +*) + let next_term1 = subst term1 frees1 unique_list1 + and next_term2 = subst term2 frees2 unique_list2 in + let new_term1 = apply_var_subst next_term1 var_mapping + and new_term2 = apply_var_subst next_term2 var_mapping + in + (pos,(rule,new_term1,new_term2))::(make_test_interface r input_map) + end + +(**************************************************************) + +(*: modified for Coq :*) + +let decomp_pos pos = + let {name=n; address=a; label=l} = pos in + (n,(a,l)) + +let rec build_formula_id ftree = + let rec build_fid_list = function + [] -> [] + | t::rest -> (build_formula_id t)@(build_fid_list rest) + in + match ftree with + Empty -> [] + | NodeAt(position) -> + [decomp_pos position] + | NodeA(position,subtrees) -> + let tree_list = Array.to_list subtrees in + (decomp_pos position)::(build_fid_list tree_list) + +let rec encode1 = function (* normal *) + [] -> "" + | i::r -> "_"^(string_of_int i)^(encode1 r) + +let rec encode2 = function (* move up *) + [i] -> "" + | i::r -> "_"^(string_of_int i)^(encode2 r) + | _ -> raise coq_exn + +let rec encode3 = function (* move down *) + [] -> "_1" + | i::r -> "_"^(string_of_int i)^(encode3 r) + +let lookup_coq str map = + try + let (il,t) = List.assoc str map in + il + with Not_found -> raise coq_exn + +let create_coq_input inf map = + let rec rec_coq_part inf = + match inf with + [] -> [] + | (rule, (s1, t1), ((s2, t2) as k))::r -> + begin + match rule with + Andl | Andr | Orl | Orr1 | Orr2 -> + (rule, (encode1 (lookup_coq s1 map), t1), k)::(rec_coq_part r) + | Impr | Impl | Negr | Negl | Ax -> + (rule, (encode2 (lookup_coq s1 map), t1), k)::(rec_coq_part r) + | Exr -> + (rule, (encode1 (lookup_coq s1 map), t1), + (encode1 (lookup_coq s2 map), t2))::(rec_coq_part r) + | Exl -> + (rule, (encode1 (lookup_coq s1 map), t1), + (encode3 (lookup_coq s1 map), t2))::(rec_coq_part r) + | Allr | Alll -> + (rule, (encode2 (lookup_coq s1 map), t1), + (* (s2, t2))::(rec_coq_part r) *) + (encode3 (lookup_coq s1 map), t2))::(rec_coq_part r) + | _ -> raise coq_exn + end + in + rec_coq_part inf + +let gen_prover mult_limit logic calculus hyps concls = + let (input_map,renamed_termlist) = renam_free_vars (hyps @ concls) in + let (ftree,red_ordering,eqlist,(sigmaQ,sigmaJ),ext_proof) = prove mult_limit renamed_termlist logic in + let sequent_proof = reconstruct ftree red_ordering sigmaQ ext_proof logic calculus in + let (ptree,count_ax) = bproof sequent_proof in + let idl = build_formula_id ftree in +(* print_ftree ftree; apple *) + (* transform types and rename constants *) + (* we can transform the eigenvariables AFTER proof reconstruction since *) + (* new delta_0 constants may have been constructed during rule permutation *) + (* from the LJmc to the LJ proof *) + create_coq_input (create_output sequent_proof input_map) idl + +(*: end of coq modification :*) + +let prover mult_limit hyps concl = gen_prover mult_limit "J" "LJ" hyps [concl] + +(************* test with propositional proof reconstruction ************) + +let rec count_axioms seq_list = + match seq_list with + [] -> 0 + | f::r -> + let (rule,_,_) = f in + if rule = Ax then + 1 + count_axioms r + else + count_axioms r + +let do_prove mult_limit termlist logic calculus = + try begin + let (input_map,renamed_termlist) = renam_free_vars termlist in + let (ftree,red_ordering,eqlist,(sigmaQ,sigmaJ),ext_proof) = prove mult_limit renamed_termlist logic in + Format.open_box 0; + Format.force_newline (); + Format.force_newline (); + Format.print_string "Extension proof ready"; + Format.force_newline (); + Format.force_newline (); + Format.print_string ("Length of Extension proof: "^((string_of_int (List.length ext_proof)))^ + " Axioms"); + Format.force_newline (); + Format.force_newline (); + print_endline "Extension proof:"; + Format.open_box 0; + print_pairlist ext_proof; (* print list of type (string * string) list *) + Format.force_newline (); + Format.force_newline (); + Format.force_newline (); + Format.print_flush (); + Format.print_flush (); + Format.open_box 0; + print_ordering red_ordering; + Format.print_flush (); + Format.open_box 0; + Format.force_newline (); +(* ----------------------------------------------- *) + Format.open_box 0; + print_tunify sigmaJ; + Format.print_flush (); + print_endline ""; + print_endline ""; + print_sigmaQ sigmaQ; + print_endline ""; + print_endline ""; + Format.open_box 0; + let (qmax,equations) = eqlist in + print_endline ("number of quantifier domains : "^(string_of_int (qmax-1))); + print_endline ""; + print_equations equations; + Format.print_flush (); + print_endline ""; + print_endline ""; + print_endline ("Length of equations : "^((string_of_int (List.length equations)))); + print_endline ""; + print_endline ""; +(* --------------------------------------------------------- *) + Format.print_string "Break ... "; + print_endline ""; + print_endline ""; + Format.print_flush (); +(*: let _ = input_char stdin in :*) + let reconstr_proof = reconstruct ftree red_ordering sigmaQ ext_proof logic calculus in + let sequent_proof = make_test_interface reconstr_proof input_map in + Format.open_box 0; + Format.force_newline (); + Format.force_newline (); + Format.print_string "Sequent proof ready"; + Format.force_newline (); + Format.force_newline (); + Format.print_flush (); + let (ptree,count_ax) = bproof sequent_proof in + Format.open_box 0; + Format.print_string ("Length of sequent proof: "^((string_of_int count_ax))^" Axioms"); + Format.force_newline (); + Format.force_newline (); + Format.force_newline (); + Format.force_newline (); + Format.print_flush (); + tt ptree; (*: print proof tree :*) + Format.print_flush (); + print_endline ""; + print_endline "" + end with exn -> begin + print_endline "Jprover got an exception:"; + print_endline (Printexc.to_string exn) + end + +let test concl logic calculus = (* calculus should be LJmc or LJ for J, and LK for C *) + do_prove None [concl] logic calculus + +(* for sequents *) + +let seqtest list_term logic calculus = + let bterms = (dest_term list_term).term_terms in + let termlist = collect_subterms bterms in + do_prove None termlist logic calculus + +(*****************************************************************) + +end (* of struct *) diff --git a/contrib/jprover/jall.mli b/contrib/jprover/jall.mli new file mode 100644 index 00000000..1811fe59 --- /dev/null +++ b/contrib/jprover/jall.mli @@ -0,0 +1,339 @@ +(* JProver provides an efficient refiner for first-order classical + and first-order intuitionistic logic. It consists of two main parts: + a proof search procedure and a proof reconstruction procedure. + + + Proof Search + ============ + + The proof search process is based on a matrix-based (connection-based) + proof procedure, i.e.~a non-normalform extension procedure. + Besides the well-known quantifier substitution (Martelli Montanari), + a special string unifiation procedure is used in order to + efficiently compute intuitionistic rule non-permutabilities. + + + Proof Reconstruction + ==================== + + The proof reconstruction process converts machine-generated matrix proofs + into cut-free Gentzen-style sequent proofs. For classcal logic "C", + Gentzen's sequent calculus "LK" is used as target calculus. + For intuitionistic logic "J", either Gentzen's single-conclusioned sequent + calculus "LJ" or Fitting's multiply-conclusioned sequent calculus "LJmc" + can be used. All sequent claculi are implemented in a set-based formulation + in order to avoid structural rules. + + The proof reconstruction procedure combines three main procedures, depending + on the selected logics and sequent calculi. It consists of: + + 1) A uniform traversal algorithm for all logics and target sequent calculi. + This procedure converts classical (intuitionistic) matrix proofs + directly into cut-free "LK" ("LJmc" or "LJ") sequent proofs. + However, the direct construction of "LJ" proofs may fail in some cases + due to proof theoretical reasons. + + 2) A complete redundancy deletion algorithm, which integrates additional + knowledge from the proof search process into the reconstruction process. + This procedure is called by the traversal algorithms in order to avoid + search and deadlocks during proof reconstruciton. + + 3) A permutation-based proof transformation for converting "LJmc" proofs + into "LJ" proofs. + This procedure is called by-need, whenever the direct reconstruction + of "LJ" proofs from matrix proofs fails. + + + + + Literature: + ========== + + JProver system description was presented at CADE 2001: + @InProceedings{inp:Schmitt+01a, + author = "Stephan Schmitt and Lori Lorigo and Christoph Kreitz and + Alexey Nogin", + title = "{{\sf JProver}}: Integrating Connection-based Theorem + Proving into Interactive Proof Assistants", + booktitle = "International Joint Conference on Automated Reasoning", + year = "2001", + editor = "R. Gore and A. Leitsch and T. Nipkow", + volume = 2083, + series = LNAI, + pages = "421--426", + publisher = SPRINGER, + language = English, + where = OWN, + } + + The implementation of JProver is based on the following publications: + + + + Slides of PRL-seminar talks: + --------------------------- + + An Efficient Refiner for First-order Intuitionistic Logic + + http://www.cs.cornell.edu/Nuprl/PRLSeminar/PRLSeminar99_00/schmitt/feb28.html + + + An Efficient Refiner for First-order Intuitionistic Logic (Part II) + + http://www.cs.cornell.edu/Nuprl/PRLSeminar/PRLSeminar99_00/schmitt/may22.html + + + + Proof search: + ------------- + + +[1] + @InProceedings{inp:OttenKreitz96b, + author = "J.~Otten and C.~Kreitz", + title = "A uniform proof procedure for classical and + non-classical logics", + booktitle = "Proceedings of the 20$^{th}$ German Annual Conference on + Artificial Intelligence", + year = "1996", + editor = "G.~G{\"o}rz and S.~H{\"o}lldobler", + number = "1137", + series = LNAI, + pages = "307--319", + publisher = SPRINGER + } + + +[2] + @Article{ar:KreitzOtten99, + author = "C.~Kreitz and J.~Otten", + title = "Connection-based theorem proving in classical and + non-classical logics", + journal = "Journal for Universal Computer Science, + Special Issue on Integration of Deductive Systems", + year = "1999", + volume = "5", + number = "3", + pages = "88--112" + } + + + + + Special string unifiation procedure: + ------------------------------------ + + +[3] + @InProceedings{inp:OttenKreitz96a, + author = "J.~Otten and C.~Kreitz", + titl = "T-string-unification: unifying prefixes in + non-classical proof methods", + booktitle = "Proceedings of the 5$^{th}$ Workshop on Theorem Proving + with Analytic Tableaux and Related Methods", + year = 1996, + editor = "U.~Moscato", + number = "1071", + series = LNAI, + pages = "244--260", + publisher = SPRINGER, + month = "May " + } + + + + Proof reconstruction: Uniform traversal algorithm + ------------------------------------------------- + + +[4] + @InProceedings{inp:SchmittKreitz96a, + author = "S.~Schmitt and C.~Kreitz", + title = "Converting non-classical matrix proofs into + sequent-style systems", + booktitle = "Proceedings of the 13$^t{}^h$ Conference on + Automated Deduction", + editor = M.~A.~McRobbie and J.~K.~Slaney", + number = "1104", + series = LNAI, + pages = "418--432", + year = "1996", + publisher = SPRINGER, + month = "July/August" + } + + +[5] + @Article{ar:KreitzSchmitt00, + author = "C.~Kreitz and S.~Schmitt", + title = "A uniform procedure for converting matrix proofs + into sequent-style systems", + journal = "Journal of Information and Computation", + year = "2000", + note = "(to appear)" + } + + +[6] + @Book{bo:Schmitt00, + author = "S.~Schmitt", + title = "Proof reconstruction in classical and non-classical logics", + year = "2000", + publisher = "Infix", + series = "Dissertationen zur K{\"u}nstlichen Intelleigenz", + number = "(to appear)", + note = "(Ph.{D}.~{T}hesis, Technische Universit{\"a}t Darmstadt, + FG Intellektik, Germany, 1999)" + } + + The traversal algorithm is presented in the Chapters 2 and 3 of my thesis. + The thesis will be made available for the Department through Christoph Kreitz, + Upson 4159, kreitz@cs.cornell.edu + + + + + Proof reconstruction: Complete redundancy deletion + -------------------------------------------------- + + +[7] + @Book{bo:Schmitt00, + author = "S.~Schmitt", + title = "Proof reconstruction in classical and non-classical logics", + year = "2000", + publisher = "Infix", + series = "Dissertationen zur K{\"u}nstlichen Intelleigenz", + note = "(Ph.{D}.~{T}hesis, Technische Universit{\"a}t Darmstadt, + FG Intellektik, Germany, 1999)" + note = "(to appear)", + + } + + The integration of proof knowledge and complete redundancy deletion is presented + in Chapter 4 of my thesis. + + +[8] + @InProceedings{inp:Schmitt00, + author = "S.~Schmitt", + title = "A tableau-like representation framework for efficient + proof reconstruction", + booktitle = "Proceedings of the International Conference on Theorem Proving + with Analytic Tableaux and Related Methods", + year = "2000", + series = LNAI, + publisher = SPRINGER, + month = "June" + note = "(to appear)", + } + + + + + Proof Reconstruction: Permutation-based poof transformations "LJ" -> "LJmc" + --------------------------------------------------------------------------- + + +[9] + @InProceedings{inp:EglySchmitt98, + author = "U.~Egly and S.~Schmitt", + title = "Intuitionistic proof transformations and their + application to constructive program synthesis", + booktitle = "Proceedings of the 4$^{th}$ International Conference + on Artificial Intelligence and Symbolic Computation", + year = "1998", + editor = "J.~Calmet and J.~Plaza", + number = "1476", + series = LNAI, + pages = "132--144", + publisher = SPRINGER, + month = "September" + } + + +[10] + @Article{ar:EglySchmitt99, + author = "U.~Egly and S.~Schmitt", + title = "On intuitionistic proof transformations, their + complexity, and application to constructive program synthesis", + journal = "Fundamenta Informaticae, + Special Issue: Symbolic Computation and Artificial Intelligence", + year = "1999", + volume = "39", + number = "1--2", + pages = "59--83" + } +*) + +(*: open Refiner.Refiner +open Refiner.Refiner.Term +open Refiner.Refiner.TermType +open Refiner.Refiner.TermSubst + +open Jlogic_sig +:*) + +open Jterm +open Opname +open Jlogic + +val ruletable : rule -> string + +module JProver(JLogic: JLogicSig) : +sig + val test : term -> string -> string -> unit + + (* Procedure call: test conclusion logic calculus + + test is applied to a first-order formula. The output is some + formatted sequent proof for test / debugging purposes. + + The arguments for test are as follows: + + logic = "C"|"J" + i.e. first-order classical logic or first-order intuitionistic logic + + calculus = "LK"|"LJ"|"LJmc" + i.e. "LK" for classical logic "C", and either Gentzen's single conclusioned + calculus "LJ" or Fittings multiply-conclusioned calculus "LJmc" for + intuitionistic logic "J". + + term = first-order formula representing the proof goal. + *) + + + + val seqtest : term -> string -> string -> unit + + (* seqtest procedure is for debugging purposes only *) + + + val gen_prover : int option -> string -> string -> term list -> term list -> JLogic.inference + + (* Procedure call: gen_prover mult_limit logic calculus hypothesis conclusion + + The arguments for gen_prover are as follows: + + mult_limit - maximal multiplicity to try, None for unlimited + + logic = same as in test + + calculus = same as in test + + hypothesis = list of first-order terms forming the antecedent of the input sequent + + conclusion = list of first-order terms forming the succedent of the input sequent + This list should contain only one element if logic = "J" and calculus = "LJ". + *) + + + val prover : int option -> term list -> term -> JLogic.inference + + (* Procedure call: gen_prover mult_limit "J" "LJ" hyps [concl] + + prover provides the first-order refiner for NuPRL, using + a single concluisoned succedent [concl] in the sequent. + The result is a sequent proof in the single-conclusioned calculus "LJ". + *) +end diff --git a/contrib/jprover/jlogic.ml b/contrib/jprover/jlogic.ml new file mode 100644 index 00000000..c074e93e --- /dev/null +++ b/contrib/jprover/jlogic.ml @@ -0,0 +1,106 @@ +open Opname +open Jterm + +type rule = + | Ax | Andr | Andl | Orr | Orr1 | Orr2 | Orl | Impr | Impl | Negr | Negl + | Allr | Alll| Exr | Exl | Fail | Falsel | Truer + +let ruletable = function + | Fail -> "Fail" + | Ax -> "Ax" + | Negl -> "Negl" + | Negr -> "Negr" + | Andl -> "Andl" + | Andr -> "Andr" + | Orl -> "Orl" + | Orr -> "Orr" + | Orr1 -> "Orr1" + | Orr2 -> "Orr2" + | Impl -> "Impl" + | Impr -> "Impr" + | Exl -> "Exl" + | Exr -> "Exr" + | Alll -> "Alll" + | Allr -> "Allr" + | Falsel -> "Falsel" + | Truer -> "Truer" + +module type JLogicSig = +sig + (* understanding the input *) + val is_all_term : term -> bool + val dest_all : term -> string * term * term + val is_exists_term : term -> bool + val dest_exists : term -> string * term * term + val is_and_term : term -> bool + val dest_and : term -> term * term + val is_or_term : term -> bool + val dest_or : term -> term * term + val is_implies_term : term -> bool + val dest_implies : term -> term * term + val is_not_term : term -> bool + val dest_not : term -> term + + (* processing the output *) + type inf_step = rule * (string * term) * (string * term) + type inference = inf_step list +(* type inference *) + val empty_inf : inference + val append_inf : inference -> (string * term) -> (string * term) -> rule -> inference + val print_inf : inference -> unit +end;; + +(* Copy from [term_op_std.ml]: *) + + let rec print_address int_list = + match int_list with + | [] -> + Format.print_string "" + | hd::rest -> + begin + Format.print_int hd; + print_address rest + end + +module JLogic: JLogicSig = +struct + let is_all_term = Jterm.is_all_term + let dest_all = Jterm.dest_all + let is_exists_term = Jterm.is_exists_term + let dest_exists = Jterm.dest_exists + let is_and_term = Jterm.is_and_term + let dest_and = Jterm.dest_and + let is_or_term = Jterm.is_or_term + let dest_or = Jterm.dest_or + let is_implies_term = Jterm.is_implies_term + let dest_implies = Jterm.dest_implies + let is_not_term = Jterm.is_not_term + let dest_not = Jterm.dest_not + + type inf_step = rule * (string * term) * (string * term) + type inference = inf_step list + + let empty_inf = [] + let append_inf inf t1 t2 rule = + (rule, t1, t2)::inf + + let rec print_inf inf = + match inf with + | [] -> print_string "."; Format.print_flush () + | (rule, (n1,t1), (n2,t2))::d -> + print_string (ruletable rule); + print_string (":("^n1^":"); + print_term stdout t1; + print_string (","^n2^":"); + print_term stdout t2; + print_string ")\n"; + print_inf d +end;; + +let show_loading s = print_string s +type my_Debug = { mutable debug_name: string; + mutable debug_description: string; + debug_value: bool + } + +let create_debug x = ref false diff --git a/contrib/jprover/jlogic.mli b/contrib/jprover/jlogic.mli new file mode 100644 index 00000000..a9079791 --- /dev/null +++ b/contrib/jprover/jlogic.mli @@ -0,0 +1,40 @@ +(* The interface to manipulate [jterms], which is + extracted and modified from Meta-Prl. *) + +type rule = + Ax | Andr | Andl | Orr | Orr1 | Orr2 | Orl | Impr | Impl | Negr | Negl + | Allr | Alll| Exr | Exl | Fail | Falsel | Truer + +module type JLogicSig = + sig + val is_all_term : Jterm.term -> bool + val dest_all : Jterm.term -> string * Jterm.term * Jterm.term + val is_exists_term : Jterm.term -> bool + val dest_exists : Jterm.term -> string * Jterm.term * Jterm.term + val is_and_term : Jterm.term -> bool + val dest_and : Jterm.term -> Jterm.term * Jterm.term + val is_or_term : Jterm.term -> bool + val dest_or : Jterm.term -> Jterm.term * Jterm.term + val is_implies_term : Jterm.term -> bool + val dest_implies : Jterm.term -> Jterm.term * Jterm.term + val is_not_term : Jterm.term -> bool + val dest_not : Jterm.term -> Jterm.term + type inf_step = rule * (string * Jterm.term) * (string * Jterm.term) + type inference = inf_step list + val empty_inf : inference + val append_inf : + inference -> (string * Jterm.term) -> (string * Jterm.term) -> rule -> inference + val print_inf : inference -> unit + end + +module JLogic : JLogicSig + +val show_loading : string -> unit + +type my_Debug = { + mutable debug_name : string; + mutable debug_description : string; + debug_value : bool; +} +val create_debug : 'a -> bool ref +val ruletable : rule -> string diff --git a/contrib/jprover/jprover.ml4 b/contrib/jprover/jprover.ml4 new file mode 100644 index 00000000..dd76438f --- /dev/null +++ b/contrib/jprover/jprover.ml4 @@ -0,0 +1,565 @@ +(*i camlp4deps: "parsing/grammar.cma" i*) + +open Jlogic + +module JA = Jall +module JT = Jterm +module T = Tactics +module TCL = Tacticals +module TM = Tacmach +module N = Names +module PT = Proof_type +module HT = Hiddentac +module PA = Pattern +module HP = Hipattern +module TR = Term +module PR = Printer +module RO = Reductionops +module UT = Util +module RA = Rawterm + +module J=JA.JProver(JLogic) (* the JProver *) + +(*i +module NO = Nameops +module TO = Termops +module RE = Reduction +module CL = Coqlib +module ID = Inductiveops +module CV = Clenv +module RF = Refiner +i*) + +(* Interface to JProver: *) +(* type JLogic.inf_step = rule * (string * Jterm.term) * (string * Jterm.term) *) +type jp_inf_step = JLogic.inf_step +type jp_inference = JLogic.inference (* simply a list of [inf_step] *) + +(* Definitions for rebuilding proof tree from JProver: *) +(* leaf, one-branch, two-branch, two-branch, true, false *) +type jpbranch = JP0 | JP1 | JP2 | JP2' | JPT | JPF +type jptree = | JPempty (* empty tree *) + | JPAx of jp_inf_step (* Axiom node *) + | JPA of jp_inf_step * jptree + | JPB of jp_inf_step * jptree * jptree + +(* Private debugging tools: *) +(*i*) +let mbreak s = Format.print_flush (); print_string ("-break at: "^s); + Format.print_flush (); let _ = input_char stdin in () +(*i*) +let jp_error re = raise (JT.RefineError ("jprover", JT.StringError re)) + +(* print Coq constructor *) +let print_constr ct = Pp.ppnl (PR.prterm ct); Format.print_flush () + +let rec print_constr_list = function + | [] -> () + | ct::r -> print_constr ct; print_constr_list r + +let print_constr_pair op c1 c2 = + print_string (op^"("); + print_constr c1; + print_string ","; + print_constr c2; + print_string ")\n" + + +(* Parsing modules for Coq: *) +(* [is_coq_???] : testing functions *) +(* [dest_coq_???] : destructors *) + +let is_coq_true ct = (HP.is_unit_type ct) && not (HP.is_equation ct) + +let is_coq_false = HP.is_empty_type + +(* return two subterms *) +let dest_coq_and ct = + match (HP.match_with_conjunction ct) with + | Some (hdapp,args) -> +(*i print_constr hdapp; print_constr_list args; i*) + begin + match args with + | s1::s2::[] -> +(*i print_constr_pair "and" s1 s2; i*) + (s1,s2) + | _ -> jp_error "dest_coq_and" + end + | None -> jp_error "dest_coq_and" + +let is_coq_or = HP.is_disjunction + +(* return two subterms *) +let dest_coq_or ct = + match (HP.match_with_disjunction ct) with + | Some (hdapp,args) -> +(*i print_constr hdapp; print_constr_list args; i*) + begin + match args with + | s1::s2::[] -> +(*i print_constr_pair "or" s1 s2; i*) + (s1,s2) + | _ -> jp_error "dest_coq_or" + end + | None -> jp_error "dest_coq_or" + +let is_coq_not = HP.is_nottype + +let dest_coq_not ct = + match (HP.match_with_nottype ct) with + | Some (hdapp,arg) -> +(*i print_constr hdapp; print_constr args; i*) +(*i print_string "not "; + print_constr arg; i*) + arg + | None -> jp_error "dest_coq_not" + + +let is_coq_impl ct = + match TR.kind_of_term ct with + | TR.Prod (_,_,b) -> (not (Termops.dependent (TR.mkRel 1) b)) + | _ -> false + + +let dest_coq_impl c = + match TR.kind_of_term c with + | TR.Prod (_,b,c) -> +(*i print_constr_pair "impl" b c; i*) + (b, c) + | _ -> jp_error "dest_coq_impl" + +(* provide new variables for renaming of universal variables *) +let new_counter = + let ctr = ref 0 in + fun () -> incr ctr;!ctr + +(* provide new symbol name for unknown Coq constructors *) +let new_ecounter = + let ectr = ref 0 in + fun () -> incr ectr;!ectr + +(* provide new variables for address naming *) +let new_acounter = + let actr = ref 0 in + fun () -> incr actr;!actr + +let is_coq_forall ct = + match TR.kind_of_term (RO.whd_betaiota ct) with + | TR.Prod (_,_,b) -> Termops.dependent (TR.mkRel 1) b + | _ -> false + +(* return the bounded variable (as a string) and the bounded term *) +let dest_coq_forall ct = + match TR.kind_of_term (RO.whd_betaiota ct) with + | TR.Prod (_,_,b) -> + let x ="jp_"^(string_of_int (new_counter())) in + let v = TR.mkVar (N.id_of_string x) in + let c = TR.subst1 v b in (* substitute de Bruijn variable by [v] *) +(*i print_constr_pair "forall" v c; i*) + (x, c) + | _ -> jp_error "dest_coq_forall" + + +(* Apply [ct] to [t]: *) +let sAPP ct t = + match TR.kind_of_term (RO.whd_betaiota ct) with + | TR.Prod (_,_,b) -> + let c = TR.subst1 t b in + c + | _ -> jp_error "sAPP" + + +let is_coq_exists ct = + if not (HP.is_conjunction ct) then false + else let (hdapp,args) = TR.decompose_app ct in + match args with + | _::la::[] -> + begin + try + match TR.destLambda la with + | (N.Name _,_,_) -> true + | _ -> false + with _ -> false + end + | _ -> false + +(* return the bounded variable (as a string) and the bounded term *) +let dest_coq_exists ct = + let (hdapp,args) = TR.decompose_app ct in + match args with + | _::la::[] -> + begin + try + match TR.destLambda la with + | (N.Name x,t1,t2) -> + let v = TR.mkVar x in + let t3 = TR.subst1 v t2 in +(*i print_constr_pair "exists" v t3; i*) + (N.string_of_id x, t3) + | _ -> jp_error "dest_coq_exists" + with _ -> jp_error "dest_coq_exists" + end + | _ -> jp_error "dest_coq_exists" + + +let is_coq_and ct = + if (HP.is_conjunction ct) && not (is_coq_exists ct) + && not (is_coq_true ct) then true + else false + + +(* Parsing modules: *) + +let jtbl = Hashtbl.create 53 (* associate for unknown Coq constr. *) +let rtbl = Hashtbl.create 53 (* reverse table of [jtbl] *) + +let dest_coq_symb ct = + N.string_of_id (TR.destVar ct) + +(* provide new names for unknown Coq constr. *) +(* [ct] is the unknown constr., string [s] is appended to the name encoding *) +let create_coq_name ct s = + try + Hashtbl.find jtbl ct + with Not_found -> + let t = ("jp_"^s^(string_of_int (new_ecounter()))) in + Hashtbl.add jtbl ct t; + Hashtbl.add rtbl t ct; + t + +let dest_coq_app ct s = + let (hd, args) = TR.decompose_app ct in +(*i print_constr hd; + print_constr_list args; i*) + if TR.isVar hd then + (dest_coq_symb hd, args) + else (* unknown constr *) + (create_coq_name hd s, args) + +let rec parsing2 c = (* for function symbols, variables, constants *) + if (TR.isApp c) then (* function symbol? *) + let (f,args) = dest_coq_app c "fun_" in + JT.fun_ f (List.map parsing2 args) + else if TR.isVar c then (* identifiable variable or constant *) + JT.var_ (dest_coq_symb c) + else (* unknown constr *) + JT.var_ (create_coq_name c "var_") + +(* the main parsing function *) +let rec parsing c = + let ct = Reduction.whd_betadeltaiota (Global.env ()) c in +(* let ct = Reduction.whd_betaiotazeta (Global.env ()) c in *) + if is_coq_true ct then + JT.true_ + else if is_coq_false ct then + JT.false_ + else if is_coq_not ct then + JT.not_ (parsing (dest_coq_not ct)) + else if is_coq_impl ct then + let (t1,t2) = dest_coq_impl ct in + JT.imp_ (parsing t1) (parsing t2) + else if is_coq_or ct then + let (t1,t2) = dest_coq_or ct in + JT.or_ (parsing t1) (parsing t2) + else if is_coq_and ct then + let (t1,t2) = dest_coq_and ct in + JT.and_ (parsing t1) (parsing t2) + else if is_coq_forall ct then + let (v,t) = dest_coq_forall ct in + JT.forall v (parsing t) + else if is_coq_exists ct then + let (v,t) = dest_coq_exists ct in + JT.exists v (parsing t) + else if TR.isApp ct then (* predicate symbol with arguments *) + let (p,args) = dest_coq_app ct "P_" in + JT.pred_ p (List.map parsing2 args) + else if TR.isVar ct then (* predicate symbol without arguments *) + let p = dest_coq_symb ct in + JT.pred_ p [] + else (* unknown predicate *) + JT.pred_ (create_coq_name ct "Q_") [] + +(*i + print_string "??";print_constr ct; + JT.const_ ("err_"^(string_of_int (new_ecounter()))) +i*) + + +(* Translate JProver terms into Coq constructors: *) +(* The idea is to retrieve it from [rtbl] if it exists indeed, otherwise + create one. *) +let rec constr_of_jterm t = + if (JT.is_var_term t) then (* a variable *) + let v = JT.dest_var t in + try + Hashtbl.find rtbl v + with Not_found -> TR.mkVar (N.id_of_string v) + else if (JT.is_fun_term t) then (* a function symbol *) + let (f,ts) = JT.dest_fun t in + let f' = try Hashtbl.find rtbl f with Not_found -> TR.mkVar (N.id_of_string f) in + TR.mkApp (f', Array.of_list (List.map constr_of_jterm ts)) + else jp_error "constr_of_jterm" + + +(* Coq tactics for Sequent Calculus LJ: *) +(* Note that for left-rule a name indicating the being applied rule + in Coq's Hints is required; for right-rule a name is also needed + if it will pass some subterm to the left-hand side. + However, all of these can be computed by the path [id] of the being + applied rule. +*) + +let assoc_addr = Hashtbl.create 97 + +let short_addr s = + let ad = + try + Hashtbl.find assoc_addr s + with Not_found -> + let t = ("jp_H"^(string_of_int (new_acounter()))) in + Hashtbl.add assoc_addr s t; + t + in + N.id_of_string ad + +(* and-right *) +let dyn_andr = + T.split RA.NoBindings + +(* For example, the following implements the [and-left] rule: *) +let dyn_andl id = (* [id1]: left child; [id2]: right child *) + let id1 = (short_addr (id^"_1")) and id2 = (short_addr (id^"_2")) in + (TCL.tclTHEN (T.simplest_elim (TR.mkVar (short_addr id))) (T.intros_using [id1;id2])) + +let dyn_orr1 = + T.left RA.NoBindings + +let dyn_orr2 = + T.right RA.NoBindings + +let dyn_orl id = + let id1 = (short_addr (id^"_1")) and id2 = (short_addr (id^"_2")) in + (TCL.tclTHENS (T.simplest_elim (TR.mkVar (short_addr id))) + [T.intro_using id1; T.intro_using id2]) + +let dyn_negr id = + let id1 = id^"_1_1" in + HT.h_intro (short_addr id1) + +let dyn_negl id = + T.simplest_elim (TR.mkVar (short_addr id)) + +let dyn_impr id = + let id1 = id^"_1_1" in + HT.h_intro (short_addr id1) + +let dyn_impl id gl = + let t = TM.pf_get_hyp_typ gl (short_addr id) in + let ct = Reduction.whd_betadeltaiota (Global.env ()) t in (* unfolding *) + let (_,b) = dest_coq_impl ct in + let id2 = (short_addr (id^"_1_2")) in + (TCL.tclTHENLAST + (TCL.tclTHENS (T.cut b) [T.intro_using id2;TCL.tclIDTAC]) + (T.apply_term (TR.mkVar (short_addr id)) + [TR.mkMeta (Clenv.new_meta())])) gl + +let dyn_allr c = (* [c] must be an eigenvariable which replaces [v] *) + HT.h_intro (N.id_of_string c) + +(* [id2] is the path of the instantiated term for [id]*) +let dyn_alll id id2 t gl = + let id' = short_addr id in + let id2' = short_addr id2 in + let ct = TM.pf_get_hyp_typ gl id' in + let ct' = Reduction.whd_betadeltaiota (Global.env ()) ct in (* unfolding *) + let ta = sAPP ct' t in + TCL.tclTHENS (T.cut ta) [T.intro_using id2'; T.apply (TR.mkVar id')] gl + +let dyn_exl id id2 c = (* [c] must be an eigenvariable *) + (TCL.tclTHEN (T.simplest_elim (TR.mkVar (short_addr id))) + (T.intros_using [(N.id_of_string c);(short_addr id2)])) + +let dyn_exr t = + T.one_constructor 1 (RA.ImplicitBindings [t]) + +let dyn_falsel = dyn_negl + +let dyn_truer = + T.one_constructor 1 RA.NoBindings + +(* Do the proof by the guidance of JProver. *) + +let do_one_step inf = + let (rule, (s1, t1), ((s2, t2) as k)) = inf in + begin +(*i if not (Jterm.is_xnil_term t2) then + begin + print_string "1: "; JT.print_term stdout t2; print_string "\n"; + print_string "2: "; print_constr (constr_of_jterm t2); print_string "\n"; + end; +i*) + match rule with + | Andl -> dyn_andl s1 + | Andr -> dyn_andr + | Orl -> dyn_orl s1 + | Orr1 -> dyn_orr1 + | Orr2 -> dyn_orr2 + | Impr -> dyn_impr s1 + | Impl -> dyn_impl s1 + | Negr -> dyn_negr s1 + | Negl -> dyn_negl s1 + | Allr -> dyn_allr (JT.dest_var t2) + | Alll -> dyn_alll s1 s2 (constr_of_jterm t2) + | Exr -> dyn_exr (constr_of_jterm t2) + | Exl -> dyn_exl s1 s2 (JT.dest_var t2) + | Ax -> T.assumption (*i TCL.tclIDTAC i*) + | Truer -> dyn_truer + | Falsel -> dyn_falsel s1 + | _ -> jp_error "do_one_step" + (* this is impossible *) + end +;; + +(* Parameter [tr] is the reconstucted proof tree from output of JProver. *) +let do_coq_proof tr = + let rec rec_do trs = + match trs with + | JPempty -> TCL.tclIDTAC + | JPAx h -> do_one_step h + | JPA (h, t) -> TCL.tclTHEN (do_one_step h) (rec_do t) + | JPB (h, left, right) -> TCL.tclTHENS (do_one_step h) [rec_do left; rec_do right] + in + rec_do tr + + +(* Rebuild the proof tree from the output of JProver: *) + +(* Since some universal variables are not necessarily first-order, + lazy substitution may happen. They are recorded in [rtbl]. *) +let reg_unif_subst t1 t2 = + let (v,_,_) = JT.dest_all t1 in + Hashtbl.add rtbl v (TR.mkVar (N.id_of_string (JT.dest_var t2))) + +let count_jpbranch one_inf = + let (rule, (_, t1), (_, t2)) = one_inf in + begin + match rule with + | Ax -> JP0 + | Orr1 | Orr2 | Negl | Impr | Alll | Exr | Exl -> JP1 + | Andr | Orl -> JP2 + | Negr -> if (JT.is_true_term t1) then JPT else JP1 + | Andl -> if (JT.is_false_term t1) then JPF else JP1 + | Impl -> JP2' (* reverse the sons of [Impl] since [dyn_impl] reverses them *) + | Allr -> reg_unif_subst t1 t2; JP1 + | _ -> jp_error "count_jpbranch" + end + +let replace_by r = function + (rule, a, b) -> (r, a, b) + +let rec build_jptree inf = + match inf with + | [] -> ([], JPempty) + | h::r -> + begin + match count_jpbranch h with + | JP0 -> (r,JPAx h) + | JP1 -> let (r1,left) = build_jptree r in + (r1, JPA(h, left)) + | JP2 -> let (r1,left) = build_jptree r in + let (r2,right) = build_jptree r1 in + (r2, JPB(h, left, right)) + | JP2' -> let (r1,left) = build_jptree r in (* for [Impl] *) + let (r2,right) = build_jptree r1 in + (r2, JPB(h, right, left)) + | JPT -> let (r1,left) = build_jptree r in (* right True *) + (r1, JPAx (replace_by Truer h)) + | JPF -> let (r1,left) = build_jptree r in (* left False *) + (r1, JPAx (replace_by Falsel h)) + end + + +(* The main function: *) +(* [limits] is the multiplicity limit. *) +let jp limits gls = + let concl = TM.pf_concl gls in + let ct = concl in +(*i print_constr ct; i*) + Hashtbl.clear jtbl; (* empty the hash tables *) + Hashtbl.clear rtbl; + Hashtbl.clear assoc_addr; + let t = parsing ct in +(*i JT.print_term stdout t; i*) + try + let p = (J.prover limits [] t) in +(*i print_string "\n"; + JLogic.print_inf p; i*) + let (il,tr) = build_jptree p in + if (il = []) then + begin + Pp.msgnl (Pp.str "Proof is built."); + do_coq_proof tr gls + end + else UT.error "Cannot reconstruct proof tree from JProver." + with e -> Pp.msgnl (Pp.str "JProver fails to prove this:"); + JT.print_error_msg e; + UT.error "JProver terminated." + +(* an unfailed generalization procedure *) +let non_dep_gen b gls = + let concl = TM.pf_concl gls in + if (not (Termops.dependent b concl)) then + T.generalize [b] gls + else + TCL.tclIDTAC gls + +let rec unfail_gen = function + | [] -> TCL.tclIDTAC + | h::r -> + TCL.tclTHEN + (TCL.tclORELSE (non_dep_gen h) (TCL.tclIDTAC)) + (unfail_gen r) + +(* +(* no argument, which stands for no multiplicity limit *) +let jp gls = + let ls = List.map (fst) (TM.pf_hyps_types gls) in +(*i T.generalize (List.map TR.mkVar ls) gls i*) + (* generalize the context *) + TCL.tclTHEN (TCL.tclTRY T.red_in_concl) + (TCL.tclTHEN (unfail_gen (List.map TR.mkVar ls)) + (jp None)) gls +*) +(* +let dyn_jp l gls = + assert (l = []); + jp +*) + +(* one optional integer argument for the multiplicity *) +let jpn n gls = + let ls = List.map (fst) (TM.pf_hyps_types gls) in + TCL.tclTHEN (TCL.tclTRY T.red_in_concl) + (TCL.tclTHEN (unfail_gen (List.map TR.mkVar ls)) + (jp n)) gls +(* +let dyn_jpn l gls = + match l with + | [PT.Integer n] -> jpn n + | _ -> jp_error "Impossible!!!" + + +let h_jp = TM.hide_tactic "Jp" dyn_jp + +let h_jpn = TM.hide_tactic "Jpn" dyn_jpn +*) + +TACTIC EXTEND Jprover + [ "Jp" natural_opt(n) ] -> [ jpn n ] +END + +(* +TACTIC EXTEND Andl + [ "Andl" ident(id)] -> [ ... (Andl id) ... ]. +END +*) diff --git a/contrib/jprover/jterm.ml b/contrib/jprover/jterm.ml new file mode 100644 index 00000000..7fc923a5 --- /dev/null +++ b/contrib/jprover/jterm.ml @@ -0,0 +1,872 @@ +open Printf +open Opname +open List + +(* Definitions of [jterm]: *) +type param = param' + and operator = operator' + and term = term' + and bound_term = bound_term' + and param' = + | Number of int + | String of string + | Token of string + | Var of string + | ParamList of param list + and operator' = { op_name : opname; op_params : param list } + and term' = { term_op : operator; term_terms : bound_term list } + and bound_term' = { bvars : string list; bterm : term } +;; + +(* Debugging tools: *) +(*i*) +let mbreak s = Format.print_flush (); print_string ("-break at: "^s); + Format.print_flush (); let _ = input_char stdin in () +(*i*) + +type error_msg = + | TermMatchError of term * string + | StringError of string + +exception RefineError of string * error_msg + +let ref_raise = function + | RefineError(s,e) -> raise (RefineError(s,e)) + | _ -> raise (RefineError ("Jterm", StringError "unexpected error")) + +(* Printing utilities: *) + +let fprint_str ostream s = + let _ = fprintf ostream "%s." s in ostream + +let fprint_str_list ostream sl = + ignore (List.fold_left fprint_str ostream sl); + Format.print_flush () + +let fprint_opname ostream = function + { opname_token= tk; opname_name = sl } -> + fprint_str_list ostream sl + +let rec fprint_param ostream = function + | Number n -> fprintf ostream " %d " n + | String s -> fprint_str_list ostream [s] + | Token t -> fprint_str_list ostream [t] + | Var v -> fprint_str_list ostream [v] + | ParamList ps -> fprint_param_list ostream ps +and fprint_param_list ostream = function + | [] -> () + | param::r -> fprint_param ostream param; + fprint_param_list ostream r +;; + +let print_strs = fprint_str_list stdout + + +(* Interface to [Jall.ml]: *) +(* It is extracted from Meta-Prl's standard implementation. *) +(*c begin of the extraction *) + +type term_subst = (string * term) list +let mk_term op bterms = { term_op = op; term_terms = bterms } +let make_term x = x (* external [make_term : term' -> term] = "%identity" *) +let dest_term x = x (* external [dest_term : term -> term'] = "%identity" *) +let mk_op name params = + { op_name = name; op_params = params } + +let make_op x = x (* external [make_op : operator' -> operator] = "%identity" *) +let dest_op x = x (* external [dest_op : operator -> operator'] = "%identity" *) +let mk_bterm bvars term = { bvars = bvars; bterm = term } +let make_bterm x = x (* external [make_bterm : bound_term' -> bound_term] = "%identity" *) +let dest_bterm x = x (* external [dest_bterm : bound_term -> bound_term'] = "%identity" *) +let make_param x = x (* external [make_param : param' -> param] = "%identity" *) +let dest_param x = x (* external [dest_param : param -> param'] = "%identity" *) + +(* + * Operator names. + *) +let opname_of_term = function + { term_op = { op_name = name } } -> + name + +(* + * Get the subterms. + * None of the subterms should be bound. + *) +let subterms_of_term t = + List.map (fun { bterm = t } -> t) t.term_terms + +let subterm_count { term_terms = terms } = + List.length terms + +let subterm_arities { term_terms = terms } = + List.map (fun { bvars = vars } -> List.length vars) terms + +(* + * Manifest terms are injected into the "perv" module. + *) +let xperv = make_opname ["Perv"] +let sequent_opname = mk_opname "sequent" xperv + +(* + * Variables. + *) + +let var_opname = make_opname ["var"] + +(* + * See if a term is a variable. + *) +let is_var_term = function + | { term_op = { op_name = opname; op_params = [Var v] }; + term_terms = [] + } when Opname.eq opname var_opname -> true + | _ -> + false + +(* + * Destructor for a variable. + *) +let dest_var = function + | { term_op = { op_name = opname; op_params = [Var v] }; + term_terms = [] + } when Opname.eq opname var_opname -> v + | t -> + ref_raise(RefineError ("dest_var", TermMatchError (t, "not a variable"))) +(* + * Make a variable. + *) +let mk_var_term v = + { term_op = { op_name = var_opname; op_params = [Var v] }; + term_terms = [] + } + +(* + * Simple terms + *) +(* + * "Simple" terms have no parameters and no binding variables. + *) +let is_simple_term_opname name = function + | { term_op = { op_name = name'; op_params = [] }; + term_terms = bterms + } when Opname.eq name' name -> + let rec aux = function + | { bvars = []; bterm = _ }::t -> aux t + | _::t -> false + | [] -> true + in + aux bterms + | _ -> false + +let mk_any_term op terms = + let aux t = + { bvars = []; bterm = t } + in + { term_op = op; term_terms = List.map aux terms } + +let mk_simple_term name terms = + mk_any_term { op_name = name; op_params = [] } terms + +let dest_simple_term = function + | ({ term_op = { op_name = name; op_params = [] }; + term_terms = bterms + } : term) as t -> + let aux = function + | { bvars = []; bterm = t } -> + t + | _ -> + ref_raise(RefineError ("dest_simple_term", TermMatchError (t, "binding vars exist"))) + in + name, List.map aux bterms + | t -> + ref_raise(RefineError ("dest_simple_term", TermMatchError (t, "params exist"))) + +let dest_simple_term_opname name = function + | ({ term_op = { op_name = name'; op_params = [] }; + term_terms = bterms + } : term) as t -> + if Opname.eq name name' then + let aux = function + | { bvars = []; bterm = t } -> t + | _ -> ref_raise(RefineError ("dest_simple_term_opname", TermMatchError (t, "binding vars exist"))) + in + List.map aux bterms + else + ref_raise(RefineError ("dest_simple_term_opname", TermMatchError (t, "opname mismatch"))) + | t -> + ref_raise(RefineError ("dest_simple_term_opname", TermMatchError (t, "params exist"))) + +(* + * Bound terms. + *) +let mk_simple_bterm bterm = + { bvars = []; bterm = bterm } + +let dest_simple_bterm = function + | { bvars = []; bterm = bterm } -> + bterm + | _ -> + ref_raise(RefineError ("dest_simple_bterm", StringError ("bterm is not simple"))) + +(* Copy from [term_op_std.ml]: *) +(*i modified for Jprover, as a patch... i*) +let mk_string_term opname s = + { term_op = { op_name = opname; op_params = [String s] }; term_terms = [] } + +(*i let mk_string_term opname s = + let new_opname={opname_token=opname.opname_token; opname_name=(List.tl opname.opname_name)@[s]} in + { term_op = { op_name = new_opname; op_params = [String (List.hd opname.opname_name)] }; term_terms = [] } +i*) + +(* Copy from [term_subst_std.ml]: *) + +let rec free_vars_term gvars bvars = function + | { term_op = { op_name = opname; op_params = [Var v] }; term_terms = bterms } when Opname.eq opname var_opname -> + (* This is a variable *) + let gvars' = + if List.mem v bvars or List.mem v gvars then + gvars + else + v::gvars + in + free_vars_bterms gvars' bvars bterms + | { term_terms = bterms } -> + free_vars_bterms gvars bvars bterms + and free_vars_bterms gvars bvars = function + | { bvars = vars; bterm = term}::l -> + let bvars' = vars @ bvars in + let gvars' = free_vars_term gvars bvars' term in + free_vars_bterms gvars' bvars l + | [] -> + gvars + +let free_vars_list = free_vars_term [] [] + + +(* Termop: *) + +let is_no_subterms_term opname = function + | { term_op = { op_name = opname'; op_params = [] }; + term_terms = [] + } -> + Opname.eq opname' opname + | _ -> + false + +(* + * Terms with one subterm. + *) +let is_dep0_term opname = function + | { term_op = { op_name = opname'; op_params = [] }; + term_terms = [{ bvars = [] }] + } -> Opname.eq opname' opname + | _ -> false + +let mk_dep0_term opname t = + { term_op = { op_name = opname; op_params = [] }; + term_terms = [{ bvars = []; bterm = t }] + } + +let dest_dep0_term opname = function + | { term_op = { op_name = opname'; op_params = [] }; + term_terms = [{ bvars = []; bterm = t }] + } when Opname.eq opname' opname -> t + | t -> ref_raise(RefineError ("dest_dep0_term", TermMatchError (t, "not a dep0 term"))) + +(* + * Terms with two subterms. + *) +let is_dep0_dep0_term opname = function + | { term_op = { op_name = opname'; op_params = [] }; + term_terms = [{ bvars = [] }; { bvars = [] }] + } -> Opname.eq opname' opname + | _ -> false + +let mk_dep0_dep0_term opname = fun + t1 t2 -> + { term_op = { op_name = opname; op_params = [] }; + term_terms = [{ bvars = []; bterm = t1 }; + { bvars = []; bterm = t2 }] + } + +let dest_dep0_dep0_term opname = function + | { term_op = { op_name = opname'; op_params = [] }; + term_terms = [{ bvars = []; bterm = t1 }; + { bvars = []; bterm = t2 }] + } when Opname.eq opname' opname -> t1, t2 + | t -> ref_raise(RefineError ("dest_dep0_dep0_term", TermMatchError (t, "bad arity"))) + +(* + * Bound term. + *) + +let is_dep0_dep1_term opname = function + | { term_op = { op_name = opname'; op_params = [] }; + term_terms = [{ bvars = [] }; { bvars = [_] }] + } when Opname.eq opname' opname -> true + | _ -> false + +let is_dep0_dep1_any_term = function + | { term_op = { op_params = [] }; + term_terms = [{ bvars = [] }; { bvars = [_] }] + } -> true + | _ -> false + +let mk_dep0_dep1_term opname = fun + v t1 t2 -> { term_op = { op_name = opname; op_params = [] }; + term_terms = [{ bvars = []; bterm = t1 }; + { bvars = [v]; bterm = t2 }] + } + +let dest_dep0_dep1_term opname = function + | { term_op = { op_name = opname'; op_params = [] }; + term_terms = [{ bvars = []; bterm = t1 }; + { bvars = [v]; bterm = t2 }] + } when Opname.eq opname' opname -> v, t1, t2 + | t -> ref_raise(RefineError ("dest_dep0_dep1_term", TermMatchError (t, "bad arity"))) + +let rec smap f = function + | [] -> [] + | (hd::tl) as l -> + let hd' = f hd in + let tl' = smap f tl in + if (hd==hd')&&(tl==tl') then l else hd'::tl' + +let rec try_check_assoc v v' = function + | [] -> raise Not_found + | (v1,v2)::tl -> + begin match v=v1, v'=v2 with + | true, true -> true + | false, false -> try_check_assoc v v' tl + | _ -> false + end + +let rec zip_list l l1 l2 = match (l1,l2) with + | (h1::t1), (h2::t2) -> + zip_list ((h1,h2)::l) t1 t2 + | [], [] -> + l + | _ -> raise (Failure "Term.zip_list") + +let rec assoc_in_range eq y = function + | (_, y')::tl -> + (eq y y') || (assoc_in_range eq y tl) + | [] -> + false + +let rec check_assoc v v' = function + | [] -> v=v' + | (v1,v2)::tl -> + begin match v=v1, v'=v2 with + | true, true -> true + | false, false -> check_assoc v v' tl + | _ -> false + end + +let rec zip a b = match (a,b) with + | (h1::t1), (h2::t2) -> + (h1, h2) :: zip t1 t2 + | [], [] -> + [] + | + _ -> raise (Failure "Term.zip") + +let rec for_all2 f l1 l2 = + match (l1,l2) with + | h1::t1, h2::t2 -> for_all2 f t1 t2 & f h1 h2 + | [], [] -> true + | _ -> false + +let newname v i = + v ^ "_" ^ (string_of_int i) + +let rec new_var v avoid i = + let v' = newname v i in + if avoid v' + then new_var v avoid (succ i) + else v' + +let vnewname v avoid = new_var v avoid 1 + +let rev_mem a b = List.mem b a + +let rec find_index_aux v i = function + | h::t -> + if h = v then + i + else + find_index_aux v (i + 1) t + | [] -> + raise Not_found + +let find_index v l = find_index_aux v 0 l + +let rec remove_elements l1 l2 = + match l1, l2 with + | flag::ft, h::t -> + if flag then + remove_elements ft t + else + h :: remove_elements ft t + | _, l -> + l + +let rec subtract l1 l2 = + match l1 with + | h::t -> + if List.mem h l2 then + subtract t l2 + else + h :: subtract t l2 + | [] -> + [] + +let rec fv_mem fv v = + match fv with + | [] -> false + | h::t -> + List.mem v h || fv_mem t v + +let rec new_vars fv = function + | [] -> [] + | v::t -> + (* Rename the first one, then add it to free vars *) + let v' = vnewname v (fv_mem fv) in + v'::(new_vars ([v']::fv) t) + +let rec fsubtract l = function + | [] -> l + | h::t -> + fsubtract (subtract l h) t + +let add_renames_fv r l = + let rec aux = function + | [] -> l + | v::t -> [v]::(aux t) + in + aux r + +let add_renames_terms r l = + let rec aux = function + | [] -> l + | v::t -> (mk_var_term v)::(aux t) + in + aux r + +(* + * First order simultaneous substitution. + *) +let rec subst_term terms fv vars = function + | { term_op = { op_name = opname; op_params = [Var(v)] }; term_terms = [] } as t + when Opname.eq opname var_opname-> + (* Var case *) + begin + try List.nth terms (find_index v vars) with + Not_found -> + t + end + | { term_op = op; term_terms = bterms } -> + (* Other term *) + { term_op = op; term_terms = subst_bterms terms fv vars bterms } + +and subst_bterms terms fv vars bterms = + (* When subst through bterms, catch binding occurrences *) + let rec subst_bterm = function + | { bvars = []; bterm = term } -> + (* Optimize the common case *) + { bvars = []; bterm = subst_term terms fv vars term } + + | { bvars = bvars; bterm = term } -> + (* First subtract bound instances *) + let flags = List.map (function v -> List.mem v bvars) vars in + let vars' = remove_elements flags vars in + let fv' = remove_elements flags fv in + let terms' = remove_elements flags terms in + + (* If any of the binding variables are free, rename them *) + let renames = subtract bvars (fsubtract bvars fv') in + if renames <> [] then + let fv'' = (free_vars_list term)::fv' in + let renames' = new_vars fv'' renames in + { bvars = subst_bvars renames' renames bvars; + bterm = subst_term + (add_renames_terms renames' terms') + (add_renames_fv renames' fv') + (renames @ vars') + term + } + else + { bvars = bvars; + bterm = subst_term terms' fv' vars' term + } + in + List.map subst_bterm bterms + +and subst_bvars renames' renames bvars = + let subst_bvar v = + try List.nth renames' (find_index v renames) with + Not_found -> v + in + List.map subst_bvar bvars + +let subst term vars terms = + subst_term terms (List.map free_vars_list terms) vars term + +(*i bug!!! in the [term_std] module + let subst1 t var term = + let fv = free_vars_list term in + if List.mem var fv then + subst_term [term] [fv] [var] t + else + t +The following is the correct implementation +i*) + +let subst1 t var term = +if List.mem var (free_vars_list t) then + subst_term [term] [free_vars_list term] [var] t +else + t + +let apply_subst t s = + let vs,ts = List.split s in + subst t vs ts + +let rec equal_params p1 p2 = + match p1, p2 with + | Number n1, Number n2 -> + n1 = n2 + | ParamList pl1, ParamList pl2 -> + List.for_all2 equal_params pl1 pl2 + | _ -> + p1 = p2 + +let rec equal_term vars t t' = + match t, t' with + | { term_op = { op_name = opname1; op_params = [Var v] }; + term_terms = [] + }, + { term_op = { op_name = opname2; op_params = [Var v'] }; + term_terms = [] + } when Opname.eq opname1 var_opname & Opname.eq opname2 var_opname -> + check_assoc v v' vars + | { term_op = { op_name = name1; op_params = params1 }; term_terms = bterms1 }, + { term_op = { op_name = name2; op_params = params2 }; term_terms = bterms2 } -> + (Opname.eq name1 name2) + & (for_all2 equal_params params1 params2) + & (equal_bterms vars bterms1 bterms2) +and equal_bterms vars bterms1 bterms2 = + let equal_bterm = fun + { bvars = bvars1; bterm = term1 } + { bvars = bvars2; bterm = term2 } -> + equal_term (zip_list vars bvars1 bvars2) term1 term2 + in + for_all2 equal_bterm bterms1 bterms2 + + +let alpha_equal t1 t2 = + try equal_term [] t1 t2 with Failure _ -> false + +let var_subst t t' v = + let { term_op = { op_name = opname } } = t' in + let vt = mk_var_term v in + let rec subst_term = function + { term_op = { op_name = opname'; op_params = params }; + term_terms = bterms + } as t -> + (* Check if this is the same *) + if Opname.eq opname' opname & alpha_equal t t' then + vt + else + { term_op = { op_name = opname'; op_params = params }; + term_terms = List.map subst_bterm bterms + } + + and subst_bterm { bvars = vars; bterm = term } = + if List.mem v vars then + let av = vars @ (free_vars_list term) in + let v' = vnewname v (fun v -> List.mem v av) in + let rename var = if var = v then v' else var in + let term = subst1 term v (mk_var_term v') in + { bvars = smap rename vars; bterm = subst_term term } + else + { bvars = vars; bterm = subst_term term } + in + subst_term t + +let xnil_opname = mk_opname "nil" xperv +let xnil_term = mk_simple_term xnil_opname [] +let is_xnil_term = is_no_subterms_term xnil_opname + +(*c End of the extraction from Meta-Prl *) + +(* Huang's modification: *) +let all_opname = make_opname ["quantifier";"all"] +let is_all_term = is_dep0_dep1_term all_opname +let dest_all = dest_dep0_dep1_term all_opname +let mk_all_term = mk_dep0_dep1_term all_opname + +let exists_opname = make_opname ["quantifier";"exst"] +let is_exists_term = is_dep0_dep1_term exists_opname +let dest_exists = dest_dep0_dep1_term exists_opname +let mk_exists_term = mk_dep0_dep1_term exists_opname + +let or_opname = make_opname ["connective";"or"] +let is_or_term = is_dep0_dep0_term or_opname +let dest_or = dest_dep0_dep0_term or_opname +let mk_or_term = mk_dep0_dep0_term or_opname + +let and_opname = make_opname ["connective";"and"] +let is_and_term = is_dep0_dep0_term and_opname +let dest_and = dest_dep0_dep0_term and_opname +let mk_and_term = mk_dep0_dep0_term and_opname + +let cor_opname = make_opname ["connective";"cor"] +let is_cor_term = is_dep0_dep0_term cor_opname +let dest_cor = dest_dep0_dep0_term cor_opname +let mk_cor_term = mk_dep0_dep0_term cor_opname + +let cand_opname = make_opname ["connective";"cand"] +let is_cand_term = is_dep0_dep0_term cand_opname +let dest_cand = dest_dep0_dep0_term cand_opname +let mk_cand_term = mk_dep0_dep0_term cand_opname + +let implies_opname = make_opname ["connective";"=>"] +let is_implies_term = is_dep0_dep0_term implies_opname +let dest_implies = dest_dep0_dep0_term implies_opname +let mk_implies_term = mk_dep0_dep0_term implies_opname + +let iff_opname = make_opname ["connective";"iff"] +let is_iff_term = is_dep0_dep0_term iff_opname +let dest_iff = dest_dep0_dep0_term iff_opname +let mk_iff_term = mk_dep0_dep0_term iff_opname + +let not_opname = make_opname ["connective";"not"] +let is_not_term = is_dep0_term not_opname +let dest_not = dest_dep0_term not_opname +let mk_not_term = mk_dep0_term not_opname + +let var_ = mk_var_term +let fun_opname = make_opname ["function"] +let fun_ f ts = mk_any_term {op_name = fun_opname; op_params = [String f] } ts + +let is_fun_term = function + | { term_op = { op_name = opname; op_params = [String f] }} + when Opname.eq opname fun_opname -> true + | _ -> + false + +let dest_fun = function + | { term_op = { op_name = opname; op_params = [String f] }; term_terms = ts} + when Opname.eq opname fun_opname -> (f, List.map (fun { bterm = t } -> t) ts) + | t -> + ref_raise(RefineError ("dest_fun", TermMatchError (t, "not a function symbol"))) + +let const_ c = fun_ c [] +let is_const_term = function + | { term_op = { op_name = opname; op_params = [String f] }; term_terms = [] } + when Opname.eq opname fun_opname -> true + | _ -> + false + +let dest_const t = + let (n, ts) = dest_fun t in n + +let pred_opname = make_opname ["predicate"] +let pred_ p ts = mk_any_term {op_name = pred_opname; op_params = [String p] } ts + +let not_ = mk_not_term +let and_ = mk_and_term +let or_ = mk_or_term +let imp_ = mk_implies_term +let cand_ = mk_cand_term +let cor_ = mk_cor_term +let iff_ = mk_iff_term +let nil_term = {term_op={op_name=nil_opname; op_params=[]}; term_terms=[] } +let forall v t = mk_all_term v nil_term t +let exists v t= mk_exists_term v nil_term t +let rec wbin op = function + | [] -> raise (Failure "Term.wbin") + | [t] -> t + | t::r -> op t (wbin op r) + +let wand_ = wbin and_ +let wor_ = wbin or_ +let wimp_ = wbin imp_ + +(*i let true_opname = make_opname ["bool";"true"] +let is_true_term = is_no_subterms_term true_opname +let true_ = mk_simple_term true_opname [] +let false_ = not_ true_ + +let is_false_term t = + if is_not_term t then + let t1 = dest_not t in + is_true_term t1 + else + false +i*) + +let dummy_false_ = mk_simple_term (make_opname ["bool";"false"]) [] +let dummy_true_ = mk_simple_term (make_opname ["bool";"true"]) [] +let false_ = and_ (dummy_false_) (not_ dummy_false_) +let true_ = not_ (and_ (dummy_true_) (not_ dummy_true_)) + +let is_false_term t = + if (alpha_equal t false_) then true + else false + +let is_true_term t = + if (alpha_equal t true_) then true + else false + +(* Print a term [t] via the [ostream]: *) +let rec fprint_term ostream t prec = + let l_print op_prec = + if (prec > op_prec) then fprintf ostream "(" in + let r_print op_prec = + if (prec > op_prec) then fprintf ostream ")" in + if is_false_term t then (* false *) + fprint_str_list ostream ["False"] + else if is_true_term t then (* true *) + fprint_str_list ostream ["True"] + else if is_all_term t then (* for all *) + let v, t1, t2 = dest_all t in + fprint_str_list ostream ["A."^v]; + fprint_term ostream t2 4 + else if is_exists_term t then (* exists *) + let v, t1, t2 = dest_exists t in + fprint_str_list ostream ["E."^v]; + fprint_term ostream t2 4 (* implication *) + else if is_implies_term t then + let t1, t2 = dest_implies t in + l_print 0; + fprint_term ostream t1 1; + fprint_str_list ostream ["=>"]; + fprint_term ostream t2 0; + r_print 0 + else if is_and_term t then (* logical and *) + let t1, t2 = dest_and t in + l_print 3; + fprint_term ostream t1 3; + fprint_str_list ostream ["&"]; + fprint_term ostream t2 3; + r_print 3 + else if is_or_term t then (* logical or *) + let t1, t2 = dest_or t in + l_print 2; + fprint_term ostream t1 2; + fprint_str_list ostream ["|"]; + fprint_term ostream t2 2; + r_print 2 + else if is_not_term t then (* logical not *) + let t2 = dest_not t in + fprint_str_list ostream ["~"]; + fprint_term ostream t2 4 (* nil term *) + else if is_xnil_term t then + fprint_str_list ostream ["NIL"] + else match t with (* other cases *) + { term_op = { op_name = opname; op_params = opparm }; term_terms = bterms} -> + if (Opname.eq opname pred_opname) || (Opname.eq opname fun_opname) then + begin + fprint_param_list ostream opparm; + if bterms != [] then + begin + fprintf ostream "("; + fprint_bterm_list ostream prec bterms; + fprintf ostream ")"; + end + end else + begin + fprintf ostream "["; +(* fprint_opname ostream opname; + fprintf ostream ": "; *) + fprint_param_list ostream opparm; + if bterms != [] then + begin + fprintf ostream "("; + fprint_bterm_list ostream prec bterms; + fprintf ostream ")"; + end; + fprintf ostream "]" + end +and fprint_bterm_list ostream prec = function + | [] -> () + | {bvars=bv; bterm=bt}::r -> + fprint_str_list ostream bv; + fprint_term ostream bt prec; + if (r<>[]) then fprint_str_list ostream [","]; + fprint_bterm_list ostream prec r +;; + + +let print_term ostream t = + Format.print_flush (); + fprint_term ostream t 0; + Format.print_flush () + +let print_error_msg = function + | RefineError(s,e) -> print_string ("(module "^s^") "); + begin + match e with + | TermMatchError(t,s) -> print_term stdout t; print_string (s^"\n") + | StringError s -> print_string (s^"\n") + end + | ue -> print_string "Unexpected error for Jp.\n"; + raise ue + + +(* Naive implementation for [jterm] substitution, unification, etc.: *) +let substitute subst term = + apply_subst term subst + +(* A naive unification algorithm: *) +let compsubst subst1 subst2 = + (List.map (fun (v, t) -> (v, substitute subst1 t)) subst2) @ subst1 +;; + +let rec extract_terms = function + | [] -> [] + | h::r -> let {bvars=_; bterm=bt}=h in bt::extract_terms r + +(* Occurs check: *) +let occurs v t = + let rec occur_rec t = + if is_var_term t then v=dest_var t + else let { term_op = _ ; term_terms = bterms} = t in + let sons = extract_terms bterms in + List.exists occur_rec sons + in + occur_rec t + +(* The naive unification algorithm: *) +let rec unify2 (term1,term2) = + if is_var_term term1 then + if equal_term [] term1 term2 then [] + else let v1 = dest_var term1 in + if occurs v1 term2 then raise (RefineError ("unify1", StringError ("1"))) + else [v1,term2] + else if is_var_term term2 then + let v2 = dest_var term2 in + if occurs v2 term1 then raise (RefineError ("unify2", StringError ("2"))) + else [v2,term1] + else + let { term_op = { op_name = opname1; op_params = params1 }; + term_terms = bterms1 + } = term1 + in + let { term_op = { op_name = opname2; op_params = params2 }; + term_terms = bterms2 + } = term2 + in + if Opname.eq opname1 opname2 & params1 = params2 then + let sons1 = extract_terms bterms1 + and sons2 = extract_terms bterms2 in + List.fold_left2 + (fun s t1 t2 -> compsubst + (unify2 (substitute s t1, substitute s t2)) s) + [] sons1 sons2 + else raise (RefineError ("unify3", StringError ("3"))) + +let unify term1 term2 = unify2 (term1, term2) +let unify_mm term1 term2 _ = unify2 (term1, term2) diff --git a/contrib/jprover/jterm.mli b/contrib/jprover/jterm.mli new file mode 100644 index 00000000..0bc42010 --- /dev/null +++ b/contrib/jprover/jterm.mli @@ -0,0 +1,110 @@ +(* This module is modified and extracted from Meta-Prl. *) + +(* Definitions of [jterm]: *) +type param = param' +and operator = operator' +and term = term' +and bound_term = bound_term' +and param' = + | Number of int + | String of string + | Token of string + | Var of string + | ParamList of param list +and operator' = { op_name : Opname.opname; op_params : param list; } +and term' = { term_op : operator; term_terms : bound_term list; } +and bound_term' = { bvars : string list; bterm : term; } +type term_subst = (string * term) list + +type error_msg = TermMatchError of term * string | StringError of string + +exception RefineError of string * error_msg + +(* Collect free variables: *) +val free_vars_list : term -> string list + +(* Substitutions: *) +val subst_term : term list -> string list list -> string list -> term -> term +val subst : term -> string list -> term list -> term +val subst1 : term -> string -> term -> term +val var_subst : term -> term -> string -> term +val apply_subst : term -> (string * term) list -> term + +(* Unification: *) +val unify_mm : term -> term -> 'a -> (string * term) list + +val xnil_term : term' + +(* Testing functions: *) +val is_xnil_term : term' -> bool +val is_var_term : term' -> bool +val is_true_term : term' -> bool +val is_false_term : term' -> bool +val is_all_term : term' -> bool +val is_exists_term : term' -> bool +val is_or_term : term' -> bool +val is_and_term : term' -> bool +val is_cor_term : term' -> bool +val is_cand_term : term' -> bool +val is_implies_term : term' -> bool +val is_iff_term : term' -> bool +val is_not_term : term' -> bool +val is_fun_term : term -> bool +val is_const_term : term -> bool + + +(* Constructors for [jterms]: *) +val var_ : string -> term' +val fun_ : string -> term list -> term' +val const_ : string -> term' +val pred_ : string -> term list -> term' +val not_ : term -> term' +val and_ : term -> term -> term' +val or_ : term -> term -> term' +val imp_ : term -> term -> term' +val cand_ : term -> term -> term' +val cor_ : term -> term -> term' +val iff_ : term -> term -> term' +val false_ : term' +val true_ : term' +val nil_term : term' +val forall : string -> term -> term' +val exists : string -> term -> term' + + +(* Destructors for [jterm]: *) +val dest_var : term -> string +val dest_fun : term -> string * term list +val dest_const : term -> string +val dest_not : term -> term +val dest_iff : term -> term * term +val dest_implies : term -> term * term +val dest_cand : term -> term * term +val dest_cor : term -> term * term +val dest_and : term -> term * term +val dest_or : term -> term * term +val dest_exists : term -> string * term * term +val dest_all : term -> string * term * term + +(* Wide-logical connectives: *) +val wand_ : term list -> term +val wor_ : term list -> term +val wimp_ : term list -> term + +(* Printing and debugging tools: *) +val fprint_str_list : out_channel -> string list -> unit +val mbreak : string -> unit +val print_strs : string list -> unit +val print_term : out_channel -> term -> unit +val print_error_msg : exn -> unit + +(* Other exported functions for [jall.ml]: *) +val make_term : 'a -> 'a +val dest_term : 'a -> 'a +val make_op : 'a -> 'a +val dest_op : 'a -> 'a +val make_bterm : 'a -> 'a +val dest_bterm : 'a -> 'a +val dest_param : 'a -> 'a +val mk_var_term : string -> term' +val mk_string_term : Opname.opname -> string -> term' diff --git a/contrib/jprover/jtunify.ml b/contrib/jprover/jtunify.ml new file mode 100644 index 00000000..2295e62c --- /dev/null +++ b/contrib/jprover/jtunify.ml @@ -0,0 +1,507 @@ +(* + * Unification procedures for JProver. See jall.mli for more + * information on JProver. + * + * ---------------------------------------------------------------- + * + * This file is part of MetaPRL, a modular, higher order + * logical framework that provides a logical programming + * environment for OCaml and other languages. + * + * See the file doc/index.html for information on Nuprl, + * OCaml, and more information about this system. + * + * Copyright (C) 2000 Stephan Schmitt + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Stephan Schmitt + * Modified by: Aleksey Nogin + *) + +exception Not_unifiable +exception Failed + +let jprover_bug = Invalid_argument "Jprover bug (Jtunify module)" + +(* ************ T-STRING UNIFICATION *********************************) + + +(* ******* printing ********** *) + +let rec list_to_string s = + match s with + [] -> "" + | f::r -> + f^"."^(list_to_string r) + +let rec print_eqlist eqlist = + match eqlist with + [] -> + print_endline "" + | (atnames,f)::r -> + let (s,t) = f in + let ls = list_to_string s + and lt = list_to_string t in + begin + print_endline ("Atom names: "^(list_to_string atnames)); + print_endline (ls^" = "^lt); + print_eqlist r + end + +let print_equations eqlist = + begin + Format.open_box 0; + Format.force_newline (); + print_endline "Equations:"; + print_eqlist eqlist; + Format.force_newline (); + end + +let rec print_subst sigma = + match sigma with + [] -> + print_endline "" + | f::r -> + let (v,s) = f in + let ls = list_to_string s in + begin + print_endline (v^" = "^ls); + print_subst r + end + +let print_tunify sigma = + let (n,subst) = sigma in + begin + print_endline " "; + print_endline ("MaxVar = "^(string_of_int (n-1))); + print_endline " "; + print_endline "Substitution:"; + print_subst subst; + print_endline " " + end + + (*****************************************************) + +let is_const name = + (String.get name 0) = 'c' + +let is_var name = + (String.get name 0) = 'v' + +let r_1 s ft rt = + (s = []) && (ft = []) && (rt = []) + +let r_2 s ft rt = + (s = []) && (ft = []) && (List.length rt >= 1) + +let r_3 s ft rt = + ft=[] && (List.length s >= 1) && (List.length rt >= 1) && (List.hd s = List.hd rt) + +let r_4 s ft rt = + ft=[] + && (List.length s >= 1) + && (List.length rt >= 1) + && is_const (List.hd s) + && is_var (List.hd rt) + +let r_5 s ft rt = + rt=[] + && (List.length s >= 1) + && is_var (List.hd s) + +let r_6 s ft rt = + ft=[] + && (List.length s >= 1) + && (List.length rt >= 1) + && is_var (List.hd s) + && is_const (List.hd rt) + +let r_7 s ft rt = + List.length s >= 1 + && (List.length rt >= 2) + && is_var (List.hd s) + && is_const (List.hd rt) + && is_const (List.hd (List.tl rt)) + +let r_8 s ft rt = + ft=[] + && List.length s >= 2 + && List.length rt >= 1 + && let v = List.hd s + and v1 = List.hd rt in + (is_var v) & (is_var v1) & (v <> v1) + +let r_9 s ft rt = + (List.length s >= 2) && (List.length ft >= 1) && (List.length rt >= 1) + && let v = (List.hd s) + and v1 = (List.hd rt) in + (is_var v) & (is_var v1) & (v <> v1) + +let r_10 s ft rt = + (List.length s >= 1) && (List.length rt >= 1) + && let v = List.hd s + and x = List.hd rt in + (is_var v) && (v <> x) + && (((List.tl s) =[]) or (is_const x) or ((List.tl rt) <> [])) + +let rec com_subst slist ((ov,ovlist) as one_subst) = + match slist with + [] -> raise jprover_bug + | f::r -> + if f = ov then + (ovlist @ r) + else + f::(com_subst r one_subst) + +let rec combine subst ((ov,oslist) as one_subst) = + match subst with + [] -> [] + | ((v, slist) as f) :: r -> + let rest_combine = (combine r one_subst) in + if (List.mem ov slist) then (* subst assumed to be idemponent *) + let com_element = com_subst slist one_subst in + ((v,com_element)::rest_combine) + else + (f::rest_combine) + +let compose ((n,subst) as sigma) ((ov,oslist) as one_subst) = + let com = combine subst one_subst in +(* begin + print_endline "!!!!!!!!!test print!!!!!!!!!!"; + print_subst [one_subst]; + print_subst subst; + print_endline "!!!!!!!!! END test print!!!!!!!!!!"; +*) + if List.mem one_subst subst then + (n,com) + else +(* ov may multiply as variable in subst with DIFFERENT values *) +(* in order to avoid explicit atom instances!!! *) + (n,(com @ [one_subst])) +(* end *) + +let rec apply_element fs ft (v,slist) = + match (fs,ft) with + ([],[]) -> + ([],[]) + | ([],(ft_first::ft_rest)) -> + let new_ft_first = + if ft_first = v then + slist + else + [ft_first] + in + let (emptylist,new_ft_rest) = apply_element [] ft_rest (v,slist) in + (emptylist,(new_ft_first @ new_ft_rest)) + | ((fs_first::fs_rest),[]) -> + let new_fs_first = + if fs_first = v then + slist + else + [fs_first] + in + let (new_fs_rest,emptylist) = apply_element fs_rest [] (v,slist) in + ((new_fs_first @ new_fs_rest),emptylist) + | ((fs_first::fs_rest),(ft_first::ft_rest)) -> + let new_fs_first = + if fs_first = v then + slist + else + [fs_first] + and new_ft_first = + if ft_first = v then + slist + else + [ft_first] + in + let (new_fs_rest,new_ft_rest) = apply_element fs_rest ft_rest (v,slist) in + ((new_fs_first @ new_fs_rest),(new_ft_first @ new_ft_rest)) + +let rec shorten us ut = + match (us,ut) with + ([],_) | (_,[]) -> (us,ut) (*raise jprover_bug*) + | ((fs::rs),(ft::rt)) -> + if fs = ft then + shorten rs rt + else + (us,ut) + +let rec apply_subst_list eq_rest (v,slist) = + match eq_rest with + [] -> + (true,[]) + | (atomnames,(fs,ft))::r -> + let (n_fs,n_ft) = apply_element fs ft (v,slist) in + let (new_fs,new_ft) = shorten n_fs n_ft in (* delete equal first elements *) + match (new_fs,new_ft) with + [],[] -> + let (bool,new_eq_rest) = apply_subst_list r (v,slist) in + (bool,((atomnames,([],[]))::new_eq_rest)) + | [],(fft::rft) -> + if (is_const fft) then + (false,[]) + else + let (bool,new_eq_rest) = apply_subst_list r (v,slist) in + (bool,((atomnames,([],new_ft))::new_eq_rest)) + | (ffs::rfs),[] -> + if (is_const ffs) then + (false,[]) + else + let (bool,new_eq_rest) = apply_subst_list r (v,slist) in + (bool,((atomnames,(new_fs,[]))::new_eq_rest)) + | (ffs::rfs),(fft::rft) -> + if (is_const ffs) & (is_const fft) then + (false,[]) + (* different first constants cause local fail *) + else + (* at least one of firsts is a variable *) + let (bool,new_eq_rest) = apply_subst_list r (v,slist) in + (bool,((atomnames,(new_fs,new_ft))::new_eq_rest)) + +let apply_subst eq_rest (v,slist) atomnames = + if (List.mem v atomnames) then (* don't apply subst to atom variables !! *) + (true,eq_rest) + else + apply_subst_list eq_rest (v,slist) + + +(* let all_variable_check eqlist = false needs some discussion with Jens! -- NOT done *) + +(* + let rec all_variable_check eqlist = + match eqlist with + [] -> true + | ((_,(fs,ft))::rest_eq) -> + if (fs <> []) & (ft <> []) then + let fs_first = List.hd fs + and ft_first = List.hd ft + in + if (is_const fs_first) or (is_const ft_first) then + false + else + all_variable_check rest_eq + else + false +*) + +let rec tunify_list eqlist init_sigma = + let rec tunify atomnames fs ft rt rest_eq sigma = + let apply_r1 fs ft rt rest_eq sigma = + (* print_endline "r1"; *) + tunify_list rest_eq sigma + + in + let apply_r2 fs ft rt rest_eq sigma = + (* print_endline "r2"; *) + tunify atomnames rt fs ft rest_eq sigma + + in + let apply_r3 fs ft rt rest_eq sigma = + (* print_endline "r3"; *) + let rfs = (List.tl fs) + and rft = (List.tl rt) in + tunify atomnames rfs ft rft rest_eq sigma + + in + let apply_r4 fs ft rt rest_eq sigma = + (* print_endline "r4"; *) + tunify atomnames rt ft fs rest_eq sigma + + in + let apply_r5 fs ft rt rest_eq sigma = + (* print_endline "r5"; *) + let v = (List.hd fs) in + let new_sigma = compose sigma (v,ft) in + let (bool,new_rest_eq) = apply_subst rest_eq (v,ft) atomnames in + if (bool=false) then + raise Not_unifiable + else + tunify atomnames (List.tl fs) rt rt new_rest_eq new_sigma + + in + let apply_r6 fs ft rt rest_eq sigma = + (* print_endline "r6"; *) + let v = (List.hd fs) in + let new_sigma = (compose sigma (v,[])) in + let (bool,new_rest_eq) = apply_subst rest_eq (v,[]) atomnames in + if (bool=false) then + raise Not_unifiable + else + tunify atomnames (List.tl fs) ft rt new_rest_eq new_sigma + + in + let apply_r7 fs ft rt rest_eq sigma = + (* print_endline "r7"; *) + let v = (List.hd fs) + and c1 = (List.hd rt) + and c2t =(List.tl rt) in + let new_sigma = (compose sigma (v,(ft @ [c1]))) in + let (bool,new_rest_eq) = apply_subst rest_eq (v,(ft @ [c1])) atomnames in + if bool=false then + raise Not_unifiable + else + tunify atomnames (List.tl fs) [] c2t new_rest_eq new_sigma + in + let apply_r8 fs ft rt rest_eq sigma = + (* print_endline "r8"; *) + tunify atomnames rt [(List.hd fs)] (List.tl fs) rest_eq sigma + + in + let apply_r9 fs ft rt rest_eq sigma = + (* print_endline "r9"; *) + let v = (List.hd fs) + and (max,subst) = sigma in + let v_new = ("vnew"^(string_of_int max)) in + let new_sigma = (compose ((max+1),subst) (v,(ft @ [v_new]))) in + let (bool,new_rest_eq) = apply_subst rest_eq (v,(ft @ [v_new])) atomnames in + if (bool=false) then + raise Not_unifiable + else + tunify atomnames rt [v_new] (List.tl fs) new_rest_eq new_sigma + + in + let apply_r10 fs ft rt rest_eq sigma = + (* print_endline "r10"; *) + let x = List.hd rt in + tunify atomnames fs (ft @ [x]) (List.tl rt) rest_eq sigma + + in + if r_1 fs ft rt then + apply_r1 fs ft rt rest_eq sigma + else if r_2 fs ft rt then + apply_r2 fs ft rt rest_eq sigma + else if r_3 fs ft rt then + apply_r3 fs ft rt rest_eq sigma + else if r_4 fs ft rt then + apply_r4 fs ft rt rest_eq sigma + else if r_5 fs ft rt then + apply_r5 fs ft rt rest_eq sigma + else if r_6 fs ft rt then + (try + apply_r6 fs ft rt rest_eq sigma + with Not_unifiable -> + if r_7 fs ft rt then (* r7 applicable if r6 was and tr6 = C2t' *) + (try + apply_r7 fs ft rt rest_eq sigma + with Not_unifiable -> + apply_r10 fs ft rt rest_eq sigma (* r10 always applicable if r6 was *) + ) + else + (* r10 could be represented only once if we would try it before r7.*) + (* but looking at the transformation rules, r10 should be tried at last in any case *) + apply_r10 fs ft rt rest_eq sigma (* r10 always applicable r6 was *) + ) + else if r_7 fs ft rt then (* not r6 and r7 possible if z <> [] *) + (try + apply_r7 fs ft rt rest_eq sigma + with Not_unifiable -> + apply_r10 fs ft rt rest_eq sigma (* r10 always applicable if r7 was *) + ) + else if r_8 fs ft rt then + (try + apply_r8 fs ft rt rest_eq sigma + with Not_unifiable -> + if r_10 fs ft rt then (* r10 applicable if r8 was and tr8 <> [] *) + apply_r10 fs ft rt rest_eq sigma + else + raise Not_unifiable (* simply back propagation *) + ) + else if r_9 fs ft rt then + (try + apply_r9 fs ft rt rest_eq sigma + with Not_unifiable -> + if r_10 fs ft rt then (* r10 applicable if r9 was and tr9 <> [] *) + apply_r10 fs ft rt rest_eq sigma + else + raise Not_unifiable (* simply back propagation *) + ) + else if r_10 fs ft rt then (* not ri, i<10, and r10 possible if for instance *) + (* (s=[] and x=v1) or (z<>[] and xt=C1V1t') *) + apply_r10 fs ft rt rest_eq sigma + else (* NO rule applicable *) + raise Not_unifiable + in + match eqlist with + [] -> + init_sigma + | f::rest_eq -> + let (atomnames,(fs,ft)) = f in + tunify atomnames fs [] ft rest_eq init_sigma + +let rec test_apply_eq atomnames eqs eqt subst = + match subst with + [] -> (eqs,eqt) + | (f,flist)::r -> + let (first_appl_eqs,first_appl_eqt) = + if List.mem f atomnames then + (eqs,eqt) + else + (apply_element eqs eqt (f,flist)) + in + test_apply_eq atomnames first_appl_eqs first_appl_eqt r + +let rec test_apply_eqsubst eqlist subst = + match eqlist with + [] -> [] + | f::r -> + let (atomnames,(eqs,eqt)) = f in + let applied_element = test_apply_eq atomnames eqs eqt subst in + (atomnames,applied_element)::(test_apply_eqsubst r subst) + +let ttest us ut ns nt eqlist orderingQ atom_rel = + let (short_us,short_ut) = shorten us ut in (* apply intial rule R3 *) + (* to eliminate common beginning *) + let new_element = ([ns;nt],(short_us,short_ut)) in + let full_eqlist = + if List.mem new_element eqlist then + eqlist + else + new_element::eqlist + in + let sigma = tunify_list full_eqlist (1,[]) in + let (n,subst) = sigma in + let test_apply = test_apply_eqsubst full_eqlist subst in + begin + print_endline ""; + print_endline "Final equations:"; + print_equations full_eqlist; + print_endline ""; + print_endline "Final substitution:"; + print_tunify sigma; + print_endline ""; + print_endline "Applied equations:"; + print_equations test_apply + end + +let do_stringunify us ut ns nt equations = + let (short_us,short_ut) = shorten us ut in (* apply intial rule R3 to eliminate common beginning *) + let new_element = ([ns;nt],(short_us,short_ut)) in + let full_eqlist = + if List.mem new_element equations then + equations + else + new_element::equations + in +(* print_equations full_eqlist; *) + (try + let new_sigma = tunify_list full_eqlist (1,[]) in + (new_sigma,(1,full_eqlist)) + with Not_unifiable -> + raise Failed (* new connection please *) + ) + + +(* type of one unifier: int * (string * string) list *) diff --git a/contrib/jprover/jtunify.mli b/contrib/jprover/jtunify.mli new file mode 100644 index 00000000..0aabc79e --- /dev/null +++ b/contrib/jprover/jtunify.mli @@ -0,0 +1,35 @@ +exception Not_unifiable +exception Failed + +(* Utilities *) + +val is_const : string -> bool +val is_var : string -> bool +val r_1 : 'a list -> 'b list -> 'c list -> bool +val r_2 : 'a list -> 'b list -> 'c list -> bool +val r_3 : 'a list -> 'b list -> 'a list -> bool +val r_4 : string list -> 'a list -> string list -> bool +val r_5 : string list -> 'a -> 'b list -> bool +val r_6 : string list -> 'a list -> string list -> bool +val r_7 : string list -> 'a -> string list -> bool +val r_8 : string list -> 'a list -> string list -> bool +val r_9 : string list -> 'a list -> string list -> bool +val r_10 : string list -> 'a -> string list -> bool +val com_subst : 'a list -> 'a * 'a list -> 'a list + +(* Debugging *) + +val print_equations : (string list * (string list * string list)) list -> unit + +val print_tunify : int * (string * string list) list -> unit + +(* Main function *) + +val do_stringunify : string list -> + string list -> + string -> + string -> + (string list * (string list * string list)) list -> + (int * (string * string list) list) * (* unifier *) + (int * ((string list * (string list * string list)) list)) (* applied new eqlist *) + diff --git a/contrib/jprover/opname.ml b/contrib/jprover/opname.ml new file mode 100644 index 00000000..d0aa9046 --- /dev/null +++ b/contrib/jprover/opname.ml @@ -0,0 +1,90 @@ +open Printf + +type token = string +type atom = string list + +let opname_token = String.make 4 (Char.chr 0) + +type opname = + { mutable opname_token : token; + mutable opname_name : string list + } + +let (optable : (string list, opname) Hashtbl.t) = Hashtbl.create 97 + +(* * Constructors.*) +let nil_opname = { opname_token = opname_token; opname_name = [] } + +let _ = Hashtbl.add optable [] nil_opname + +let rec mk_opname s ({ opname_token = token; opname_name = name } as opname) = + if token == opname_token then + let name = s :: name in + try Hashtbl.find optable name with + Not_found -> + let op = { opname_token = opname_token; opname_name = name } in + Hashtbl.add optable name op; + op + else + mk_opname s (normalize_opname opname) + +and make_opname = function + | [] -> + nil_opname + | h :: t -> + mk_opname h (make_opname t) + +and normalize_opname opname = + if opname.opname_token == opname_token then + (* This opname is already normalized *) + opname + else + let res = make_opname opname.opname_name + in + opname.opname_name <- res.opname_name; + opname.opname_token <- opname_token; + res + +(* * Atoms are the inner string list. *) +let intern opname = + if opname.opname_token == opname_token then + opname.opname_name + else + let name = (normalize_opname opname).opname_name in + opname.opname_token <- opname_token; + opname.opname_name <- name; + name + +let eq_inner op1 op2 = + op1.opname_name <- (normalize_opname op1).opname_name; + op1.opname_token <- opname_token; + op2.opname_name <- (normalize_opname op2).opname_name; + op2.opname_token <- opname_token; + op1.opname_name == op2.opname_name + +let eq op1 op2 = + (op1.opname_name == op2.opname_name) + or ((op1.opname_token != opname_token or op2.opname_token != opname_token) & eq_inner op1 op2) + +(* * Destructor. *) +let dst_opname = function + | { opname_name = n :: name } -> n, { opname_token = opname_token; opname_name = name } + | _ -> raise (Invalid_argument "dst_opname") + +let dest_opname { opname_name = name } = + name + +let string_of_opname op = + let rec flatten = function + | [] -> + "" + | h::t -> + let rec collect s = function + | h::t -> + collect (h ^ "!" ^ s) t + | [] -> + s + in + collect h t + in + flatten op.opname_name diff --git a/contrib/jprover/opname.mli b/contrib/jprover/opname.mli new file mode 100644 index 00000000..56bf84e2 --- /dev/null +++ b/contrib/jprover/opname.mli @@ -0,0 +1,15 @@ +(* This module is extracted from Meta-Prl. *) + +type token = string +and atom = string list +val opname_token : token +type opname = { + mutable opname_token : token; + mutable opname_name : string list; +} +val nil_opname : opname +val mk_opname : string -> opname -> opname +val make_opname : string list -> opname +val eq : opname -> opname -> bool +val dest_opname : opname -> string list +val string_of_opname : opname -> string -- cgit v1.2.3