|
@@ -6,15 +6,12 @@ import java.io.PrintStream;
|
|
|
import java.util.*;
|
|
|
import java.util.function.Function;
|
|
|
import java.util.function.Predicate;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
public class Tree {
|
|
|
Node root;
|
|
|
|
|
|
- public Tree(Formula formulaToProve) {
|
|
|
- var f = new Formula.Not(formulaToProve);
|
|
|
-
|
|
|
- root = (new Node(null, f));
|
|
|
- }
|
|
|
+ public LinkedHashMap<Unifier.UV.Zmienna, Unifier.Unifiable> successfullUnif;
|
|
|
|
|
|
public Optional<Node> findNode(Predicate<Node> additionalCnd) {
|
|
|
return fon(root, additionalCnd);
|
|
@@ -32,6 +29,44 @@ public class Tree {
|
|
|
}
|
|
|
|
|
|
private boolean expanded = false;
|
|
|
+ boolean unifiedNything = false;
|
|
|
+
|
|
|
+ public Tree(Formula formulaToProve) {
|
|
|
+ var f = new Formula.Not(formulaToProve);
|
|
|
+
|
|
|
+ root = (Node.root(f));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static LinkedHashMap<Term.Variable, Term> podmien(LinkedHashMap<Unifier.UV.Zmienna, Unifier.Unifiable> successfullUnif) {
|
|
|
+ LinkedHashMap<Term.Variable, Term> subst = new LinkedHashMap<>();
|
|
|
+ for (Unifier.UV.Zmienna uz : successfullUnif.keySet()) {
|
|
|
+ var uv = successfullUnif.get(uz);
|
|
|
+ subst.put(uz.v(), Unifier.toTerm(uv));
|
|
|
+ }
|
|
|
+ return subst;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Formula swapF(LinkedHashMap<Term.Variable, Term> subst, Formula f) {
|
|
|
+ var trzymak = new Trzymak<>(f);
|
|
|
+
|
|
|
+ subst.forEach((a, b) -> trzymak.zapisz(FormulaUtil.swap(trzymak.wez(), a, b)));
|
|
|
+ return trzymak.wez();
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<Node> findTips() {
|
|
|
+ var r = new ArrayList<Node>();
|
|
|
+ ft(r, root);
|
|
|
+ return r;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ft(List<Node> r, Node n) {
|
|
|
+ if (n.getChildren().isEmpty()) r.add(n);
|
|
|
+ else {
|
|
|
+ for (Node child : n.getChildren()) {
|
|
|
+ ft(r, child);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
private boolean unexpandForalls() {
|
|
|
|
|
@@ -43,108 +78,251 @@ public class Tree {
|
|
|
var chng = false;
|
|
|
while (n.isPresent()) {
|
|
|
chng = true;
|
|
|
- n.get().mark=true;
|
|
|
- n.get().expanded=false;
|
|
|
+ n.get().mark = true;
|
|
|
+ n.get().expanded = false;
|
|
|
n = findNode(isForallNotMarked);
|
|
|
}
|
|
|
|
|
|
n = findNode(isForallMarked);
|
|
|
while (n.isPresent()) {
|
|
|
- n.get().mark=false;
|
|
|
+ n.get().mark = false;
|
|
|
n = findNode(isForallMarked);
|
|
|
}
|
|
|
return chng;
|
|
|
}
|
|
|
|
|
|
+ private void unmarkNonUnify() {
|
|
|
+
|
|
|
+ Predicate<Node> isNotMarked = nde -> !nde.mark;
|
|
|
+ Predicate<Node> isMarked = nde -> nde.mark;
|
|
|
+ var n = findNode(isNotMarked);
|
|
|
+ while (n.isPresent()) {
|
|
|
+ n.get().mark = true;
|
|
|
+ var nn = n.get();
|
|
|
+ nn.revertToOrig();
|
|
|
+ n = findNode(isNotMarked);
|
|
|
+ }
|
|
|
+
|
|
|
+ n = findNode(isMarked);
|
|
|
+ while (n.isPresent()) {
|
|
|
+ n.get().mark = false;
|
|
|
+ n = findNode(isMarked);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
public void expand() {
|
|
|
if (expanded) return;
|
|
|
expanded = true;
|
|
|
|
|
|
- Predicate<Node> isForall = nde -> nde.formula instanceof Formula.Forall;
|
|
|
- Predicate<Node> nonExpandedNotForall = nde -> nde.notExpanded() && Predicate.not(isForall).test(nde);
|
|
|
- Predicate<Node> isForallNotExpanded = nde -> nde.notExpanded() && (isForall).test(nde);
|
|
|
|
|
|
Optional<Node> n;
|
|
|
boolean chng;
|
|
|
+
|
|
|
do {
|
|
|
chng = false;
|
|
|
- n = findNode(nonExpandedNotForall);
|
|
|
- while (n.isPresent()) {
|
|
|
- n.get().expand();
|
|
|
- chng = true;
|
|
|
- n = findNode(nonExpandedNotForall);
|
|
|
- }
|
|
|
+ for (RuleType type : RuleType.values()) {
|
|
|
+
|
|
|
+ Predicate<Node> nonExpanded = Node::notExpanded;
|
|
|
+ Predicate<Node> ofType = ndd -> RuleType.ofNode(ndd) == type;
|
|
|
+
|
|
|
+ Predicate<Node> thePred = ndd -> nonExpanded.test(ndd) && ofType.test(ndd);
|
|
|
|
|
|
- n = findNode(isForallNotExpanded);
|
|
|
- while (n.isPresent()) {
|
|
|
- chng = true;
|
|
|
- n.get().expand(); // pwt
|
|
|
- n = findNode(isForallNotExpanded);
|
|
|
+ n = findNode(thePred);
|
|
|
+ while (n.isPresent()) {
|
|
|
+ n.get().expand();
|
|
|
+ chng = true;
|
|
|
+ n = findNode(thePred);
|
|
|
+ }
|
|
|
}
|
|
|
} while (chng);
|
|
|
|
|
|
+
|
|
|
}
|
|
|
|
|
|
+ public boolean isOk(int searchBound) {
|
|
|
+ for (int i = 0; searchBound < 0 || i < searchBound; i++) {
|
|
|
+ expand();
|
|
|
+ List<Node> tips = findTips();
|
|
|
+ var solutionsForEachbranch = new ArrayList<List<Pair>>();
|
|
|
+ for (Node tip : tips) {
|
|
|
+ solutionsForEachbranch.add(genPossilbeSolutions(tip));
|
|
|
+
|
|
|
+ // 1. generate possible unif. solutions for each open branch
|
|
|
+ // 2. find non-clasing solutions
|
|
|
+//
|
|
|
|
|
|
- public List<Node> findTips() {
|
|
|
- var r = new ArrayList<Node>();
|
|
|
- ft(r, root);
|
|
|
- return r;
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- private void ft(List<Node> r, Node n) {
|
|
|
- if (n.getChildren().isEmpty()) r.add(n);
|
|
|
- else {
|
|
|
- for (Node child : n.getChildren()) {
|
|
|
- ft(r, child);
|
|
|
+ var filtered = new ArrayList<List<Pair>>();
|
|
|
+ var ok = true;
|
|
|
+ for (List<Pair> branch : solutionsForEachbranch) {
|
|
|
+ // check if we're doomed - no solutions even with unconstrained unif
|
|
|
+ if (branch.isEmpty()) {
|
|
|
+ ok = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // remove branches solved without unif - they won't clash
|
|
|
+// if (branch.stream().anyMatch(Map::isEmpty)) continue;
|
|
|
+ filtered.add(branch);
|
|
|
+ }
|
|
|
+ if (ok) {
|
|
|
+ ok = solveConstraints2(filtered);
|
|
|
}
|
|
|
+ if (ok) {
|
|
|
+ if (Main.DEBUG) print();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ var warto = unexpandForalls();
|
|
|
+ if (warto) {
|
|
|
+ if (i + 1 < searchBound) System.out.println("Trying another round of `forall` expansion");
|
|
|
+ unmarkNonUnify();
|
|
|
+ } else return false;// no point in expanding
|
|
|
}
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
- public boolean isOk(int searchBound) {
|
|
|
- main:
|
|
|
- for (int i = 0; searchBound<0 || i < searchBound; i++) {
|
|
|
- expand();
|
|
|
+
|
|
|
+ // return true if solution ok exists
|
|
|
+ private boolean solveConstraints2(ArrayList<List<Pair>> candidates) {
|
|
|
+ if (candidates.isEmpty()) {
|
|
|
for (Node tip : findTips()) {
|
|
|
- var ok = close(tip);
|
|
|
- tip.cls=ok;
|
|
|
- if (!ok) {
|
|
|
- var warto = unexpandForalls();
|
|
|
- if (warto) {
|
|
|
-// System.out.println("Trying another round of `forall` expansion");
|
|
|
- continue main;
|
|
|
- }
|
|
|
- else break main;
|
|
|
+ var closed = close(tip, false);
|
|
|
+ if (!closed) {
|
|
|
+ System.out.println("to się nie powinno dziać, ale cóœ zrobisz");
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
+ var myPart = candidates.get(0);
|
|
|
+ var rest = candidates.subList(1, candidates.size());
|
|
|
+
|
|
|
+ for (Pair candidate : myPart) {
|
|
|
+ // try unif
|
|
|
+ var ca = Unifier.fromPred(candidate.a());
|
|
|
+ var cb = Unifier.fromPred(candidate.b());
|
|
|
+ var reso = Unifier.unify(ca, cb);
|
|
|
+ if (reso.isEmpty()) continue; //rodo chng
|
|
|
+ var res = reso.get();
|
|
|
+ // apply unif to tree
|
|
|
+ // first make a copy for bkup
|
|
|
+ var origRoot = new HashMap<Node.NodeId, Formula>();
|
|
|
+ backupFormulas(root, origRoot);
|
|
|
+ propChang(res);
|
|
|
+ // apply unif to remaining candidates(copy?!)
|
|
|
+ var newRest = new ArrayList<List<Pair>>();
|
|
|
+ var pp = podmien(res);
|
|
|
+ for (List<Pair> rr : rest) {
|
|
|
+ var nn = rr.stream().map(pr -> {
|
|
|
+ var na = (Formula.Predicate) swapF(pp, pr.a());
|
|
|
+ var nb = (Formula.Predicate) swapF(pp, pr.b());
|
|
|
+ return new Pair(na, nb);
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ newRest.add(nn);
|
|
|
+ }
|
|
|
+ // go for rest
|
|
|
+ var ok = solveConstraints2(newRest);
|
|
|
+ if (ok) return true;
|
|
|
+ // revert changes (how?)
|
|
|
+ // so, rest stays rest
|
|
|
+ // revert tree changes
|
|
|
+ revert(root, origRoot);
|
|
|
+ }
|
|
|
+ // unif not found :(
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- private boolean close(Node tip) {
|
|
|
+ private void backupFormulas(Node node, Map<Node.NodeId, Formula> bkMap) {
|
|
|
+ bkMap.put(node.getId(), node.formula);
|
|
|
+ for (Node child : node.getChildren()) {
|
|
|
+ backupFormulas(child, bkMap);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void revert(Node node, Map<Node.NodeId, Formula> bkMap) {
|
|
|
+ node.formula = bkMap.getOrDefault(node.getId(), node.formula);
|
|
|
+ for (Node child : node.getChildren()) {
|
|
|
+ revert(child, bkMap);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ private List<Pair> genPossilbeSolutions(Node tip) {
|
|
|
+ var solutions = new ArrayList<Pair>();
|
|
|
for (Node candidate = tip; candidate != null; candidate = candidate.getParent().orElse(null)) {
|
|
|
- var candidateFormula = candidate.formula.simplify();
|
|
|
+ var candidateFormula = candidate.formula;//.simplify();
|
|
|
if (candidateFormula instanceof Formula.Predicate pred) {
|
|
|
// look for neg!
|
|
|
for (Node othr = tip; othr != null; othr = othr.parent) {
|
|
|
- var otf = othr.formula.simplify();
|
|
|
+ var otf = othr.formula;//.simplify();
|
|
|
if (otf instanceof Formula.Not on) {
|
|
|
- if (on.simplify() instanceof Formula.Not onn) {
|
|
|
+ if (on/*.simplify() */ instanceof Formula.Not onn) {
|
|
|
var possiblyo = onn.f();
|
|
|
if (possiblyo instanceof Formula.Predicate op) {
|
|
|
var a = Unifier.fromPred(pred);
|
|
|
var b = Unifier.fromPred(op);
|
|
|
var res = Unifier.unify(a, b);
|
|
|
if (res.isPresent()) {
|
|
|
- // uwaga kolejność iteracji ważna!!!
|
|
|
- Map<Term.Variable, Term> resq = LinkedHashMap.newLinkedHashMap(res.get().size());
|
|
|
+ solutions.add(new Pair(pred, op));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ return solutions;
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean close(Node tip, boolean allowUnif) {
|
|
|
+ for (Node candidate = tip; candidate != null; candidate = candidate.getParent().orElse(null)) {
|
|
|
+ var candidateFormula = candidate.formula;//.simplify();
|
|
|
+ if (candidateFormula instanceof Formula.Predicate pred) {
|
|
|
+ // look for neg!
|
|
|
+ for (Node othr = tip; othr != null; othr = othr.parent) {
|
|
|
+
|
|
|
+ var otf = othr.formula;//.simplify();
|
|
|
+ if (otf instanceof Formula.Not on) {
|
|
|
+ if (on/*.simplify() */ instanceof Formula.Not onn) {
|
|
|
+ var possiblyo = onn.f();
|
|
|
+ if (possiblyo instanceof Formula.Predicate op) {
|
|
|
+// if (othr.dontUnifyWit.contains(candidate.getId())) {
|
|
|
+//// System.out.println("no co ty nie bd się z tobą unifikować "+candidateFormula +" " +othr.formula);
|
|
|
+// continue;
|
|
|
+// }
|
|
|
+ var a = Unifier.fromPred(pred);
|
|
|
+ var b = Unifier.fromPred(op);
|
|
|
+ var res = Unifier.unify(a, b);
|
|
|
+ if (res.isPresent()) {
|
|
|
+ LinkedHashMap<Term.Variable, Term> resq = LinkedHashMap.newLinkedHashMap(res.get().size());
|
|
|
res.get().forEach((Unifier.UV.Zmienna aq, Unifier.Unifiable bq) ->
|
|
|
resq.put(aq.v(), Unifier.toTerm(bq))
|
|
|
);
|
|
|
-
|
|
|
-
|
|
|
- propagateChanges(resq);
|
|
|
+ boolean harmlessUnif = res.get().isEmpty();
|
|
|
+ if (!harmlessUnif) {
|
|
|
+ if (!allowUnif) {
|
|
|
+ throw new IllegalArgumentException();
|
|
|
+ }
|
|
|
+ unifiedNything = true;
|
|
|
+ propagateChanges(resq);
|
|
|
+ } else {
|
|
|
+ if (Main.DEBUG) {
|
|
|
+ System.out.printf("No i chyba git [%s,%s] %s %s%n",
|
|
|
+ candidate.getId(),
|
|
|
+ othr.getId(),
|
|
|
+ candidate.formula,
|
|
|
+ othr.formula
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ tip.closeBy(candidate);
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
@@ -158,30 +336,39 @@ public class Tree {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- private void propagateChanges(Map<Term.Variable, Term> subst) {
|
|
|
+ private void propChang(LinkedHashMap<Unifier.UV.Zmienna, Unifier.Unifiable> successfullUnif) {
|
|
|
|
|
|
- Function<Formula, Formula> swp = f -> {
|
|
|
- var trzymak = new Trzymak<>(f);
|
|
|
- // wygląda obejszczenie, ale kolejność ważna!
|
|
|
- /*
|
|
|
- przykład
|
|
|
- Map(X-> d, Y->X)
|
|
|
- X ^ Y -> d ^ Y -> d ^ X
|
|
|
- Map(Y->X, X->d)
|
|
|
- X ^ Y -> X ^ X -> d ^ d
|
|
|
+ propagateChanges(podmien(successfullUnif));
|
|
|
+ }
|
|
|
|
|
|
- */
|
|
|
+ private void propagateChanges(LinkedHashMap<Term.Variable, Term> subst) {
|
|
|
|
|
|
- subst.forEach((a, b) -> trzymak.zapisz(FormulaUtil.swap(trzymak.wez(), a, b)));
|
|
|
- return trzymak.wez();
|
|
|
- };
|
|
|
+ Function<Formula, Formula> swp = f -> swapF(subst, f);
|
|
|
|
|
|
propC(root, swp);
|
|
|
}
|
|
|
|
|
|
- private void propC(Node root, Function<Formula, Formula> swp) {
|
|
|
- root.formula = swp.apply(root.formula);
|
|
|
- root.children.forEach(a -> propC(a, swp));
|
|
|
+ private void propC(Node nde, Function<Formula, Formula> swp) {
|
|
|
+ nde.formula = swp.apply(nde.formula);
|
|
|
+ nde.children.forEach(a -> propC(a, swp));
|
|
|
+ }
|
|
|
+
|
|
|
+ private void print(PrintStream out, Node n, int ident) {
|
|
|
+ var s = " ";
|
|
|
+ if (n.isTip()) {
|
|
|
+ s = (n.cls ? "XX" : "OO");
|
|
|
+ }
|
|
|
+
|
|
|
+ var ai = (n.closedBy == null ? "" : " {" + n.closedBy.getId() + "}");
|
|
|
+
|
|
|
+ for (int i = 0; i < ident; i++) out.print(s);
|
|
|
+ out.println("|" + n.formula + " " + n.getId() + " [" + n.getOriginator().map(Node::getId).orElse(n.getId()) + "]" + ai);
|
|
|
+ ////
|
|
|
+
|
|
|
+ for (Node child : n.children) {
|
|
|
+ print(out, child, ident + 1);
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|
|
@@ -193,19 +380,20 @@ public class Tree {
|
|
|
print(out, root, 0);
|
|
|
}
|
|
|
|
|
|
- private void print(PrintStream out, Node n, int ident) {
|
|
|
- var s = " ";
|
|
|
- if(n.isTip()){
|
|
|
- s=(n.cls ? "XX":"OO");
|
|
|
- }
|
|
|
- for (int i = 0; i < ident; i++) out.print(s);
|
|
|
- out.println( "|"+ n.formula );
|
|
|
- ////
|
|
|
+ public Node ofId(Node.NodeId id) {
|
|
|
+ return ofIdInt(id, root);
|
|
|
+ }
|
|
|
|
|
|
- for (Node child : n.children) {
|
|
|
- print(out, child, ident + 1);
|
|
|
+ private Node ofIdInt(Node.NodeId id, Node root) {
|
|
|
+ if (root.getId().equals(id)) return root;
|
|
|
+ for (Node child : root.getChildren()) {
|
|
|
+ var r = ofIdInt(id, child);
|
|
|
+ if (r != null) return r;
|
|
|
}
|
|
|
+ return null;
|
|
|
+ }
|
|
|
|
|
|
+ record Pair(Formula.Predicate a, Formula.Predicate b) {
|
|
|
}
|
|
|
|
|
|
}
|