From 2d5e626fd4a597f95cd6ef08b736abe3bce31d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Wed, 3 Sep 2025 17:11:49 +0200 Subject: [PATCH 01/31] classification tree and slct implementation --- .../learnlib/ralib/ct/CTAutomatonBuilder.java | 299 ++++++++++ .../java/de/learnlib/ralib/ct/CTBranch.java | 56 ++ .../de/learnlib/ralib/ct/CTHypothesis.java | 46 ++ .../de/learnlib/ralib/ct/CTInnerNode.java | 154 +++++ .../java/de/learnlib/ralib/ct/CTLeaf.java | 158 +++++ .../java/de/learnlib/ralib/ct/CTNode.java | 25 + .../java/de/learnlib/ralib/ct/CTPath.java | 148 +++++ .../learnlib/ralib/ct/ClassificationTree.java | 548 ++++++++++++++++++ .../de/learnlib/ralib/ct/MemorableSet.java | 18 + .../java/de/learnlib/ralib/ct/Prefix.java | 212 +++++++ .../de/learnlib/ralib/ct/ShortPrefix.java | 57 ++ .../learnlib/ralib/data/util/DataUtils.java | 38 ++ .../learning/ralambda/LeafComponent.java | 89 +++ .../ralib/learning/ralambda/SLCT.java | 188 ++++++ .../learnlib/ralib/ct/CTConsistencyTest.java | 391 +++++++++++++ .../java/de/learnlib/ralib/ct/CTTest.java | 364 ++++++++++++ 16 files changed, 2791 insertions(+) create mode 100644 src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java create mode 100644 src/main/java/de/learnlib/ralib/ct/CTBranch.java create mode 100644 src/main/java/de/learnlib/ralib/ct/CTHypothesis.java create mode 100644 src/main/java/de/learnlib/ralib/ct/CTInnerNode.java create mode 100644 src/main/java/de/learnlib/ralib/ct/CTLeaf.java create mode 100644 src/main/java/de/learnlib/ralib/ct/CTNode.java create mode 100644 src/main/java/de/learnlib/ralib/ct/CTPath.java create mode 100644 src/main/java/de/learnlib/ralib/ct/ClassificationTree.java create mode 100644 src/main/java/de/learnlib/ralib/ct/MemorableSet.java create mode 100644 src/main/java/de/learnlib/ralib/ct/Prefix.java create mode 100644 src/main/java/de/learnlib/ralib/ct/ShortPrefix.java create mode 100644 src/main/java/de/learnlib/ralib/data/util/DataUtils.java create mode 100644 src/main/java/de/learnlib/ralib/learning/ralambda/LeafComponent.java create mode 100644 src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java create mode 100644 src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java create mode 100644 src/test/java/de/learnlib/ralib/ct/CTTest.java diff --git a/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java new file mode 100644 index 00000000..92ce51b7 --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java @@ -0,0 +1,299 @@ +package de.learnlib.ralib.ct; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import de.learnlib.logging.Category; +import de.learnlib.ralib.automata.Assignment; +import de.learnlib.ralib.automata.RALocation; +import de.learnlib.ralib.automata.Transition; +import de.learnlib.ralib.automata.output.OutputMapping; +import de.learnlib.ralib.automata.output.OutputTransition; +import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.data.Constants; +import de.learnlib.ralib.data.DataType; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.RegisterAssignment; +import de.learnlib.ralib.data.SymbolicDataValue; +import de.learnlib.ralib.data.SymbolicDataValue.Parameter; +import de.learnlib.ralib.data.SymbolicDataValue.Register; +import de.learnlib.ralib.data.VarMapping; +import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; +import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.RegisterGenerator; +import de.learnlib.ralib.learning.AutomatonBuilder; +import de.learnlib.ralib.learning.Hypothesis; +import de.learnlib.ralib.learning.rastar.RaStar; +import de.learnlib.ralib.oracles.Branching; +import de.learnlib.ralib.smt.ReplacingValuesVisitor; +import de.learnlib.ralib.smt.SMTUtil; +import de.learnlib.ralib.words.DataWords; +import de.learnlib.ralib.words.OutputSymbol; +import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import gov.nasa.jpf.constraints.api.Expression; +import gov.nasa.jpf.constraints.expressions.NumericBooleanExpression; +import gov.nasa.jpf.constraints.expressions.NumericComparator; +import gov.nasa.jpf.constraints.expressions.PropositionalCompound; +import gov.nasa.jpf.constraints.util.ExpressionUtil; +import net.automatalib.word.Word; + +public class CTAutomatonBuilder { + + private final ClassificationTree ct; + + private final Map, RALocation> locations; + private final Map leaves; +// private final Map, Bijection> rpRenamings; + +// private final Set> visitedTransitions; + + private final CTHypothesis hyp; + +// private final Constants consts; + + private boolean ioMode; + + public CTAutomatonBuilder(ClassificationTree ct, Constants consts, boolean ioMode) { + this.ct = ct; +// this.consts = consts; + this.ioMode = ioMode; + + locations = new LinkedHashMap<>(); + leaves = new LinkedHashMap<>(); +// rpRenamings = new LinkedHashMap<>(); +// visitedTransitions = new LinkedHashSet<>(); + hyp = new CTHypothesis(consts, ct.getLeaves().size()); + } + + public Hypothesis buildHypothesis() { + computeLocations(); + computeTransitions(); + hyp.putLeaves(leaves); + return hyp; + } + + private void computeLocations() { + CTLeaf initial = ct.getLeaf(RaStar.EMPTY_PREFIX); + RALocation l0 = hyp.addInitialState(initial.isAccepting()); + locations.put(RaStar.EMPTY_PREFIX, l0); + hyp.setAccessSequence(l0, RaStar.EMPTY_PREFIX); +// rpRenamings.put(RaStar.EMPTY_PREFIX, new Bijection()); + leaves.put(initial, l0); + + for (CTLeaf leaf : ct.getLeaves()) { + if (leaf != initial) { + RALocation l = hyp.addState(leaf.isAccepting()); + hyp.setAccessSequence(l, leaf.getRepresentativePrefix()); +// locations.put(leaf.getRepresentativePrefix(), l); + for (Word sp : leaf.getShortPrefixes()) { + locations.put(sp, l); + } + leaves.put(leaf, l); + } + } + } + + private void computeTransitions() { + for (CTLeaf leaf : ct.getLeaves()) { +// computeTransition(leaf, leaf.getRepresentativePrefix()); + for (Prefix prefix : leaf.getPrefixes()) { + computeTransition(leaf, prefix); + } + } + } + + private void computeTransition(CTLeaf dest_l, Prefix prefix) { +// if (visitedTransitions.contains(prefix)) { +// return; +// } + + if (prefix.length() < 1) { + return; + } + +// Word dest_id = prefix; + Prefix dest_rp = dest_l.getRepresentativePrefix(); + Word src_id = prefix.prefix(prefix.length() - 1); + CTLeaf src_l = ct.getLeaf(src_id); + + assert src_l != null : "Source prefix not present in classification tree: " + src_id; + assert src_l.getPrefix(src_id) instanceof ShortPrefix : "Source prefix is not short: " + src_id; + assert dest_rp instanceof ShortPrefix : "Representative prefix is not short: " + dest_rp; + + RALocation src_loc = locations.get(src_id); + RALocation dest_loc = locations.get(dest_rp); + + ParameterizedSymbol action = prefix.lastSymbol().getBaseSymbol(); + + assert src_l.getRepresentativePrefix() instanceof ShortPrefix : "Representative prefix is not a short prefix: " + src_l; + + Prefix src_prefix = src_l.getPrefix(src_id); + ShortPrefix src_u = (ShortPrefix)(src_prefix instanceof ShortPrefix ? + src_prefix : + src_l.getRepresentativePrefix()); + + // guard + Branching b = src_u.getBranching(action); + Expression guard = b.getBranches().get(prefix); + + assert guard != null : "No guard for prefix " + prefix; + + ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); + guard = rvv.apply(guard, src_u.getAssignment()); + + RegisterAssignment srcAssign = src_u.getAssignment(); + RegisterAssignment destAssign = dest_rp.getAssignment(); + Bijection remapping = prefix.getRpBijection(); + Assignment assign = AutomatonBuilder.computeAssignment(prefix, srcAssign, destAssign, remapping); + + Transition t = createTransition(action, guard, src_loc, dest_loc, assign); + if (t != null) { + hyp.addTransition(src_loc, action, t); + hyp.setTransitionSequence(t, prefix); + } +// +// Word src_rp = src_l.getRepresentativePrefix(); +// Bijection src_renaming = rpRenamings.get(src_rp); +// if (src_renaming == null) { +// computeTransition(src_l, src_l.getRepresentativePrefix()); +// src_renaming = rpRenamings.get(src_rp); +// } +// +// int max = DataWords.paramValLength(src_id); +// List regs = new ArrayList<>(prefix.getRegisters()); +// regs.sort((r1, r2) -> Integer.compare(r1.getId(), r2.getId())); +// RegisterGenerator rgen = new RegisterGenerator(); +// +// Map mapping = new LinkedHashMap<>(); +// +// Bijection dest_renaming; +// if (prefix == dest_l.getRepresentativePrefix()) { +// // case 1 : prefix is the rp +// dest_renaming = new Bijection(); +// for (Register r : regs) { +// Register reg = rgen.next(r.getDataType()); +// dest_renaming.put(r, reg); +// if (r.getId() > max) { +// Parameter p = new Parameter(r.getDataType(), r.getId() - max); +// mapping.put(reg, p); +// } else { +// Register p = src_renaming.get(r); +// assert p != null : "Register not memorable in source location: " + r; +// mapping.put(reg, p); +// } +// } +// rpRenamings.put(prefix, dest_renaming); +// } else { +// // case 2 : prefix is not the rp +//// Word dest_rp = dest_l.getRepresentativePrefix().getPrefix(); +// Bijection rp_renaming = rpRenamings.get(dest_rp); +// assert rp_renaming != null : "No rp mapping: " + dest_rp; +// dest_renaming = prefix.getRpBijection().compose(rp_renaming); +// for (Register r : regs) { +// Register reg = dest_renaming.get(r); +// assert reg != null : "Register not compatible with rp: " + r; +// if (r.getId() > max) { +// Parameter p = new Parameter(r.getDataType(), r.getId() - max); +// mapping.put(reg, p); +// } else { +// Register src_r = src_renaming.get(r); +// assert src_r != null : "Register not memorable in source location: " + r; +// mapping.put(reg, src_r); +// } +// } +// } +// +// VarMapping vars = new VarMapping<>(); +// vars.putAll(mapping); +// Assignment assignment = new Assignment(vars); +// +// VarMapping guardRenaming = new VarMapping<>(); +// guardRenaming.putAll(src_renaming); +// Expression guardRenamed = SMTUtil.renameVars(guard, guardRenaming); +// +// Transition transition = createTransition(action, guardRenamed, src_loc, dest_loc, assignment); +// if (transition != null) { +// hyp.addTransition(src_loc, action, transition); +// hyp.setTransitionSequence(transition, dest_id); +// } +// +// visitedTransitions.add(dest_id); + } + + private Transition createTransition(ParameterizedSymbol action, Expression guard, + RALocation src_loc, RALocation dest_loc, Assignment assignment) { + if (ioMode && !dest_loc.isAccepting()) { + return null; + } + + if (!ioMode || !(action instanceof OutputSymbol)) { + return new Transition(action, guard, src_loc, dest_loc, assignment); + } + + //IfGuard _guard = (IfGuard) guard; + Expression expr = guard; + + VarMapping outmap = new VarMapping<>(); + analyzeExpression(expr, outmap); + + Set fresh = new LinkedHashSet<>(); + ParameterGenerator pgen = new ParameterGenerator(); + for (DataType t : action.getPtypes()) { + Parameter p = pgen.next(t); + if (!outmap.containsKey(p)) { + fresh.add(p); + } + } + + OutputMapping outMap = new OutputMapping(fresh, outmap); + + return new OutputTransition(ExpressionUtil.TRUE, + outMap, (OutputSymbol) action, src_loc, dest_loc, assignment); + } + + + private void analyzeExpression(Expression expr, + VarMapping outmap) { + + if (expr instanceof PropositionalCompound pc) { + analyzeExpression(pc.getLeft(), outmap); + analyzeExpression(pc.getRight(), outmap); + } + else if (expr instanceof NumericBooleanExpression nbe) { + if (nbe.getComparator() == NumericComparator.EQ) { + // FIXME: this is unchecked! + //System.out.println(expr); + SymbolicDataValue left = (SymbolicDataValue) nbe.getLeft(); + SymbolicDataValue right = (SymbolicDataValue) nbe.getRight(); + + Parameter p = null; + SymbolicDataValue sv = null; + + if (left instanceof Parameter) { + if (right instanceof Parameter) { + throw new UnsupportedOperationException("not implemented yet."); + } + else { + p = (Parameter) left; + sv = right; + } + } + else { + p = (Parameter) right; + sv = left; + } + + outmap.put(p, sv); + } + } + else { + // true and false ... + //throw new IllegalStateException("Unsupported: " + expr.getClass()); + } + } +} diff --git a/src/main/java/de/learnlib/ralib/ct/CTBranch.java b/src/main/java/de/learnlib/ralib/ct/CTBranch.java new file mode 100644 index 00000000..4d06290a --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ct/CTBranch.java @@ -0,0 +1,56 @@ +package de.learnlib.ralib.ct; + +import java.util.Set; + +import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.SymbolicDataValue.Register; +import de.learnlib.ralib.data.util.RemappingIterator; +import de.learnlib.ralib.smt.ConstraintSolver; + +public class CTBranch { + private final CTNode child; + + private final CTPath reprPath; + + public CTBranch(CTPath path, CTNode child) { + this.reprPath = path; + this.child = child; + } + + public CTPath getPath() { + return reprPath; + } + + public CTNode getChild() { + return child; + } + + public Bijection matches(CTPath other, ConstraintSolver solver) { + if (!reprPath.typeSizesMatch(other)) { + return null; + } + + Set regs = reprPath.getMemorable(); + Set otherRegs = other.getMemorable(); + + RemappingIterator it = new RemappingIterator<>(otherRegs, regs); + + for (Bijection vars : it) { + if (reprPath.isEquivalent(other, vars, solver)) { + return vars; + } + } + + return null; + } + + public CTPath getRepresentativePath() { + return reprPath; + } + + @Override + public String toString() { + return child.toString(); + } +} diff --git a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java new file mode 100644 index 00000000..3bb60f3f --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java @@ -0,0 +1,46 @@ +package de.learnlib.ralib.ct; + +import java.util.Map; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; + +import de.learnlib.ralib.automata.RALocation; +import de.learnlib.ralib.data.Constants; +import de.learnlib.ralib.learning.Hypothesis; +import de.learnlib.ralib.words.ParameterizedSymbol; + +public class CTHypothesis extends Hypothesis { + + private final BiMap leaves; + + public CTHypothesis(Constants consts, int leaves) { + super(consts); + this.leaves = HashBiMap.create(leaves); + } + + public CTHypothesis(Constants consts, Map leaves) { + super(consts); + this.leaves = HashBiMap.create(leaves.size()); + this.leaves.putAll(leaves); + } + + public void putLeaves(Map leaves) { + this.leaves.putAll(leaves); + } + + @Override + public @Nullable RALocation getSuccessor(RALocation state, ParameterizedSymbol input) { + return super.getSuccessor(state, input); + } + + public RALocation getLocation(CTLeaf leaf) { + return leaves.get(leaf); + } + + public CTLeaf getLeaf(RALocation location) { + return leaves.inverse().get(location); + } +} diff --git a/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java new file mode 100644 index 00000000..863a6b72 --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java @@ -0,0 +1,154 @@ +package de.learnlib.ralib.ct; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.learning.SymbolicSuffix; +import de.learnlib.ralib.oracles.TreeOracle; +import de.learnlib.ralib.smt.ConstraintSolver; +import de.learnlib.ralib.theory.SDT; +import de.learnlib.ralib.words.PSymbolInstance; +import net.automatalib.word.Word; + +public class CTInnerNode extends CTNode { + private final SymbolicSuffix suffix; + private final List branches; + + public CTInnerNode(CTNode parent, SymbolicSuffix suffix) { + super(parent); + this.suffix = suffix; + branches = new ArrayList<>(); + } + + public SymbolicSuffix getSuffix() { + return suffix; + } + + public List getBranches() { + return branches; + } + + protected CTBranch getBranch(CTNode child) { + for (CTBranch b : getBranches()) { + if (b.getChild() == child) { + return b; + } + } + return null; + } + + @Override + protected CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, boolean ioMode) { + CTPath path = CTPath.computePath(oracle, prefix, getSuffixes(), ioMode); +// SDT sdt = path.getSDT(suffix); +// prefix.putSDT(suffix, sdt); + + for (CTBranch b : branches) { + Bijection vars = b.matches(path, solver); + if (vars != null) { +// prefix.setRpBijection(vars); + prefix = new Prefix(prefix, vars, path); + return b.getChild().sift(prefix, oracle, solver, ioMode); + } + } + + // no child with equivalent SDTs, create a new leaf + prefix = new Prefix(prefix, path); + CTLeaf leaf = new CTLeaf(prefix, this); + CTBranch branch = new CTBranch(path, leaf); + branches.add(branch); + return leaf; + } + + protected Map, CTLeaf> refine(CTLeaf leaf, SymbolicSuffix suffix, TreeOracle oracle, ConstraintSolver solver, boolean ioMode) { + CTBranch b = getBranch(leaf); + assert b != null : "Node is not the parent of leaf " + leaf; + + CTInnerNode newNode = new CTInnerNode(this, suffix); + CTBranch newBranch = new CTBranch(b.getPath(), newNode); + branches.remove(b); + branches.add(newBranch); + + Map, CTLeaf> leaves = new LinkedHashMap<>(); + CTLeaf l = sift(leaf.getRepresentativePrefix(), oracle, solver, ioMode); + leaves.put(leaf.getRepresentativePrefix(), l); + + Set prefixes = new LinkedHashSet<>(leaf.getPrefixes()); + prefixes.remove(leaf.getRepresentativePrefix()); + + for (Prefix u : prefixes) { + l = sift(u, oracle, solver, ioMode); + leaves.put(u, l); + } + + return leaves; + } + + @Override + public List getSuffixes() { + List suffixes = new ArrayList<>(); + suffixes.add(suffix); + if (getParent() == null) { + return suffixes; + } + + suffixes.addAll(getParent().getSuffixes()); + return suffixes; + } + + @Override + public boolean isLeaf() { + return false; + } + + @Override + public String toString() { + return "(" + suffix + ")"; + } + +// @Override +// protected void sift(Prefix u, Map rpSDTs, ConstraintSolver solver, TreeOracle oracle) { +// TreeQueryResult tqr = oracle.treeQuery(u.getPrefix(), suffix); +// SDT sdt = tqr.getSdt().relabel(tqr.getPiv().getRenaming().toVarMapping()); +// +// Set regs = new LinkedHashSet<>(); +// regs.addAll(u.getRegisters()); +// regs.addAll(sdt.getRegisters()); +// +// Set rpRegs = new LinkedHashSet<>(); +// for (SDT sdt : rpSDTs.values()) { +// rpRegs.addAll(sdt.getRegisters()); +// } +// +// for (CTBranch b : branches) { +// Set branchRegs = new LinkedHashSet<>(rpRegs); +// branchRegs.addAll(b.getSDT().getRegisters()); +// +// RemappingIterator it = new RemappingIterator(regs, branchRegs); +// +// while(it.hasNext()) { +// Bijection renaming = it.next(); +// if (!b.equivalentUnderRenaming(u, rpSDTs, renaming, solver, oracle)) { +// continue; +// } +// +// // equivalent for all SDTs up to this point +// u = new Prefix(u, new Bijection(renaming)); +// u.putSDT(suffix, sdt); +// rpSDTs.put(suffix, sdt); +// b.getChild().sift(u, rpSDTs, solver, oracle); +// return; +// } +// } +// +// // no branch with equivalent SDT, create new leaf +// u.putSDT(suffix, sdt); +// CTLeaf leaf = new CTLeaf(u, this); +// } + +} diff --git a/src/main/java/de/learnlib/ralib/ct/CTLeaf.java b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java new file mode 100644 index 00000000..d522a026 --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java @@ -0,0 +1,158 @@ +package de.learnlib.ralib.ct; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.learning.LocationComponent; +import de.learnlib.ralib.learning.PrefixContainer; +import de.learnlib.ralib.learning.SymbolicSuffix; +import de.learnlib.ralib.oracles.Branching; +import de.learnlib.ralib.oracles.TreeOracle; +import de.learnlib.ralib.smt.ConstraintSolver; +import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import net.automatalib.word.Word; + +public class CTLeaf extends CTNode implements LocationComponent { + private Prefix rp; + private final Set shortPrefixes; + private final Set prefixes; + + public CTLeaf(Prefix rp, CTNode parent) { + super(parent); + if (parent == null) { + throw new IllegalArgumentException("A leaf must have a parent"); + } + this.rp = rp; + shortPrefixes = new LinkedHashSet<>(); + prefixes = new LinkedHashSet<>(); + prefixes.add(rp); + if (rp instanceof ShortPrefix) { + ((ShortPrefix) rp).updateBranching(); + } + } + + @Override + public List getSuffixes() { + return getParent().getSuffixes(); + } + + public Set getPrefixes() { + return prefixes; + } + + public Prefix getPrefix(Word u) { + for (Prefix p : prefixes) { + if (p.equals(u)) { + return p; + } + } + return null; + } + +// public Set> getWords() { +// return getWords(prefixes); +// } + + public Set getShortPrefixes() { + return shortPrefixes; + } + +// public Set> getShortWords() { +// return getWords(shortPrefixes); +// } + +// private static Set> getWords(Set prefixes) { +// Set> words = new LinkedHashSet<>(); +// for (Prefix p : prefixes) { +// words.add(p.getPrefix()); +// } +// return words; +// } + + public Prefix getRepresentativePrefix() { + return rp; + } + + @Override + public boolean isLeaf() { + return true; + } + + public boolean isAccepting() { + return rp.getPath().isAccepting(); + } + + @Override + protected CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, boolean ioMode) { + prefixes.add(prefix); + if (prefix instanceof ShortPrefix) { + ShortPrefix sp = (ShortPrefix) prefix; + shortPrefixes.add(sp); + sp.updateBranching(); + } + return this; + } + + protected ShortPrefix elevatePrefix(Word u, TreeOracle oracle, ParameterizedSymbol ... inputs) { + Prefix prefix = getPrefix(u); + assert !(prefix instanceof ShortPrefix) : "Prefix is already short: " + prefix; + prefixes.remove(prefix); + ShortPrefix sp = new ShortPrefix(prefix, oracle, inputs); + shortPrefixes.add(sp); + prefixes.add(sp); + + if (prefix == rp) { + rp = sp; + } + return sp; + } + + @Override + public String toString() { +// return prefixes.toString(); + String str = "{RP:[" + rp.toString() + "]"; + for (Prefix u : prefixes) { + if (u != rp) { + str = str + ", " + (u instanceof ShortPrefix ? "SP:[" : "[") + u.toString() + "]"; + } + } + return str + "}"; + } + + @Override + public Word getAccessSequence() { + return getRepresentativePrefix(); + } + + @Override + public Bijection getRemapping(PrefixContainer r) { + assert r instanceof Prefix; + return ((Prefix) r).getRpBijection(); + } + + @Override + public Branching getBranching(ParameterizedSymbol action) { + assert rp instanceof ShortPrefix : "Representative prefix is not a short prefix"; + return ((ShortPrefix) rp).getBranching(action); + } + + @Override + public PrefixContainer getPrimePrefix() { + return rp; + } + + @Override + public Collection getOtherPrefixes() { + Collection prefs = new LinkedList<>(); + prefs.addAll(prefixes); + prefs.remove(rp); + return prefs; + } +} diff --git a/src/main/java/de/learnlib/ralib/ct/CTNode.java b/src/main/java/de/learnlib/ralib/ct/CTNode.java new file mode 100644 index 00000000..1f1be9ad --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ct/CTNode.java @@ -0,0 +1,25 @@ +package de.learnlib.ralib.ct; + +import java.util.List; + +import de.learnlib.ralib.learning.SymbolicSuffix; +import de.learnlib.ralib.oracles.TreeOracle; +import de.learnlib.ralib.smt.ConstraintSolver; + +public abstract class CTNode { + private final CTNode parent; + + public CTNode(CTNode parent) { + this.parent = parent; + } + + public CTNode getParent() { + return parent; + } + + public abstract List getSuffixes(); + + public abstract boolean isLeaf(); + + protected abstract CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, boolean ioMode); +} diff --git a/src/main/java/de/learnlib/ralib/ct/CTPath.java b/src/main/java/de/learnlib/ralib/ct/CTPath.java new file mode 100644 index 00000000..fdd15b41 --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ct/CTPath.java @@ -0,0 +1,148 @@ +package de.learnlib.ralib.ct; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.SDTRelabeling; +import de.learnlib.ralib.data.SymbolicDataValue.Register; +import de.learnlib.ralib.data.util.DataUtils; +import de.learnlib.ralib.learning.SymbolicSuffix; +import de.learnlib.ralib.learning.rastar.RaStar; +import de.learnlib.ralib.oracles.TreeOracle; +import de.learnlib.ralib.oracles.TreeQueryResult; +import de.learnlib.ralib.smt.ConstraintSolver; +import de.learnlib.ralib.theory.SDT; +import de.learnlib.ralib.words.OutputSymbol; + +public class CTPath { + private final Map sdts; + private final MemorableSet memorable; + + private boolean ioMode; + + public CTPath(boolean ioMode) { + this.sdts = new LinkedHashMap<>(); + this.memorable = new MemorableSet(); + this.ioMode = ioMode; + } + + public void putSDT(SymbolicSuffix suffix, SDT sdt) { + assert !sdts.containsKey(suffix); + sdts.put(suffix, sdt); + memorable.addAll(sdt.getDataValues()); + } + + public MemorableSet getMemorable() { + return memorable; + } + + public SDT getSDT(SymbolicSuffix suffix) { + return sdts.get(suffix); + } + + public Map getSDTs() { + return sdts; + } + + public boolean isAccepting() { + SDT s = sdts.get(RaStar.EMPTY_SUFFIX); + return s.isAccepting(); + } + + public boolean isEquivalent(CTPath other, Bijection renaming, ConstraintSolver solver) { + if (!typeSizesMatch(other)) { + return false; + } + + if (!memorable.equals(other.memorable.relabel(renaming))) { + return false; + } + + for (Map.Entry e : sdts.entrySet()) { + SDT sdt1 = e.getValue(); + SDT sdt2 = other.sdts.get(e.getKey()); + + if (!sdt1.isEquivalent(sdt2.relabel(SDTRelabeling.fromBijection(renaming)), solver)) { + return false; + } + } + return true; + } + + protected boolean typeSizesMatch(CTPath other) { + if (!DataUtils.typedSize(memorable).equals(DataUtils.typedSize(other.memorable))) { + return false; + } + + for (Map.Entry e : sdts.entrySet()) { + SDT sdt1 = e.getValue(); + SDT sdt2 = other.sdts.get(e.getKey()); + + if (ioMode) { + if (sdt1 == null && sdt2 == null) { + continue; + } + + if (sdt1 == null || sdt2 == null) { + return false; + } + } + + if (!equalTypeSizes(sdt1.getDataValues(), sdt2.getDataValues())) { + return false; + } + } + return true; + } + + private static boolean equalTypeSizes(Set s1, Set s2) { + return DataUtils.typedSize(s1).equals(DataUtils.typedSize(s2)); + } + + public static CTPath computePath(TreeOracle oracle, Prefix prefix, List suffixes, boolean ioMode) { + CTPath r = new CTPath(ioMode); + SDT sdt = prefix.getSDT(RaStar.EMPTY_SUFFIX); + sdt = sdt == null ? oracle.treeQuery(prefix, RaStar.EMPTY_SUFFIX).sdt() : sdt; + r.putSDT(RaStar.EMPTY_SUFFIX, sdt); + for (SymbolicSuffix s : suffixes) { + if (ioMode && s.getActions().length() > 0) { + // error path + if (prefix.length() > 0 && !r.isAccepting()) { + continue; + } + + // umatched suffix + if ((prefix.length() < 1 && (s.getActions().firstSymbol() instanceof OutputSymbol))) { + continue; + } + } + + sdt = prefix.getSDT(s); + if (sdt == null) { + TreeQueryResult tqr = oracle.treeQuery(prefix, s); + sdt = tqr.sdt(); +// sdt = tqr.getSdt().relabel(tqr.getPiv().getRenaming().toVarMapping()); + } + +// r.sdts.put(s, sdt); + if (r.getSDT(s) == null) { + r.putSDT(s, sdt); + } + } + + return r; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + for (Map.Entry e : this.sdts.entrySet()) { + sb.append("[").append(e.getKey()).append("->").append(e.getValue().toString().replaceAll("\\s+", " ")).append("] "); + } + return sb.toString(); + } +} diff --git a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java new file mode 100644 index 00000000..14e43e8b --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java @@ -0,0 +1,548 @@ +package de.learnlib.ralib.ct; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +import com.google.common.collect.Sets; + +import de.learnlib.ralib.automata.RALocation; +import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.Mapping; +import de.learnlib.ralib.data.SuffixValuation; +import de.learnlib.ralib.data.SymbolicDataValue.Register; +import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; +import de.learnlib.ralib.data.util.RemappingIterator; +import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.SuffixValueGenerator; +import de.learnlib.ralib.learning.SymbolicSuffix; +import de.learnlib.ralib.learning.rastar.RaStar; +import de.learnlib.ralib.oracles.Branching; +import de.learnlib.ralib.oracles.TreeOracle; +import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; +import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; +import de.learnlib.ralib.smt.ConstraintSolver; +import de.learnlib.ralib.smt.ReplacingValuesVisitor; +import de.learnlib.ralib.theory.SDT; +import de.learnlib.ralib.words.DataWords; +import de.learnlib.ralib.words.OutputSymbol; +import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import gov.nasa.jpf.constraints.api.Expression; +import gov.nasa.jpf.constraints.util.ExpressionUtil; +import net.automatalib.word.Word; + +public class ClassificationTree { + private final CTNode root; + + private final Map, CTLeaf> prefixes; + private final Set> shortPrefixes; + + private final ConstraintSolver solver; + private final TreeOracle oracle; + private final SymbolicSuffixRestrictionBuilder restrBuilder; + private final OptimizedSymbolicSuffixBuilder suffixBuilder; + + private final ParameterizedSymbol[] inputs; + private final List outputs; + + private boolean ioMode; + + public ClassificationTree(TreeOracle oracle, + ConstraintSolver solver, + SymbolicSuffixRestrictionBuilder restrBuilder, + OptimizedSymbolicSuffixBuilder suffixBuilder, + boolean ioMode, + ParameterizedSymbol ... inputs) { + this.oracle = oracle; + this.solver = solver; + this.ioMode = ioMode; + this.inputs = inputs; + this.restrBuilder = restrBuilder; + this.suffixBuilder = suffixBuilder; + + prefixes = new LinkedHashMap<>(); + shortPrefixes = new LinkedHashSet<>(); + outputs = outputSuffixes(inputs); + + root = new CTInnerNode(null, RaStar.EMPTY_SUFFIX); + } + + private static List outputSuffixes(ParameterizedSymbol[] inputs) { + List ret = new ArrayList<>(); + for (ParameterizedSymbol ps : inputs) { + if (ps instanceof OutputSymbol) { + ret.add(new SymbolicSuffix(ps)); + } + } + return ret; + } + + public Set getLeaves() { + return new LinkedHashSet<>(prefixes.values()); + } + + public Set> getPrefixes() { + return new LinkedHashSet<>(prefixes.keySet()); + } + +// public Set> getShortPrefixes() { +// return new LinkedHashSet<>(shortPrefixes); +// } + + public CTLeaf getLeaf(Word u) { + return prefixes.get(u); + } + + public Set getExtensions(Word u) { + Set extensions = new LinkedHashSet<>(); + for (ParameterizedSymbol action : inputs) { + extensions.addAll(getExtensions(u, action) + .stream() + .map(w -> getLeaf(u).getPrefix(u)) + .collect(Collectors.toList())); + } + return extensions; + } + + public CTLeaf sift(Word u) { + Prefix prefix = new Prefix(u, new CTPath(ioMode)); + CTLeaf leaf = root.sift(prefix, oracle, solver, ioMode); + prefixes.put(u, leaf); + return leaf; + } + + public void expand(Word u) { + CTLeaf leaf = prefixes.get(u); + if (leaf == null) { + leaf = sift(u); + } + ShortPrefix prefix = leaf.elevatePrefix(u, oracle, inputs); + shortPrefixes.add(u); + + for (ParameterizedSymbol ps : inputs) { + Branching b = prefix.getBranching(ps); + for (Word ua : b.getBranches().keySet()) { + CTLeaf l = sift(ua); + prefixes.put(ua, l); + } + } + } + + public void refine(CTLeaf leaf, SymbolicSuffix suffix) { + CTInnerNode parent = (CTInnerNode) leaf.getParent(); + assert parent != null; + Map, CTLeaf> leaves = parent.refine(leaf, suffix, oracle, solver, ioMode); + prefixes.putAll(leaves); + + for (Word sp : shortPrefixes) { + CTLeaf l = prefixes.get(sp); + Prefix p = l.getPrefix(sp); + if (!(p instanceof ShortPrefix)) { + l.elevatePrefix(sp, oracle, inputs); + } + } + } + + public void initialize() { + sift(RaStar.EMPTY_PREFIX); + } + + public Set getShortPrefixes() { + Set sp = new LinkedHashSet<>(); + for (CTLeaf leaf : getLeaves()) { + sp.addAll(leaf.getShortPrefixes()); + } + assert sp.size() == shortPrefixes.size(); + assert sp.containsAll(shortPrefixes); + return sp; + } + + public CTInnerNode lca(CTNode n1, CTNode n2) { + if (n1 == n2) { + if (n1.isLeaf()) { + return (CTInnerNode) n1.getParent(); + } + return (CTInnerNode) n1; + } + int h1 = height(n1); + int h2 = height(n2); + + return lca(n1, h1, n2, h2); + } + + private CTInnerNode lca(CTNode n1, int h1, CTNode n2, int h2) { + if (n1 == n2) { + assert n1 instanceof CTInnerNode; + return (CTInnerNode) n1; + } + if (h1 < h2) { + return lca(n1, h1, n2.getParent(), h2 - 1); + } + if (h1 > h2) { + return lca(n1.getParent(), h1 - 1, n2, h2); + } + return lca(n1.getParent(), h1 - 1, n2.getParent(), h2 - 1); + } + + private int height(CTNode n) { + int h = 0; + while (n.getParent() != null) { + h++; + n = n.getParent(); + } + return h; + } + + public boolean checkOutputClosed() { + if (!ioMode) { + return true; + } + return checkOutputClosed(root); + } + + private boolean checkOutputClosed(CTNode node) { + if (node.isLeaf()) { + CTLeaf leaf = (CTLeaf) node; + for (SymbolicSuffix v : outputs) { + if (!leaf.getSuffixes().contains(v)) { + refine(leaf, v); + return false; + } + } + return true; + } else { + CTInnerNode n = (CTInnerNode) node; + for (CTBranch b : n.getBranches()) { + if (!checkOutputClosed(b.getChild())) { + return false; + } + } + } + return true; + } + + // CLOSEDNESS CHECKS + + public boolean checkLocationClosedness() { + for (CTLeaf leaf : getLeaves()) { + if (leaf.getShortPrefixes().isEmpty()) { + expand(leaf.getRepresentativePrefix()); + return false; + } + } + return true; + } + + public boolean checkTransitionClosedness() { + for (CTLeaf leaf : getLeaves()) { + for (ShortPrefix u : leaf.getShortPrefixes()) { + for (ParameterizedSymbol a : inputs) { + for (Word ua : u.getBranching(a).getBranches().keySet()) { + if (!prefixes.containsKey(ua)) { + sift(ua); + return false; + } + } + } + } + } + return true; + } + + public boolean checkRegisterClosedness() { + for (Map.Entry, CTLeaf> e : prefixes.entrySet()) { + Word ua = e.getKey(); + CTLeaf leaf = e.getValue(); + if (ua.length() < 1) { + continue; + } + Word u = ua.prefix(ua.size() - 1); + Prefix ua_pref = leaf.getPrefix(ua); + CTLeaf u_leaf = prefixes.get(u); + + Set ua_mem = leaf.getPrefix(ua).getRegisters(); + Set u_mem = prefixes.get(u).getPrefix(u).getRegisters(); + Set a_mem = actionRegisters(ua); + + if (!consistentMemorable(ua_mem, u_mem, a_mem)) { + for (SymbolicSuffix v : leaf.getSuffixes()) { + Set s_mem = ua_pref.getSDT(v).getDataValues(); + if (!consistentMemorable(s_mem, u_mem, a_mem)) { + DataValue[] missingRegs = missingRegisters(s_mem, u_mem, a_mem); + SymbolicSuffix av = extendSuffix(ua, v, missingRegs); + refine(u_leaf, av); + break; + } + } + return false; + } + } + return true; + } + + private boolean consistentMemorable(Set ua_mem, Set u_mem, Set a_mem) { + Set union = new LinkedHashSet<>(); + union.addAll(u_mem); + union.addAll(a_mem); + return union.containsAll(ua_mem); + } + + private Set actionRegisters(Word ua) { + int ua_arity = DataWords.paramLength(DataWords.actsOf(ua)); + int u_arity = ua_arity - ua.lastSymbol().getBaseSymbol().getArity(); + DataValue[] vals = DataWords.valsOf(ua); + + Set regs = new LinkedHashSet<>(); + for (int i = u_arity; i < ua_arity; i++) { + regs.add(vals[i]); + } + return regs; + } + + private DataValue[] missingRegisters(Set s_mem, Set u_mem, Set a_mem) { + Set union = new LinkedHashSet<>(u_mem); + union.addAll(a_mem); + Set difference = new LinkedHashSet<>(s_mem); + difference.removeAll(union); + return difference.toArray(new DataValue[difference.size()]); + } + + private SymbolicSuffix extendSuffix(Word ua, SymbolicSuffix v, DataValue[] missingRegs) { + if (suffixBuilder == null) { + PSymbolInstance a = ua.lastSymbol(); + Word u = ua.prefix(ua.length() - 1); + SymbolicSuffix alpha = new SymbolicSuffix(u, Word.fromSymbols(a), restrBuilder); + return alpha.concat(v); + } + + SDT u_sdt = prefixes.get(ua).getPrefix(ua).getSDT(v); + assert u_sdt != null : "SDT for symbolic suffix " + v + " does not exist for prefix " + ua; + + return suffixBuilder.extendSuffix(ua, u_sdt, v, missingRegs); + } + + // CONSISTENCY CHECKS + + public boolean checkLocationConsistency() { + for (CTLeaf l : getLeaves()) { + Iterator sp = l.getShortPrefixes().iterator(); + if (!sp.hasNext()) { + continue; + } + ShortPrefix u = sp.next(); + while (sp.hasNext()) { + ShortPrefix uPrime = sp.next(); + for (ParameterizedSymbol action : inputs) { + for (Map.Entry, Expression> ue : u.getBranching(action).getBranches().entrySet()) { + Word ua = ue.getKey(); + Expression g = ue.getValue(); + Bijection gamma = u.getRpBijection().compose(uPrime.getRpBijection().inverse()); + + ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); + Expression gammaG = rvv.apply(g, gamma.toVarMapping()); + + Optional> uPrimeA = uPrime.getBranching(action).getPrefix(gammaG, new Mapping<>(), solver); + assert uPrimeA.isPresent(); + + CTLeaf uALeaf = getLeaf(ua); + CTLeaf uPrimeALeaf = getLeaf(uPrimeA.get()); + if (uALeaf != uPrimeALeaf) { + SymbolicSuffix v = lca(uALeaf, uPrimeALeaf).getSuffix(); + SymbolicSuffix av = extendSuffix(ua, uPrimeA.get(), v); + refine(l, av); + return false; + } + } + } + } + } + return true; + } + + public boolean checkTransitionConsistency() { + for (ShortPrefix u : getShortPrefixes()) { + if (u.length() < 1) { + continue; + } + for (ParameterizedSymbol action : inputs) { + Set> extensions = getExtensions(u, action); + for (Map.Entry, Expression> e : u.getBranching(action).getBranches().entrySet()) { + Word uA = e.getKey(); + Expression g = e.getValue(); + for (Word uB : extensions) { + if (uB.equals(uA)) { + continue; + } + SuffixValuation uBVals = actionValuation(uB); + if (solver.isSatisfiable(g, uBVals)) { + Optional av = transitionConsistentA(uA, uB); + if (av.isEmpty()) { + av = transitionConsistentB(uA, uB); + } + if (av.isPresent()) { + refine(getLeaf(u), av.get()); + return false; + } + } + } + } + } + } + return true; + } + + private Optional transitionConsistentA(Word uA, Word uB) { + Word u = uA.prefix(uA.length() - 1); + CTLeaf uALeaf = getLeaf(uA); + CTLeaf uBLeaf = getLeaf(uB); + if (uALeaf != uBLeaf) { + CTLeaf uLeaf = getLeaf(u); + assert uLeaf != null : "Prefix is not short: " + u; + SymbolicSuffix v = lca(uALeaf, uBLeaf).getSuffix(); + SymbolicSuffix av = extendSuffix(uA, uB, v); + return Optional.of(av); + } + return Optional.empty(); + } + + private Optional transitionConsistentB(Word uA, Word uB) { + Prefix pA = getLeaf(uA).getPrefix(uA); + Prefix pB = getLeaf(uB).getPrefix(uB); + for (SymbolicSuffix v : getLeaf(uB).getSuffixes()) { + if (!SDT.equivalentUnderId(pA.getSDT(v), pB.getSDT(v), solver)) { + CTLeaf uLeaf = getLeaf(uA.prefix(uA.length() - 1)); + assert uLeaf != null; + DataValue[] regs = inequivalentMapping(pA.getRpBijection(), pB.getRpBijection()); + SymbolicSuffix av = extendSuffix(uA, v, regs); + return Optional.of(av); + } + } + return Optional.empty(); + } + + public boolean checkRegisterConsistency() { + for (Prefix u : getShortPrefixes()) { + if (u.length() < 2) { + continue; + } + for (ParameterizedSymbol action : inputs) { + Iterator extensions = getExtensions(u, action) + .stream() + .map(w -> getLeaf(w).getPrefix(w)) + .iterator(); + while (extensions.hasNext()) { + Prefix ua = extensions.next(); + + RemappingIterator rit = new RemappingIterator<>(u.getRegisters(), u.getRegisters()); + for (Bijection gamma : rit) { + CTPath uPath = u.getPath(); + if (uPath.isEquivalent(uPath, gamma, solver)) { + for (Map.Entry e : ua.getPath().getSDTs().entrySet()) { + SymbolicSuffix v = e.getKey(); + SDT uaSDT = e.getValue(); + if (SDT.equivalentUnderBijection(uaSDT, uaSDT, gamma, solver) == null) { + DataValue[] regs = gamma.keySet().toArray(new DataValue[gamma.size()]); + SymbolicSuffix av = extendSuffix(ua, v, regs); + refine(getLeaf(u), av); + return false; + } + } + } + + +// for (Map.Entry e : u.getPath().getSDTs().entrySet()) { +// // is u equivalent to u for v under gamma? +// SymbolicSuffix v = e.getKey(); +// SDT uSDT = e.getValue(); +// if (SDT.equivalentUnderBijection(uSDT, uSDT, gamma, solver) == null) { +// continue; +// } +// +// // is ua equivalent to ua for v under (gamma union {regs(a) -> regs(a)]) +// SDT uaSDT = ua.getSDT(v); +// if (SDT.equivalentUnderBijection(uaSDT, uaSDT, gamma, solver) == null) { +// DataValue[] regs = gamma.keySet().toArray(new DataValue[gamma.size()]); +// SymbolicSuffix av = extendSuffix(ua, v, regs); +// refine(getLeaf(u), av); +// return false; +// } +// } + } + } + } + } + return true; + } + + private SymbolicSuffix extendSuffix(Word u1, Word u2, SymbolicSuffix v) { + SDT sdt1 = getLeaf(u1).getPrefix(u1).getSDT(v); + SDT sdt2 = getLeaf(u2).getPrefix(u2).getSDT(v); + return suffixBuilder.extendDistinguishingSuffix(u1, sdt1, u2, sdt2, v); + } + + private SuffixValuation actionValuation(Word ua) { + SuffixValueGenerator svgen = new SuffixValueGenerator(); + DataValue[] vals = ua.lastSymbol().getParameterValues(); + SuffixValuation valuation = new SuffixValuation(); + for (int i = 0; i < vals.length; i++) { + SuffixValue sv = svgen.next(vals[i].getDataType()); + valuation.put(sv, vals[i]); + } + return valuation; + } + + public Set> getExtensions(Word u, ParameterizedSymbol action) { + assert u.length() > 0; + return prefixes.keySet() + .stream() + .filter(w -> w.length() == u.length() + 1) + .filter(w -> w.prefix(w.length() - 1).equals(u) && w.lastSymbol().getBaseSymbol().equals(action)) + .collect(Collectors.toSet()); + } + + private DataValue[] inequivalentMapping(Bijection a, Bijection b) { + Set ret = new LinkedHashSet<>(); + for (Map.Entry ea : a.entrySet()) { + DataValue key = ea.getKey(); + if (!b.get(key).equals(ea.getValue())) { + ret.add(key); + ret.add(b.get(key)); + } + } + return ret.toArray(new DataValue[ret.size()]); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("CT: {"); + buildTreeString(builder, root, "", " ", " -- "); + builder.append("}"); + return builder.toString(); + } + + private void buildTreeString(StringBuilder builder, CTNode node, String currentIndentation, String indentation, String sep) { + if (node.isLeaf()) { + builder.append("\n").append(currentIndentation).append("Leaf: ").append(node); + } else { + CTInnerNode inner = (CTInnerNode) node; + builder.append("\n").append(currentIndentation).append("Inner: ").append(inner.getSuffix()); + if (!inner.getBranches().isEmpty()) { + Iterator iter = inner.getBranches().iterator(); + while (iter.hasNext()) { + builder.append("\n").append(currentIndentation); + CTBranch branch = iter.next(); + builder.append("Branch: ").append(branch.getRepresentativePath()); + buildTreeString(builder, branch.getChild(), indentation + currentIndentation, indentation, sep); + } + } + } + } +} diff --git a/src/main/java/de/learnlib/ralib/ct/MemorableSet.java b/src/main/java/de/learnlib/ralib/ct/MemorableSet.java new file mode 100644 index 00000000..f1391292 --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ct/MemorableSet.java @@ -0,0 +1,18 @@ +package de.learnlib.ralib.ct; + +import java.util.LinkedHashSet; + +import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.SymbolicDataValue.Register; + +public class MemorableSet extends LinkedHashSet { + public MemorableSet relabel(Bijection renaming) { + MemorableSet renamed = new MemorableSet(); + for (DataValue dv : this) { + DataValue ndv = renaming.get(dv); + renamed.add((ndv == null) ? dv : ndv); + } + return renamed; + } +} diff --git a/src/main/java/de/learnlib/ralib/ct/Prefix.java b/src/main/java/de/learnlib/ralib/ct/Prefix.java new file mode 100644 index 00000000..6dfa7dad --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ct/Prefix.java @@ -0,0 +1,212 @@ +package de.learnlib.ralib.ct; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Spliterator; +import java.util.function.Function; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.RegisterAssignment; +import de.learnlib.ralib.data.SymbolicDataValue.Register; +import de.learnlib.ralib.data.util.SymbolicDataValueGenerator; +import de.learnlib.ralib.learning.PrefixContainer; +import de.learnlib.ralib.learning.SymbolicSuffix; +import de.learnlib.ralib.theory.SDT; +import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import net.automatalib.word.Word; + +public class Prefix extends Word implements PrefixContainer { + private final Word prefix; + private Bijection rpBijection; +// private final Map sdts; + private final CTPath path; + +// public Prefix(Word prefix, Bijection rpBijection) { + public Prefix(Word u, Bijection rpRenaming, CTPath path) { + this.prefix = u instanceof Prefix ? ((Prefix) u).getPrefix() : u; + this.rpBijection = rpRenaming; + this.path = path; +// sdts = new LinkedHashMap<>(); + } + + public Prefix(Word prefix, CTPath path) { + this(prefix, Bijection.id(path.getMemorable()), path); + } + + public Prefix(Prefix prefix, Bijection rpRenaming) { + this(prefix.prefix, rpRenaming, prefix.path); +// sdts.putAll(u.sdts); + } + + public Prefix(Prefix other) { + this(other.prefix, other.rpBijection, other.path); + } + + public void setRpBijection(Bijection rpBijection) { + this.rpBijection = rpBijection; + } + + public SDT[] getSDTs(ParameterizedSymbol ps) { + List list = new ArrayList<>(); + for (Map.Entry e : path.getSDTs().entrySet()) { + Word acts = e.getKey().getActions(); + if (acts.length() > 0 && acts.firstSymbol().equals(ps)) { + list.add(e.getValue()); + } + } + return list.toArray(new SDT[list.size()]); + } + +// public void putSDT(SymbolicSuffix s, SDT sdt) { +// sdts.put(s, sdt); +// } + +// public Word getPrefix() { +// return prefix; +// } + + public SDT getSDT(SymbolicSuffix s) { + return path.getSDT(s); + } + + public Bijection getRpBijection() { + return rpBijection; + } + + public MemorableSet getRegisters() { + return path.getMemorable(); + } + + public CTPath getPath() { + return path; + } + + @Override + public boolean equals(Object other) { + if (other instanceof Prefix) { + return ((Prefix) other).prefix.equals(prefix); + } + return prefix.equals(other); +// if (!(other instanceof Prefix)) { +// return false; +// } +// return ((Prefix) other).prefix.equals(prefix); + } + + @Override + public Word getPrefix() { + return prefix; + } + + @Override + public RegisterAssignment getAssignment() { + RegisterAssignment ra = new RegisterAssignment(); + SymbolicDataValueGenerator.RegisterGenerator regGen = + new SymbolicDataValueGenerator.RegisterGenerator(); + + this.getRegisters().forEach( + dv -> ra.put(dv, regGen.next(dv.getDataType())) + ); + + return ra; + } + + @Override + public int hashCode() { + return prefix.hashCode(); + } + + @Override + public String toString() { + return prefix.toString(); + } + + @Override + public int length() { + return prefix.length(); + } + + @Override + public PSymbolInstance getSymbol(int index) { + return prefix.getSymbol(index); + } + + @Override + public Iterator iterator() { + return prefix.iterator(); + } + + @Override + public Spliterator spliterator() { + return prefix.spliterator(); + } + + @Override + public void writeToArray(int offset, @Nullable Object[] array, int tgtOffset, int length) { + prefix.writeToArray(offset, array, tgtOffset, length); + } + + @Override + public List asList() { + return prefix.asList(); + } + + @Override + public PSymbolInstance lastSymbol() { + return prefix.lastSymbol(); + } + + @Override + public Word append(PSymbolInstance symbol) { + return prefix.append(symbol); + } + + @Override + public Word prepend(PSymbolInstance symbol) { + return prefix.prepend(symbol); + } + + @Override + public boolean isPrefixOf(Word other) { + return prefix.isPrefixOf(other); + } + + @Override + public Word longestCommonPrefix(Word other) { + return prefix.longestCommonPrefix(other); + } + + @Override + public boolean isSuffixOf(Word other) { + return prefix.isSuffixOf(other); + } + + @Override + public Word longestCommonSuffix(Word other) { + return prefix.longestCommonSuffix(other); + } + + @Override + public Word flatten() { + return prefix.flatten(); + } + + @Override + public Word trimmed() { + return prefix.trimmed(); + } + + @Override + public Word transform(Function transformer) { + return prefix.transform(transformer); + } +} diff --git a/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java b/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java new file mode 100644 index 00000000..c8f5fa6d --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java @@ -0,0 +1,57 @@ +package de.learnlib.ralib.ct; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.oracles.Branching; +import de.learnlib.ralib.oracles.TreeOracle; +import de.learnlib.ralib.theory.SDT; +import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import gov.nasa.jpf.constraints.api.Expression; +import net.automatalib.word.Word; + +public class ShortPrefix extends Prefix { + + private final Map branching; + + private final TreeOracle oracle; + + private final ParameterizedSymbol[] inputs; + + public ShortPrefix(Prefix u, Bijection rpBijection, TreeOracle oracle, ParameterizedSymbol ... inputs) { + super(u, rpBijection); + this.oracle = oracle; + this.inputs = inputs; + branching = new LinkedHashMap<>(); + + for (ParameterizedSymbol ps : inputs) { + SDT[] sdts = getSDTs(ps); + Branching b = oracle.getInitialBranching(this, ps, sdts); + branching.put(ps, b); + } + } + + public ShortPrefix(Prefix u, TreeOracle oracle, ParameterizedSymbol ... inputs) { + this(u, u.getRpBijection(), oracle, inputs); + } + + public Branching getBranching(ParameterizedSymbol ps) { + return branching.get(ps); + } + + public void updateBranching() { + for (ParameterizedSymbol ps : inputs) { + SDT[] sdts = getSDTs(ps); + Branching b = oracle.updateBranching(this, ps, branching.get(ps), sdts); + branching.put(ps, b); + } + } + + public Set> getInitialReprPrefixes(ParameterizedSymbol ps) { + return branching.get(ps).getBranches().keySet(); + } +} diff --git a/src/main/java/de/learnlib/ralib/data/util/DataUtils.java b/src/main/java/de/learnlib/ralib/data/util/DataUtils.java new file mode 100644 index 00000000..69b5af45 --- /dev/null +++ b/src/main/java/de/learnlib/ralib/data/util/DataUtils.java @@ -0,0 +1,38 @@ +package de.learnlib.ralib.data.util; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import de.learnlib.ralib.data.DataType; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.SuffixValuation; +import de.learnlib.ralib.data.SymbolicDataValue; +import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; +import de.learnlib.ralib.data.TypedValue; +import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.SuffixValueGenerator; +import de.learnlib.ralib.words.PSymbolInstance; + +public class DataUtils { + + public static Map typedSize(Set set) { + Map ts = new LinkedHashMap<>(); + for (TypedValue s : set) { + Integer i = ts.get(s.getDataType()); + i = (i == null) ? 1 : i + 1; + ts.put(s.getDataType(), i); + } + return ts; + } + + public static SuffixValuation actionValuation(PSymbolInstance action) { + SuffixValuation valuation = new SuffixValuation(); + DataValue[] vals = action.getParameterValues(); + SuffixValueGenerator svgen = new SuffixValueGenerator(); + for (int i = 0; i < vals.length; i++) { + SuffixValue sv = svgen.next(vals[i].getDataType()); + valuation.put(sv, vals[i]); + } + return valuation; + } +} diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/LeafComponent.java b/src/main/java/de/learnlib/ralib/learning/ralambda/LeafComponent.java new file mode 100644 index 00000000..c822ab71 --- /dev/null +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/LeafComponent.java @@ -0,0 +1,89 @@ +//package de.learnlib.ralib.learning.ralambda; +// +//import java.util.Collection; +//import java.util.LinkedHashSet; +//import java.util.LinkedList; +//import java.util.Set; +// +//import de.learnlib.ralib.ct.CTLeaf; +//import de.learnlib.ralib.ct.Prefix; +//import de.learnlib.ralib.ct.ShortPrefix; +//import de.learnlib.ralib.data.Bijection; +//import de.learnlib.ralib.data.PIV; +//import de.learnlib.ralib.data.VarMapping; +//import de.learnlib.ralib.learning.LocationComponent; +//import de.learnlib.ralib.learning.PrefixContainer; +//import de.learnlib.ralib.oracles.Branching; +//import de.learnlib.ralib.words.PSymbolInstance; +//import de.learnlib.ralib.words.ParameterizedSymbol; +//import net.automatalib.word.Word; +// +//public class LeafComponent implements LocationComponent { +// +// public class PC implements PrefixContainer { +// Word prefix; +// PIV piv; +// +// public PC(Word prefix, PIV piv) { +// this.prefix = prefix; +// this.piv = piv; +// } +// +// @Override +// public Word getPrefix() { +// return prefix; +// } +// +// @Override +// public PIV getParsInVars() { +// return piv; +// } +// } +// +// private final CTLeaf leaf; +// +// public LeafComponent(CTLeaf leaf) { +// this.leaf = leaf; +// } +// +// @Override +// public boolean isAccepting() { +// return leaf.isAccepting(); +// } +// +// @Override +// public Word getAccessSequence() { +// return leaf.getRepresentativePrefix(); +// } +// +// @Override +// public VarMapping getRemapping(PrefixContainer r) { +// Bijection remapping = leaf.getPrefix(r.getPrefix()).getRpBijection(); +// return remapping.toVarMapping(); +// } +// +// @Override +// public Branching getBranching(ParameterizedSymbol action) { +// Prefix rp = leaf.getRepresentativePrefix(); +// assert rp instanceof ShortPrefix : "Prefix is not a short prefix: " + rp; +// return ((ShortPrefix) rp).getBranching(action); +// } +// +// @Override +// public PrefixContainer getPrimePrefix() { +// Prefix rp = leaf.getRepresentativePrefix(); +// return new PC(rp, PIV.defaultPiv(rp.getRegisters())); +// } +// +// @Override +// public Collection getOtherPrefixes() { +// Set prefixes = new LinkedHashSet<>(leaf.getPrefixes()); +// prefixes.remove(leaf.getRepresentativePrefix()); +// Collection container = new LinkedList<>(); +// for (Prefix u : prefixes) { +// container.add(new PC(u, PIV.defaultPiv(u.getRegisters()))); +// } +// return container; +// } +// +//} diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java new file mode 100644 index 00000000..2da7b1f6 --- /dev/null +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java @@ -0,0 +1,188 @@ +package de.learnlib.ralib.learning.ralambda; + +import java.util.Deque; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import de.learnlib.logging.Category; +import de.learnlib.query.DefaultQuery; +import de.learnlib.ralib.ct.CTAutomatonBuilder; +import de.learnlib.ralib.ct.CTLeaf; +import de.learnlib.ralib.ct.ClassificationTree; +import de.learnlib.ralib.data.Constants; +import de.learnlib.ralib.learning.CounterexampleAnalysis; +import de.learnlib.ralib.learning.Hypothesis; +import de.learnlib.ralib.learning.LocationComponent; +import de.learnlib.ralib.learning.QueryStatistics; +import de.learnlib.ralib.learning.RaLearningAlgorithm; +import de.learnlib.ralib.learning.RaLearningAlgorithmName; +import de.learnlib.ralib.learning.rastar.CEAnalysisResult; +import de.learnlib.ralib.learning.rastar.RaStar; +import de.learnlib.ralib.oracles.SDTLogicOracle; +import de.learnlib.ralib.oracles.TreeOracle; +import de.learnlib.ralib.oracles.TreeOracleFactory; +import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; +import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; +import de.learnlib.ralib.smt.ConstraintSolver; +import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import net.automatalib.word.Word; + +public class SLCT implements RaLearningAlgorithm { + + private final ClassificationTree ct; + + private final Constants consts; + + private final Deque> counterexamples; + + private Hypothesis hyp; + + private final TreeOracle sulOracle; + + private final SDTLogicOracle sdtLogicOracle; + + private final TreeOracleFactory hypOracleFactory; + + private final OptimizedSymbolicSuffixBuilder suffixBuilder; + private final SymbolicSuffixRestrictionBuilder restrictionBuilder; + + private QueryStatistics queryStats; + + private final boolean ioMode; + + private final ConstraintSolver solver; + + private static final Logger LOGGER = LoggerFactory.getLogger(RaDT.class); + + public SLCT(TreeOracle sulOracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, + Constants consts, boolean ioMode, ConstraintSolver solver, ParameterizedSymbol ... inputs) { + this.consts = consts; + this.sulOracle = sulOracle; + this.sdtLogicOracle = sdtLogicOracle; + this.hypOracleFactory = hypOracleFactory; + this.solver = solver; + this.ioMode = ioMode; + restrictionBuilder = sulOracle.getRestrictionBuilder(); + suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrictionBuilder); + counterexamples = new LinkedList<>(); + hyp = null; + ct = new ClassificationTree(sulOracle, solver, restrictionBuilder, suffixBuilder, ioMode, inputs); + ct.sift(RaStar.EMPTY_PREFIX); + } + + @Override + public void learn() { + if (hyp == null) { + while(!checkClosedness()); + buildHypothesis(); + } + + while(analyzeCounterExample()); + + if (queryStats != null) { + queryStats.hypothesisConstructed(); + } + } + + private boolean checkClosedness() { + if (!ct.checkOutputClosed()) { + return false; + } + if (!ct.checkLocationClosedness()) { + return false; + } + if (!ct.checkTransitionClosedness()) { + return false; + } + if (!ct.checkRegisterClosedness()) { + return false; + } + return true; + } + + private void buildHypothesis() { + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, ioMode); + hyp = ab.buildHypothesis(); + } + + private boolean analyzeCounterExample() { + LOGGER.info(Category.PHASE, "Analyzing Counterexample"); + if (counterexamples.isEmpty()) { + return false; + } + + TreeOracle hypOracle = hypOracleFactory.createTreeOracle(hyp); + + Map, LocationComponent> components = new LinkedHashMap<>(); + for (CTLeaf leaf : ct.getLeaves()) { +// LeafComponent c = new LeafComponent(leaf); + for (Word u : leaf.getPrefixes()) { + components.put(u, leaf); + } + } + CounterexampleAnalysis analysis = new CounterexampleAnalysis(sulOracle, hypOracle, hyp, sdtLogicOracle, components, consts); + + DefaultQuery ce = counterexamples.peek(); + + boolean hypce = hyp.accepts(ce.getInput()); + boolean sulce = ce.getOutput(); + if (hypce == sulce) { + LOGGER.info(Category.EVENT, "word is not a counterexample: " + ce + " - " + sulce); + counterexamples.poll(); + return false; + } + + if (queryStats != null) { + queryStats.analyzingCounterExample(); + } + + CEAnalysisResult res = analysis.analyzeCounterexample(ce.getInput()); + + if (queryStats != null) { + queryStats.processingCounterExample(); + queryStats.analyzeCE(ce.getInput()); + } + + Word accSeq = hyp.transformAccessSequence(res.getPrefix()); + CTLeaf leaf = ct.getLeaf(accSeq); + assert leaf != null : "Prefix not in classification tree: " + accSeq; + ct.refine(leaf, res.getSuffix()); + + while(!checkClosedness()); + + buildHypothesis(); + return true; + } + + @Override + public void addCounterexample(DefaultQuery ce) { + LOGGER.info(Category.EVENT, "adding counterexample: " + ce); + counterexamples.add(ce); + } + + @Override + public Hypothesis getHypothesis() { + return hyp; + } + + @Override + public void setStatisticCounter(QueryStatistics queryStats) { + this.queryStats = queryStats; + } + + @Override + public QueryStatistics getQueryStatistics() { + return queryStats; + } + + @Override + public RaLearningAlgorithmName getName() { + return RaLearningAlgorithmName.RADT; + } + +} diff --git a/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java b/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java new file mode 100644 index 00000000..eda73309 --- /dev/null +++ b/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java @@ -0,0 +1,391 @@ +package de.learnlib.ralib.ct; + +import static de.learnlib.ralib.example.priority.PriorityQueueOracle.OFFER; +import static de.learnlib.ralib.example.stack.StackAutomatonExample.AUTOMATON; +import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_POP; +import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_PUSH; +import static de.learnlib.ralib.example.stack.StackAutomatonExample.T_INT; +import static org.testng.Assert.assertFalse; + +import java.math.BigDecimal; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import de.learnlib.ralib.RaLibTestSuite; +import de.learnlib.ralib.TestUtil; +import de.learnlib.ralib.automata.Assignment; +import de.learnlib.ralib.automata.InputTransition; +import de.learnlib.ralib.automata.MutableRegisterAutomaton; +import de.learnlib.ralib.automata.RALocation; +import de.learnlib.ralib.automata.RegisterAutomaton; +import de.learnlib.ralib.data.Constants; +import de.learnlib.ralib.data.DataType; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.SymbolicDataValue; +import de.learnlib.ralib.data.SymbolicDataValue.Parameter; +import de.learnlib.ralib.data.SymbolicDataValue.Register; +import de.learnlib.ralib.data.VarMapping; +import de.learnlib.ralib.learning.SymbolicSuffix; +import de.learnlib.ralib.learning.rastar.RaStar; +import de.learnlib.ralib.oracles.DataWordOracle; +import de.learnlib.ralib.oracles.SimulatorOracle; +import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; +import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; +import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; +import de.learnlib.ralib.smt.ConstraintSolver; +import de.learnlib.ralib.theory.Theory; +import de.learnlib.ralib.tools.theories.DoubleInequalityTheory; +import de.learnlib.ralib.tools.theories.IntegerEqualityTheory; +import de.learnlib.ralib.words.InputSymbol; +import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import gov.nasa.jpf.constraints.api.Expression; +import gov.nasa.jpf.constraints.expressions.NumericBooleanExpression; +import gov.nasa.jpf.constraints.expressions.NumericComparator; +import gov.nasa.jpf.constraints.util.ExpressionUtil; +import net.automatalib.word.Word; + +public class CTConsistencyTest extends RaLibTestSuite { + + private static DataType DT = new DataType("double"); + private static InputSymbol A = new InputSymbol("a", new DataType[] {DT}); + private static InputSymbol B = new InputSymbol("b"); + + private static InputSymbol ALPHA = new InputSymbol("α", new DataType[] {T_INT}); + private static InputSymbol BETA = new InputSymbol("β", new DataType[] {T_INT}); + + @Test + public void testConsistencyStack() { + + Map teachers = new LinkedHashMap<>(); + teachers.put(T_INT, new IntegerEqualityTheory(T_INT)); + + Constants consts = new Constants(); + + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); + OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); + + RegisterAutomaton sul = AUTOMATON; + DataWordOracle dwOracle = new SimulatorOracle(sul); + ConstraintSolver solver = new ConstraintSolver(); + + MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(dwOracle, teachers, consts, solver); + + DataValue dv0 = new DataValue(T_INT, BigDecimal.ZERO); + DataValue dv1 = new DataValue(T_INT, BigDecimal.ONE); + DataValue dv2 = new DataValue(T_INT, BigDecimal.valueOf(2)); + + PSymbolInstance push0 = new PSymbolInstance(I_PUSH, dv0); + PSymbolInstance push1 = new PSymbolInstance(I_PUSH, dv1); + PSymbolInstance pop0 = new PSymbolInstance(I_POP, dv0); + PSymbolInstance pop1 = new PSymbolInstance(I_POP, dv1); + + Word pu0 = Word.fromSymbols(push0); + Word po0 = Word.fromSymbols(pop0); + Word pu0pu1 = Word.fromSymbols(push0, push1); + Word pu0po0 = Word.fromSymbols(push0, pop0); + Word pu0pu1po1 = Word.fromSymbols(push0, push1, pop1); + + SymbolicSuffix s1 = new SymbolicSuffix(pu0, Word.fromSymbols(push1)); + SymbolicSuffix s2 = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(push0, push1)); + SymbolicSuffix s3 = new SymbolicSuffix(pu0, Word.fromSymbols(pop0)); + SymbolicSuffix s4 = new SymbolicSuffix(pu0pu1, Word.fromSymbols(pop1, pop0)); + + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, false, I_PUSH, I_POP); + + ct.initialize(); + boolean closed = ct.checkLocationClosedness(); + closed = ct.checkLocationClosedness(); + Assert.assertFalse(closed); + + ct.expand(pu0); + closed = ct.checkLocationClosedness(); + Assert.assertTrue(closed); + + ct.expand(pu0pu1); + closed = ct.checkLocationClosedness(); + Assert.assertTrue(closed); + + ct.refine(ct.getLeaf(pu0pu1), s1); + boolean consistent = ct.checkLocationConsistency(); + Assert.assertFalse(consistent); + + ct.sift(pu0po0); + consistent = ct.checkTransitionConsistency(); + Assert.assertFalse(consistent); + } + + @Test + public void testLocationConsistency() { + RegisterAutomaton sul = buildLocationConsistencyAutomaton(); + DataWordOracle dwOracle = new SimulatorOracle(sul); + + final Map teachers = new LinkedHashMap<>(); + teachers.put(DT, new DoubleInequalityTheory(DT)); + + Constants consts = new Constants(); + + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); + OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); + + ConstraintSolver solver = TestUtil.getZ3Solver(); + MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( + dwOracle, teachers, consts, solver); + + System.out.println(sul); + + DataValue dv0 = new DataValue(DT, BigDecimal.ZERO); + DataValue dv1 = new DataValue(DT, BigDecimal.ONE); + DataValue dv2 = new DataValue(DT, BigDecimal.valueOf(2)); + + Word a1 = Word.fromSymbols(new PSymbolInstance(A, dv1)); + Word a1a2 = Word.fromSymbols( + new PSymbolInstance(A, dv1), + new PSymbolInstance(A, dv2)); + Word a1a0 = Word.fromSymbols( + new PSymbolInstance(A, dv1), + new PSymbolInstance(A, dv0)); + Word a1a2a2 = Word.fromSymbols( + new PSymbolInstance(A, dv1), + new PSymbolInstance(A, dv2), + new PSymbolInstance(A, dv2)); + Word a1a0a0 = Word.fromSymbols( + new PSymbolInstance(A, dv1), + new PSymbolInstance(A, dv0), + new PSymbolInstance(A, dv0)); + + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, true, A, B); + ct.initialize(); + + boolean closed = ct.checkLocationClosedness(); + Assert.assertFalse(closed); + closed = ct.checkLocationClosedness(); +// Assert.assertFalse(closed); +// closed = ct.checkLocationClosedness(); + Assert.assertTrue(closed); + + boolean consistent = ct.checkLocationConsistency(); + Assert.assertTrue(consistent); + ct.expand(a1); + consistent = ct.checkLocationConsistency(); +// Assert.assertFalse(consistent); +// consistent = ct.checkLocationConsistency(); + Assert.assertTrue(consistent); + + ct.expand(a1a2); + closed = ct.checkLocationClosedness(); + Assert.assertFalse(closed); + consistent = ct.checkLocationConsistency(); + Assert.assertFalse(consistent); + + ct.sift(a1a0); + ct.expand(a1a0); + consistent = ct.checkLocationConsistency(); + Assert.assertFalse(consistent); + consistent = ct.checkLocationConsistency(); + Assert.assertTrue(consistent); + consistent = ct.checkTransitionConsistency(); + Assert.assertTrue(consistent); + + ct.sift(a1a2a2); + ct.sift(a1a0a0); + consistent = ct.checkLocationConsistency(); + Assert.assertTrue(consistent); + consistent = ct.checkTransitionConsistency(); + Assert.assertFalse(consistent); + } + + private RegisterAutomaton buildLocationConsistencyAutomaton() { + MutableRegisterAutomaton ra = new MutableRegisterAutomaton(); + + RALocation l0 = ra.addInitialState(true); + RALocation l1 = ra.addState(true); + RALocation l2 = ra.addState(true); + RALocation l3 = ra.addState(true); + RALocation l4 = ra.addState(false); +// RALocation l5 = ra.addState(false); + + Register r1 = new Register(DT, 1); + Parameter p1 = new Parameter(DT, 1); + + Expression gT = ExpressionUtil.TRUE; + Expression gGE = NumericBooleanExpression.create(p1, NumericComparator.GE, r1); + Expression gLt = NumericBooleanExpression.create(p1, NumericComparator.LT, r1); + Expression gEq = NumericBooleanExpression.create(p1, NumericComparator.EQ, r1); + Expression gNE = NumericBooleanExpression.create(p1, NumericComparator.NE, r1); + + VarMapping storeP1 = new VarMapping<>(); + storeP1.put(r1, p1); + VarMapping storeR1 = new VarMapping<>(); + storeR1.put(r1, r1); + + Assignment assP1 = new Assignment(storeP1); + Assignment assR1 = new Assignment(storeR1); + Assignment assNo = new Assignment(new VarMapping<>()); + + ra.addTransition(l0, A, new InputTransition(gT, A, l0, l1, assP1)); + ra.addTransition(l0, B, new InputTransition(gT, B, l0, l0, assNo)); + + ra.addTransition(l1, A, new InputTransition(gGE, A, l1, l2, assP1)); + ra.addTransition(l1, A, new InputTransition(gLt, A, l1, l3, assP1)); + ra.addTransition(l1, B, new InputTransition(gT, B, l1, l0, assNo)); + + ra.addTransition(l2, A, new InputTransition(gEq, A, l2, l4, assNo)); + ra.addTransition(l2, A, new InputTransition(gNE, A, l2, l0, assNo)); + ra.addTransition(l2, B, new InputTransition(gT, B, l2, l4, assNo)); + + ra.addTransition(l3, A, new InputTransition(gEq, A, l3, l1, assR1)); + ra.addTransition(l3, A, new InputTransition(gNE, A, l3, l0, assNo)); + ra.addTransition(l3, B, new InputTransition(gT, B, l3, l4, assNo)); + + ra.addTransition(l4, A, new InputTransition(gT, A, l4, l4, assNo)); + ra.addTransition(l4, B, new InputTransition(gT, B, l4, l4, assNo)); +// ra.addTransition(l5, A, new InputTransition(gT, A, l5, l5, assNo)); +// ra.addTransition(l5, B, new InputTransition(gT, B, l5, l5, assNo)); + + return ra; + } + + @Test + public void testRegisterConsistency() { + RegisterAutomaton sul = buildRegisterConsistencyAutomaton(); + DataWordOracle dwOracle = new SimulatorOracle(sul); + + final Map teachers = new LinkedHashMap<>(); + IntegerEqualityTheory iet = new IntegerEqualityTheory(T_INT); + iet.setUseSuffixOpt(false); + teachers.put(T_INT, iet); + + Constants consts = new Constants(); + + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); + OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); + + ConstraintSolver solver = TestUtil.getZ3Solver(); + MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( + dwOracle, teachers, consts, solver); + + System.out.println(sul); + + DataValue dv0 = new DataValue(T_INT, BigDecimal.ZERO); + DataValue dv1 = new DataValue(T_INT, BigDecimal.ONE); + DataValue dv2 = new DataValue(T_INT, BigDecimal.valueOf(2)); + DataValue dv3 = new DataValue(T_INT, BigDecimal.valueOf(3)); + + Word b0 = Word.fromSymbols(new PSymbolInstance(BETA, dv0)); + Word a0 = Word.fromSymbols(new PSymbolInstance(ALPHA, dv0)); + Word a0a1 = Word.fromSymbols( + new PSymbolInstance(ALPHA, dv0), + new PSymbolInstance(ALPHA, dv1)); + Word a0b1 = Word.fromSymbols( + new PSymbolInstance(ALPHA, dv0), + new PSymbolInstance(BETA, dv1)); + Word a0a1a0 = Word.fromSymbols( + new PSymbolInstance(ALPHA, dv0), + new PSymbolInstance(ALPHA, dv1), + new PSymbolInstance(ALPHA, dv0)); + Word a0a1b2 = Word.fromSymbols( + new PSymbolInstance(ALPHA, dv0), + new PSymbolInstance(ALPHA, dv1), + new PSymbolInstance(BETA, dv2)); + Word b2b1 = Word.fromSymbols( + new PSymbolInstance(BETA, dv2), + new PSymbolInstance(BETA, dv1)); + + SymbolicSuffix sa = new SymbolicSuffix(RaStar.EMPTY_PREFIX, a0); + SymbolicSuffix sb = new SymbolicSuffix(RaStar.EMPTY_PREFIX, b0); + SymbolicSuffix sab = new SymbolicSuffix(RaStar.EMPTY_PREFIX, a0b1); + SymbolicSuffix sbb = new SymbolicSuffix(a0a1, b2b1); + + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, false, ALPHA, BETA); + ct.initialize(); + + ct.refine(ct.getLeaf(RaStar.EMPTY_PREFIX), sa); + ct.refine(ct.getLeaf(RaStar.EMPTY_PREFIX), sb); + ct.refine(ct.getLeaf(RaStar.EMPTY_PREFIX), sab); + + ct.sift(a0a1a0); + ct.sift(a0a1); + ct.sift(a0); + ct.sift(b0); + + Assert.assertEquals(ct.getLeaves().size(), 5); + for (int i = 0; i < ct.getLeaves().size(); i++) { + Assert.assertFalse(ct.checkLocationClosedness()); + } + Assert.assertTrue(ct.checkLocationClosedness()); + + boolean consistent = ct.checkRegisterConsistency(); + Assert.assertFalse(consistent); + consistent = ct.checkRegisterConsistency(); + Assert.assertTrue(consistent); + + Assert.assertTrue(ct.getLeaf(a0a1) + .getRepresentativePrefix() + .getPath() + .getSDTs() + .keySet() + .contains(sbb)); + } + + private RegisterAutomaton buildRegisterConsistencyAutomaton() { + MutableRegisterAutomaton ra = new MutableRegisterAutomaton(); + + RALocation l0 = ra.addInitialState(false); + RALocation l1 = ra.addState(false); + RALocation l2 = ra.addState(false); + RALocation l3 = ra.addState(true); + RALocation ls = ra.addState(false); + + Register r1 = new Register(T_INT, 1); + Register r2 = new Register(T_INT, 2); + Parameter p1 = new Parameter(T_INT, 1); + + Expression gT = ExpressionUtil.TRUE; + Expression gEqR1 = NumericBooleanExpression.create(p1, NumericComparator.EQ, r1); + Expression gEqR2 = NumericBooleanExpression.create(p1, NumericComparator.EQ, r2); + Expression gNER1 = NumericBooleanExpression.create(p1, NumericComparator.NE, r1); + Expression gNER1R2 = ExpressionUtil.and( + NumericBooleanExpression.create(p1, NumericComparator.NE, r1), + NumericBooleanExpression.create(p1, NumericComparator.NE, r2)); + + VarMapping storeP1inR1 = new VarMapping<>(); + storeP1inR1.put(r1, p1); + VarMapping storeP1inR2 = new VarMapping<>(); + storeP1inR2.put(r2, p1); + VarMapping storeP1inR2andR2inR1 = new VarMapping<>(); + storeP1inR2andR2inR1.put(r1, p1); + storeP1inR2andR2inR1.put(r2, r1); + VarMapping storeR2inR1 = new VarMapping<>(); + storeR2inR1.put(r1, r2); + + Assignment assP1inR1 = new Assignment(storeP1inR1); + Assignment assP1inR2 = new Assignment(storeP1inR2); + Assignment assP1inR1andR2inR1 = new Assignment(storeP1inR2andR2inR1); + Assignment assR2inR1 = new Assignment(storeR2inR1); + Assignment assNo = new Assignment(new VarMapping<>()); + + ra.addTransition(l0, ALPHA, new InputTransition(gT, ALPHA, l0, l1, assP1inR1)); + ra.addTransition(l0, BETA, new InputTransition(gT, BETA, l0, ls, assNo)); + + ra.addTransition(l1, ALPHA, new InputTransition(gT, ALPHA, l1, l2, assP1inR2)); + ra.addTransition(l1, BETA, new InputTransition(gNER1, BETA, l1, l2, assP1inR1andR2inR1)); + ra.addTransition(l1, BETA, new InputTransition(gEqR1, BETA, l1, l3, assNo)); + + ra.addTransition(l2, ALPHA, new InputTransition(gEqR1, ALPHA, l2, l3, assNo)); + ra.addTransition(l2, ALPHA, new InputTransition(gEqR2, ALPHA, l2, l3, assNo)); + ra.addTransition(l2, ALPHA, new InputTransition(gNER1R2, ALPHA, l2, ls, assNo)); + ra.addTransition(l2, BETA, new InputTransition(gT, BETA, l2, l1, assR2inR1)); + + ra.addTransition(l3, ALPHA, new InputTransition(gT, ALPHA, l3, ls, assNo)); + ra.addTransition(l3, BETA, new InputTransition(gT, BETA, l3, ls, assNo)); + + ra.addTransition(ls, ALPHA, new InputTransition(gT, ALPHA, ls, ls, assNo)); + ra.addTransition(ls, BETA, new InputTransition(gT, BETA, ls, ls, assNo)); + + return ra; + } +} diff --git a/src/test/java/de/learnlib/ralib/ct/CTTest.java b/src/test/java/de/learnlib/ralib/ct/CTTest.java new file mode 100644 index 00000000..4e90d9d6 --- /dev/null +++ b/src/test/java/de/learnlib/ralib/ct/CTTest.java @@ -0,0 +1,364 @@ +package de.learnlib.ralib.ct; + +import static de.learnlib.ralib.example.priority.PriorityQueueOracle.OFFER; +import static de.learnlib.ralib.example.priority.PriorityQueueOracle.POLL; +import static de.learnlib.ralib.example.priority.PriorityQueueOracle.doubleType; +import static de.learnlib.ralib.example.stack.StackAutomatonExample.AUTOMATON; +import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_POP; +import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_PUSH; +import static de.learnlib.ralib.example.stack.StackAutomatonExample.T_INT; +import static org.testng.Assert.assertEquals; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import de.learnlib.ralib.TestUtil; +import de.learnlib.ralib.automata.Assignment; +import de.learnlib.ralib.automata.InputTransition; +import de.learnlib.ralib.automata.MutableRegisterAutomaton; +import de.learnlib.ralib.automata.RALocation; +import de.learnlib.ralib.automata.RegisterAutomaton; +import de.learnlib.ralib.automata.output.OutputMapping; +import de.learnlib.ralib.automata.output.OutputTransition; +import de.learnlib.ralib.data.Constants; +import de.learnlib.ralib.data.DataType; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.SymbolicDataValue; +import de.learnlib.ralib.data.SymbolicDataValue.Parameter; +import de.learnlib.ralib.data.SymbolicDataValue.Register; +import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; +import de.learnlib.ralib.data.VarMapping; +import de.learnlib.ralib.learning.Hypothesis; +import de.learnlib.ralib.learning.SymbolicSuffix; +import de.learnlib.ralib.oracles.DataWordOracle; +import de.learnlib.ralib.oracles.SimulatorOracle; +import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; +import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; +import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; +import de.learnlib.ralib.smt.ConstraintSolver; +import de.learnlib.ralib.theory.Theory; +import de.learnlib.ralib.tools.theories.DoubleInequalityTheory; +import de.learnlib.ralib.tools.theories.IntegerEqualityTheory; +import de.learnlib.ralib.words.OutputSymbol; +import de.learnlib.ralib.words.PSymbolInstance; +import gov.nasa.jpf.constraints.api.Expression; +import gov.nasa.jpf.constraints.expressions.NumericBooleanExpression; +import gov.nasa.jpf.constraints.expressions.NumericComparator; +import gov.nasa.jpf.constraints.util.ExpressionUtil; +import net.automatalib.word.Word; + +public class CTTest { + private final OutputSymbol YES = new OutputSymbol("yes"); + private final OutputSymbol NO = new OutputSymbol("no"); + + @Test + public void testStackCT() { + Map teachers = new LinkedHashMap<>(); + teachers.put(T_INT, new IntegerEqualityTheory(T_INT)); + + Constants consts = new Constants(); + + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); + OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); + + RegisterAutomaton sul = AUTOMATON; + DataWordOracle dwOracle = new SimulatorOracle(sul); + ConstraintSolver solver = new ConstraintSolver(); + + MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(dwOracle, teachers, consts, solver); + + DataValue dv0 = new DataValue(T_INT, BigDecimal.ZERO); + DataValue dv1 = new DataValue(T_INT, BigDecimal.ONE); + DataValue dv2 = new DataValue(T_INT, BigDecimal.valueOf(2)); + + PSymbolInstance push0 = new PSymbolInstance(I_PUSH, dv0); + PSymbolInstance push1 = new PSymbolInstance(I_PUSH, dv1); + PSymbolInstance pop0 = new PSymbolInstance(I_POP, dv0); + PSymbolInstance pop1 = new PSymbolInstance(I_POP, dv1); + + Word w1 = Word.fromSymbols(push0); + Word w2 = Word.fromSymbols(pop0); + Word w3 = Word.fromSymbols(push0, push1); + Word w4 = Word.fromSymbols(push0, pop0); + Word w5 = Word.fromSymbols(push0, push1, pop1); + + SymbolicSuffix s1 = new SymbolicSuffix(w1, Word.fromSymbols(push1)); + SymbolicSuffix s2 = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(push0, push1)); + SymbolicSuffix s3 = new SymbolicSuffix(w1, Word.fromSymbols(pop0)); + SymbolicSuffix s4 = new SymbolicSuffix(w2, Word.fromSymbols(pop1, pop0)); + + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, false, I_PUSH, I_POP); + + ct.sift(Word.epsilon()); +// ct.expand(Word.epsilon()); + boolean consistent = ct.checkLocationClosedness(); + Assert.assertFalse(consistent); + Assert.assertEquals(ct.getLeaves().size(), 2); + Assert.assertEquals(ct.getPrefixes().size(), 3); + + consistent = ct.checkLocationClosedness(); + Assert.assertFalse(consistent); + consistent = ct.checkLocationClosedness(); + Assert.assertTrue(consistent); + + ct.expand(w1); +// ct.expand(w2); + Assert.assertEquals(ct.getLeaves().size(), 2); + Assert.assertEquals(ct.getPrefixes().size(), 7); + + ct.refine(ct.getLeaf(w3), s1); + Assert.assertEquals(ct.getLeaves().size(), 3); + Assert.assertEquals(ct.getPrefixes().size(), 7); + + consistent = ct.checkLocationClosedness(); + Assert.assertFalse(consistent); + + ct.refine(ct.getLeaf(w1), s2); + Assert.assertEquals(ct.getLeaves().size(), 4); + Assert.assertEquals(ct.getPrefixes().size(), 9); + + ct.refine(ct.getLeaf(w1), s3); +// ct.sift(w4); + consistent = ct.checkTransitionClosedness(); + Assert.assertFalse(consistent); + Assert.assertEquals(ct.getLeaves().size(), 4); + Assert.assertEquals(ct.getPrefixes().size(), 10); + Assert.assertTrue(ct.getLeaf(Word.epsilon()).getPrefixes().contains(w4)); + + ct.refine(ct.getLeaf(w3), s3); +// ct.expand(w3); + consistent = ct.checkTransitionClosedness(); + Assert.assertFalse(consistent); + Assert.assertEquals(ct.getLeaves().size(), 4); + Assert.assertEquals(ct.getPrefixes().size(), 11); + Assert.assertTrue(ct.getLeaf(w1).getPrefixes().contains(w5)); + +// Register r1 = new Register(T_INT, 1); +// Register r2 = new Register(T_INT, 2); +// ct.refine(ct.getLeaf(w3), s4); + consistent = ct.checkRegisterClosedness(); + Assert.assertFalse(consistent); + Assert.assertTrue(ct.getLeaf(w3).getRepresentativePrefix().getRegisters().contains(dv0)); + Assert.assertTrue(ct.getLeaf(w3).getRepresentativePrefix().getRegisters().contains(dv1)); + + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, false); + Hypothesis hyp = ab.buildHypothesis(); + + Assert.assertEquals(hyp.getStates().size(), 4); + Assert.assertEquals(hyp.getTransitions().size(), 10); + Assert.assertEquals(hyp.getAccessSequences().size(), hyp.getStates().size()); + } + + @Test + public void testPQCT() { + DataWordOracle dwOracle = new de.learnlib.ralib.example.priority.PriorityQueueOracle(2); + + final Map teachers = new LinkedHashMap<>(); + teachers.put(doubleType, new DoubleInequalityTheory(doubleType)); + + Constants consts = new Constants(); + + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); + OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); + + ConstraintSolver solver = TestUtil.getZ3Solver(); + MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( + dwOracle, teachers, new Constants(), solver); + + DataValue dv0 = new DataValue(doubleType, BigDecimal.ZERO); + DataValue dv1 = new DataValue(doubleType, BigDecimal.ONE); + DataValue dv2 = new DataValue(doubleType, BigDecimal.valueOf(2)); + + PSymbolInstance offer0 = new PSymbolInstance(OFFER, dv0); + PSymbolInstance offer1 = new PSymbolInstance(OFFER, dv1); + PSymbolInstance offer2 = new PSymbolInstance(OFFER, dv2); + PSymbolInstance poll0 = new PSymbolInstance(POLL, dv0); + PSymbolInstance poll1 = new PSymbolInstance(POLL, dv1); + PSymbolInstance poll2 = new PSymbolInstance(POLL, dv2); + + Word o1 = Word.fromSymbols(offer1); + Word o1o2 = Word.fromSymbols(offer1, offer2); + Word o1o1 = Word.fromSymbols(offer1, offer1); + Word o1o0 = Word.fromSymbols(offer1, offer0); + Word o1p1 = Word.fromSymbols(offer1, poll1); + Word o1o2p1 = Word.fromSymbols(offer1, offer2, poll1); + Word o1o0p0 = Word.fromSymbols(offer1, offer0, poll0); + + SymbolicSuffix s1 = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(offer1, poll1)); + SymbolicSuffix s2 = new SymbolicSuffix(o1, Word.fromSymbols(poll1)); + SymbolicSuffix s3 = new SymbolicSuffix(o1o2, Word.fromSymbols(poll1, poll2)); + + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, false, OFFER, POLL); + + ct.sift(Word.epsilon()); + ct.refine(ct.getLeaf(Word.epsilon()), s1); + ct.expand(Word.epsilon()); + Assert.assertEquals(ct.getLeaves().size(), 3); + + ct.expand(o1); + Assert.assertEquals(ct.getLeaves().size(), 4); + + ct.refine(ct.getLeaf(o1), s2); + ct.sift(o1p1); + + ct.refine(ct.getLeaf(o1o1), s3); + ct.expand(o1o1); + ct.expand(o1o0); + Assert.assertEquals(ct.getLeaves().size(), 5); + + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), false); + Hypothesis hyp = ab.buildHypothesis(); + + Assert.assertEquals(hyp.getStates().size(), ct.getLeaves().size()); + Assert.assertEquals(hyp.getTransitions().size(), ct.getPrefixes().size() - 1); + Assert.assertTrue(hyp.accepts(o1o2p1)); + Assert.assertTrue(hyp.accepts(o1o0p0));; + } + + @Test(enabled=false) + public void testCTAutomatonBuilder() { + RegisterAutomaton sul = buildTestRA(); + DataWordOracle dwOracle = new SimulatorOracle(sul); + + final Map teachers = new LinkedHashMap<>(); + teachers.put(doubleType, new DoubleInequalityTheory(doubleType)); + + Constants consts = new Constants(); + + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); + OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); + + ConstraintSolver solver = TestUtil.getZ3Solver(); + MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( + dwOracle, teachers, consts, solver); + + System.out.println(sul); + + DataValue dv0 = new DataValue(doubleType, BigDecimal.ZERO); + DataValue dv1 = new DataValue(doubleType, BigDecimal.ONE); + DataValue dv2 = new DataValue(doubleType, BigDecimal.valueOf(2)); + DataValue dv3 = new DataValue(doubleType, BigDecimal.valueOf(3)); + + PSymbolInstance offer0 = new PSymbolInstance(OFFER, dv0); + PSymbolInstance offer1 = new PSymbolInstance(OFFER, dv1); + PSymbolInstance offer2 = new PSymbolInstance(OFFER, dv2); + PSymbolInstance offer3 = new PSymbolInstance(OFFER, dv3); + PSymbolInstance yes = new PSymbolInstance(YES); + PSymbolInstance no = new PSymbolInstance(NO); + + Word o1 = Word.fromSymbols(offer1); + Word o1y = Word.fromSymbols(offer1, yes); + Word o1yo2 = Word.fromSymbols(offer1, yes, offer2); + Word o1yo2y = Word.fromSymbols(offer1, yes, offer2, yes); + Word o1yo2yo3 = Word.fromSymbols(offer1, yes, offer2, yes, offer3); + Word o1yo2yo2 = Word.fromSymbols(offer1, yes, offer2, yes, offer2); + Word o1yo2yo0 = Word.fromSymbols(offer1, yes, offer2, yes, offer0); + Word o1yo2yo3y = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes); + Word o1yo2yo2y = Word.fromSymbols(offer1, yes, offer2, yes, offer2, yes); + Word o1yo2yo0y = Word.fromSymbols(offer1, yes, offer2, yes, offer0, yes); + Word o1yo2yo3yo3 = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes, offer3); + Word o1yo2yo3yo2 = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes, offer2); + Word o1yo2yo3yo3y = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes, offer3, yes); + Word o1yo2yo3yo2n = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes, offer2, no); + + SymbolicSuffix sy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(yes)); + SymbolicSuffix sn = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(no)); + SymbolicSuffix so = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(offer1)); + SymbolicSuffix syoyoyoy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(yes, offer2, yes, offer3, yes, offer3, yes)); + SymbolicSuffix soyoyoy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(offer2, yes, offer3, yes, offer3, yes)); + SymbolicSuffix syoyoy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(yes, offer3, yes, offer3, yes)); + + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, true, OFFER, YES, NO); + + ct.sift(Word.epsilon()); + ct.refine(ct.getLeaf(Word.epsilon()), sn); + ct.refine(ct.getLeaf(Word.epsilon()), sy); + ct.refine(ct.getLeaf(Word.epsilon()), so); + ct.refine(ct.getLeaf(Word.epsilon()), syoyoyoy); + ct.expand(Word.epsilon()); + ct.refine(ct.getLeaf(Word.epsilon()), soyoyoy); + ct.expand(o1); + ct.refine(ct.getLeaf(o1), syoyoy); + ct.expand(o1y); + ct.expand(o1yo2); + ct.expand(o1yo2y); + ct.expand(o1yo2yo0); + ct.expand(o1yo2yo2); + ct.expand(o1yo2yo0y); + ct.expand(o1yo2yo2y); + + System.out.println(ct); + + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), true); + Hypothesis hyp = ab.buildHypothesis(); + + System.out.println(hyp); + } + + private RegisterAutomaton buildTestRA() { + MutableRegisterAutomaton ra = new MutableRegisterAutomaton(); + + RALocation l0i = ra.addInitialState(); + RALocation l0o = ra.addState(); + RALocation l1i = ra.addState(); + RALocation l1o = ra.addState(); + RALocation l2i = ra.addState(); + RALocation l2o = ra.addState(); + RALocation l3i = ra.addState(); + RALocation l3o1 = ra.addState(); + RALocation l3o2 = ra.addState(); + + Parameter p1 = new Parameter(doubleType, 1); + Register r1 = new Register(doubleType, 1); + Register r2 = new Register(doubleType, 2); + SuffixValue s1 = new SuffixValue(doubleType, 1); + + Expression gT = ExpressionUtil.TRUE; + Expression gL = new NumericBooleanExpression(r1, NumericComparator.LE, p1); + Expression gG = new NumericBooleanExpression(r1, NumericComparator.GE, p1); + Expression gEq = new NumericBooleanExpression(r1, NumericComparator.EQ, p1); + Expression gNe = new NumericBooleanExpression(r1, NumericComparator.NE, p1); + + VarMapping storeP1 = new VarMapping<>(); + storeP1.put(r1, p1); + VarMapping storeR1 = new VarMapping<>(); + storeR1.put(r1, r1); + VarMapping storeP1R1 = new VarMapping<>(); + storeP1R1.put(r1, p1); + storeP1R1.put(r2, r1); + VarMapping storeR1P1 = new VarMapping<>(); + storeR1P1.put(r1, r1); + storeR1P1.put(r2, p1); + VarMapping storeR1R1 = new VarMapping<>(); + storeR1R1.put(r1, r1); + storeR1R1.put(r2, r2); + VarMapping emptyMapping = new VarMapping<>(); + + Assignment assP1 = new Assignment(storeP1); + Assignment assR1 = new Assignment(storeR1); + Assignment assP1R1 = new Assignment(storeP1R1); + Assignment assR1P1 = new Assignment(storeR1P1); + Assignment assR1R1 = new Assignment(storeR1R1); + Assignment assNo = new Assignment(emptyMapping); + OutputMapping om = new OutputMapping(new ArrayList<>(), new VarMapping<>()); + + ra.addTransition(l0i, OFFER, new InputTransition(gT, OFFER, l0i, l0o, assNo)); + ra.addTransition(l0o, YES, new OutputTransition(gT, om, YES, l0o, l1i, assNo)); + ra.addTransition(l1i, OFFER, new InputTransition(gT, OFFER, l1i, l1o, assP1)); + ra.addTransition(l1o, YES, new OutputTransition(gT, om, YES, l1o, l2i, assR1)); + ra.addTransition(l2i, OFFER, new InputTransition(gL, OFFER, l2i, l2o, assR1P1)); + ra.addTransition(l2i, OFFER, new InputTransition(gG, OFFER, l2i, l2o, assP1R1)); + ra.addTransition(l2o, YES, new OutputTransition(gT, om, YES, l2o, l3i, assR1R1)); + ra.addTransition(l3i, OFFER, new InputTransition(gEq, OFFER, l3i, l3o1, assR1)); + ra.addTransition(l3o1, YES, new OutputTransition(gT, om, YES, l3o1, l1i, assNo)); + ra.addTransition(l3i, OFFER, new InputTransition(gNe, OFFER, l3i, l3o2, assNo)); + ra.addTransition(l3o2, YES, new OutputTransition(gT, om, NO, l3o2, l3i, assR1R1)); + + return ra; + } +} From 4b3ff4eab2ddbc09c588ebbe9f1b882af2240b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Thu, 4 Sep 2025 16:10:10 +0200 Subject: [PATCH 02/31] update out-of-date code and fix errors --- .../java/de/learnlib/ralib/ct/CTPath.java | 13 +- .../learnlib/ralib/ct/ClassificationTree.java | 133 ++++++++++-------- .../java/de/learnlib/ralib/ct/Prefix.java | 36 +++-- .../de/learnlib/ralib/data/Bijection.java | 30 ++++ .../ralib/learning/ralambda/SLCT.java | 28 ++-- .../de/learnlib/ralib/oracles/Branching.java | 31 ++++ .../learnlib/ralib/smt/ConstraintSolver.java | 2 +- .../java/de/learnlib/ralib/smt/SMTUtil.java | 6 +- .../learnlib/ralib/ct/CTConsistencyTest.java | 103 +++++++------- .../java/de/learnlib/ralib/ct/CTTest.java | 126 ++++++++++------- 10 files changed, 302 insertions(+), 206 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/ct/CTPath.java b/src/main/java/de/learnlib/ralib/ct/CTPath.java index fdd15b41..512195dd 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTPath.java +++ b/src/main/java/de/learnlib/ralib/ct/CTPath.java @@ -7,13 +7,10 @@ import de.learnlib.ralib.data.Bijection; import de.learnlib.ralib.data.DataValue; -import de.learnlib.ralib.data.SDTRelabeling; -import de.learnlib.ralib.data.SymbolicDataValue.Register; import de.learnlib.ralib.data.util.DataUtils; import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.learning.rastar.RaStar; import de.learnlib.ralib.oracles.TreeOracle; -import de.learnlib.ralib.oracles.TreeQueryResult; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.SDT; import de.learnlib.ralib.words.OutputSymbol; @@ -43,7 +40,7 @@ public MemorableSet getMemorable() { public SDT getSDT(SymbolicSuffix suffix) { return sdts.get(suffix); } - + public Map getSDTs() { return sdts; } @@ -66,7 +63,7 @@ public boolean isEquivalent(CTPath other, Bijection renaming, Constra SDT sdt1 = e.getValue(); SDT sdt2 = other.sdts.get(e.getKey()); - if (!sdt1.isEquivalent(sdt2.relabel(SDTRelabeling.fromBijection(renaming)), solver)) { + if (!sdt1.isEquivalent(sdt2, renaming)) { return false; } } @@ -106,7 +103,7 @@ private static boolean equalTypeSizes(Set s1, Set s2) { public static CTPath computePath(TreeOracle oracle, Prefix prefix, List suffixes, boolean ioMode) { CTPath r = new CTPath(ioMode); SDT sdt = prefix.getSDT(RaStar.EMPTY_SUFFIX); - sdt = sdt == null ? oracle.treeQuery(prefix, RaStar.EMPTY_SUFFIX).sdt() : sdt; + sdt = sdt == null ? oracle.treeQuery(prefix, RaStar.EMPTY_SUFFIX) : sdt; r.putSDT(RaStar.EMPTY_SUFFIX, sdt); for (SymbolicSuffix s : suffixes) { if (ioMode && s.getActions().length() > 0) { @@ -123,8 +120,8 @@ public static CTPath computePath(TreeOracle oracle, Prefix prefix, List outputs; + private final Constants consts; + private boolean ioMode; public ClassificationTree(TreeOracle oracle, ConstraintSolver solver, SymbolicSuffixRestrictionBuilder restrBuilder, OptimizedSymbolicSuffixBuilder suffixBuilder, + Constants consts, boolean ioMode, ParameterizedSymbol ... inputs) { this.oracle = oracle; @@ -66,6 +65,7 @@ public ClassificationTree(TreeOracle oracle, this.inputs = inputs; this.restrBuilder = restrBuilder; this.suffixBuilder = suffixBuilder; + this.consts = consts; prefixes = new LinkedHashMap<>(); shortPrefixes = new LinkedHashSet<>(); @@ -73,7 +73,7 @@ public ClassificationTree(TreeOracle oracle, root = new CTInnerNode(null, RaStar.EMPTY_SUFFIX); } - + private static List outputSuffixes(ParameterizedSymbol[] inputs) { List ret = new ArrayList<>(); for (ParameterizedSymbol ps : inputs) { @@ -91,7 +91,7 @@ public Set getLeaves() { public Set> getPrefixes() { return new LinkedHashSet<>(prefixes.keySet()); } - + // public Set> getShortPrefixes() { // return new LinkedHashSet<>(shortPrefixes); // } @@ -99,7 +99,7 @@ public Set> getPrefixes() { public CTLeaf getLeaf(Word u) { return prefixes.get(u); } - + public Set getExtensions(Word u) { Set extensions = new LinkedHashSet<>(); for (ParameterizedSymbol action : inputs) { @@ -140,7 +140,7 @@ public void refine(CTLeaf leaf, SymbolicSuffix suffix) { assert parent != null; Map, CTLeaf> leaves = parent.refine(leaf, suffix, oracle, solver, ioMode); prefixes.putAll(leaves); - + for (Word sp : shortPrefixes) { CTLeaf l = prefixes.get(sp); Prefix p = l.getPrefix(sp); @@ -149,11 +149,11 @@ public void refine(CTLeaf leaf, SymbolicSuffix suffix) { } } } - + public void initialize() { sift(RaStar.EMPTY_PREFIX); } - + public Set getShortPrefixes() { Set sp = new LinkedHashSet<>(); for (CTLeaf leaf : getLeaves()) { @@ -163,7 +163,7 @@ public Set getShortPrefixes() { assert sp.containsAll(shortPrefixes); return sp; } - + public CTInnerNode lca(CTNode n1, CTNode n2) { if (n1 == n2) { if (n1.isLeaf()) { @@ -173,10 +173,10 @@ public CTInnerNode lca(CTNode n1, CTNode n2) { } int h1 = height(n1); int h2 = height(n2); - + return lca(n1, h1, n2, h2); } - + private CTInnerNode lca(CTNode n1, int h1, CTNode n2, int h2) { if (n1 == n2) { assert n1 instanceof CTInnerNode; @@ -190,7 +190,7 @@ private CTInnerNode lca(CTNode n1, int h1, CTNode n2, int h2) { } return lca(n1.getParent(), h1 - 1, n2.getParent(), h2 - 1); } - + private int height(CTNode n) { int h = 0; while (n.getParent() != null) { @@ -199,14 +199,14 @@ private int height(CTNode n) { } return h; } - + public boolean checkOutputClosed() { if (!ioMode) { return true; } return checkOutputClosed(root); } - + private boolean checkOutputClosed(CTNode node) { if (node.isLeaf()) { CTLeaf leaf = (CTLeaf) node; @@ -227,9 +227,9 @@ private boolean checkOutputClosed(CTNode node) { } return true; } - + // CLOSEDNESS CHECKS - + public boolean checkLocationClosedness() { for (CTLeaf leaf : getLeaves()) { if (leaf.getShortPrefixes().isEmpty()) { @@ -239,7 +239,7 @@ public boolean checkLocationClosedness() { } return true; } - + public boolean checkTransitionClosedness() { for (CTLeaf leaf : getLeaves()) { for (ShortPrefix u : leaf.getShortPrefixes()) { @@ -255,7 +255,7 @@ public boolean checkTransitionClosedness() { } return true; } - + public boolean checkRegisterClosedness() { for (Map.Entry, CTLeaf> e : prefixes.entrySet()) { Word ua = e.getKey(); @@ -266,11 +266,11 @@ public boolean checkRegisterClosedness() { Word u = ua.prefix(ua.size() - 1); Prefix ua_pref = leaf.getPrefix(ua); CTLeaf u_leaf = prefixes.get(u); - + Set ua_mem = leaf.getPrefix(ua).getRegisters(); Set u_mem = prefixes.get(u).getPrefix(u).getRegisters(); Set a_mem = actionRegisters(ua); - + if (!consistentMemorable(ua_mem, u_mem, a_mem)) { for (SymbolicSuffix v : leaf.getSuffixes()) { Set s_mem = ua_pref.getSDT(v).getDataValues(); @@ -286,26 +286,26 @@ public boolean checkRegisterClosedness() { } return true; } - + private boolean consistentMemorable(Set ua_mem, Set u_mem, Set a_mem) { Set union = new LinkedHashSet<>(); union.addAll(u_mem); union.addAll(a_mem); return union.containsAll(ua_mem); } - + private Set actionRegisters(Word ua) { int ua_arity = DataWords.paramLength(DataWords.actsOf(ua)); int u_arity = ua_arity - ua.lastSymbol().getBaseSymbol().getArity(); DataValue[] vals = DataWords.valsOf(ua); - + Set regs = new LinkedHashSet<>(); for (int i = u_arity; i < ua_arity; i++) { regs.add(vals[i]); } return regs; } - + private DataValue[] missingRegisters(Set s_mem, Set u_mem, Set a_mem) { Set union = new LinkedHashSet<>(u_mem); union.addAll(a_mem); @@ -313,7 +313,7 @@ private DataValue[] missingRegisters(Set s_mem, Set u_mem, difference.removeAll(union); return difference.toArray(new DataValue[difference.size()]); } - + private SymbolicSuffix extendSuffix(Word ua, SymbolicSuffix v, DataValue[] missingRegs) { if (suffixBuilder == null) { PSymbolInstance a = ua.lastSymbol(); @@ -321,15 +321,15 @@ private SymbolicSuffix extendSuffix(Word ua, SymbolicSuffix v, SymbolicSuffix alpha = new SymbolicSuffix(u, Word.fromSymbols(a), restrBuilder); return alpha.concat(v); } - + SDT u_sdt = prefixes.get(ua).getPrefix(ua).getSDT(v); assert u_sdt != null : "SDT for symbolic suffix " + v + " does not exist for prefix " + ua; - + return suffixBuilder.extendSuffix(ua, u_sdt, v, missingRegs); } - + // CONSISTENCY CHECKS - + public boolean checkLocationConsistency() { for (CTLeaf l : getLeaves()) { Iterator sp = l.getShortPrefixes().iterator(); @@ -344,13 +344,13 @@ public boolean checkLocationConsistency() { Word ua = ue.getKey(); Expression g = ue.getValue(); Bijection gamma = u.getRpBijection().compose(uPrime.getRpBijection().inverse()); - + ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); Expression gammaG = rvv.apply(g, gamma.toVarMapping()); - - Optional> uPrimeA = uPrime.getBranching(action).getPrefix(gammaG, new Mapping<>(), solver); + + Optional> uPrimeA = uPrime.getBranching(action).getPrefix(gammaG, solver); assert uPrimeA.isPresent(); - + CTLeaf uALeaf = getLeaf(ua); CTLeaf uPrimeALeaf = getLeaf(uPrimeA.get()); if (uALeaf != uPrimeALeaf) { @@ -365,7 +365,7 @@ public boolean checkLocationConsistency() { } return true; } - + public boolean checkTransitionConsistency() { for (ShortPrefix u : getShortPrefixes()) { if (u.length() < 1) { @@ -397,7 +397,7 @@ public boolean checkTransitionConsistency() { } return true; } - + private Optional transitionConsistentA(Word uA, Word uB) { Word u = uA.prefix(uA.length() - 1); CTLeaf uALeaf = getLeaf(uA); @@ -411,22 +411,39 @@ private Optional transitionConsistentA(Word uA, } return Optional.empty(); } - + private Optional transitionConsistentB(Word uA, Word uB) { Prefix pA = getLeaf(uA).getPrefix(uA); Prefix pB = getLeaf(uB).getPrefix(uB); for (SymbolicSuffix v : getLeaf(uB).getSuffixes()) { - if (!SDT.equivalentUnderId(pA.getSDT(v), pB.getSDT(v), solver)) { + SDT sdtA = pA.getSDT(v).toRegisterSDT(uA, consts); + SDT sdtB = pB.getSDT(v).toRegisterSDT(uB, consts); + if (!SDT.equivalentUnderId(sdtA, sdtB)) { +// if (!SDT.equivalentUnderId(pA.getSDT(v), pB.getSDT(v))) { CTLeaf uLeaf = getLeaf(uA.prefix(uA.length() - 1)); assert uLeaf != null; - DataValue[] regs = inequivalentMapping(pA.getRpBijection(), pB.getRpBijection()); - SymbolicSuffix av = extendSuffix(uA, v, regs); + Register[] regs = inequivalentMapping(rpRegBijection(pA.getRpBijection(), pA), rpRegBijection(pB.getRpBijection(), pB)); + DataValue[] regVals = regsToDvs(regs, uA); + SymbolicSuffix av = extendSuffix(uA, v, regVals); return Optional.of(av); } } return Optional.empty(); } - + + private Bijection rpRegBijection(Bijection bijection, Word prefx) { + return Bijection.DVtoRegBijection(bijection, prefx, getLeaf(prefx).getRepresentativePrefix()); + } + + private DataValue[] regsToDvs(Register[] regs, Word prefix) { + DataValue[] vals = DataWords.valsOf(prefix); + DataValue[] ret = new DataValue[regs.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = vals[regs[i].getId()-1]; + } + return ret; + } + public boolean checkRegisterConsistency() { for (Prefix u : getShortPrefixes()) { if (u.length() < 2) { @@ -439,7 +456,7 @@ public boolean checkRegisterConsistency() { .iterator(); while (extensions.hasNext()) { Prefix ua = extensions.next(); - + RemappingIterator rit = new RemappingIterator<>(u.getRegisters(), u.getRegisters()); for (Bijection gamma : rit) { CTPath uPath = u.getPath(); @@ -447,7 +464,7 @@ public boolean checkRegisterConsistency() { for (Map.Entry e : ua.getPath().getSDTs().entrySet()) { SymbolicSuffix v = e.getKey(); SDT uaSDT = e.getValue(); - if (SDT.equivalentUnderBijection(uaSDT, uaSDT, gamma, solver) == null) { + if (SDT.equivalentUnderBijection(uaSDT, uaSDT, gamma) == null) { DataValue[] regs = gamma.keySet().toArray(new DataValue[gamma.size()]); SymbolicSuffix av = extendSuffix(ua, v, regs); refine(getLeaf(u), av); @@ -455,8 +472,8 @@ public boolean checkRegisterConsistency() { } } } - - + + // for (Map.Entry e : u.getPath().getSDTs().entrySet()) { // // is u equivalent to u for v under gamma? // SymbolicSuffix v = e.getKey(); @@ -464,7 +481,7 @@ public boolean checkRegisterConsistency() { // if (SDT.equivalentUnderBijection(uSDT, uSDT, gamma, solver) == null) { // continue; // } -// +// // // is ua equivalent to ua for v under (gamma union {regs(a) -> regs(a)]) // SDT uaSDT = ua.getSDT(v); // if (SDT.equivalentUnderBijection(uaSDT, uaSDT, gamma, solver) == null) { @@ -480,13 +497,13 @@ public boolean checkRegisterConsistency() { } return true; } - + private SymbolicSuffix extendSuffix(Word u1, Word u2, SymbolicSuffix v) { SDT sdt1 = getLeaf(u1).getPrefix(u1).getSDT(v); SDT sdt2 = getLeaf(u2).getPrefix(u2).getSDT(v); return suffixBuilder.extendDistinguishingSuffix(u1, sdt1, u2, sdt2, v); } - + private SuffixValuation actionValuation(Word ua) { SuffixValueGenerator svgen = new SuffixValueGenerator(); DataValue[] vals = ua.lastSymbol().getParameterValues(); @@ -497,7 +514,7 @@ private SuffixValuation actionValuation(Word ua) { } return valuation; } - + public Set> getExtensions(Word u, ParameterizedSymbol action) { assert u.length() > 0; return prefixes.keySet() @@ -506,19 +523,19 @@ public Set> getExtensions(Word u, Paramet .filter(w -> w.prefix(w.length() - 1).equals(u) && w.lastSymbol().getBaseSymbol().equals(action)) .collect(Collectors.toSet()); } - - private DataValue[] inequivalentMapping(Bijection a, Bijection b) { - Set ret = new LinkedHashSet<>(); - for (Map.Entry ea : a.entrySet()) { - DataValue key = ea.getKey(); + + private Register[] inequivalentMapping(Bijection a, Bijection b) { + Set ret = new LinkedHashSet<>(); + for (Map.Entry ea : a.entrySet()) { + Register key = ea.getKey(); if (!b.get(key).equals(ea.getValue())) { ret.add(key); ret.add(b.get(key)); } } - return ret.toArray(new DataValue[ret.size()]); + return ret.toArray(new Register[ret.size()]); } - + @Override public String toString() { StringBuilder builder = new StringBuilder(); diff --git a/src/main/java/de/learnlib/ralib/ct/Prefix.java b/src/main/java/de/learnlib/ralib/ct/Prefix.java index 6dfa7dad..90a36c46 100644 --- a/src/main/java/de/learnlib/ralib/ct/Prefix.java +++ b/src/main/java/de/learnlib/ralib/ct/Prefix.java @@ -2,11 +2,8 @@ import java.util.ArrayList; import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.Spliterator; import java.util.function.Function; @@ -15,7 +12,6 @@ import de.learnlib.ralib.data.Bijection; import de.learnlib.ralib.data.DataValue; import de.learnlib.ralib.data.RegisterAssignment; -import de.learnlib.ralib.data.SymbolicDataValue.Register; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator; import de.learnlib.ralib.learning.PrefixContainer; import de.learnlib.ralib.learning.SymbolicSuffix; @@ -39,7 +35,7 @@ public Prefix(Word u, Bijection rpRenaming, CTPath p } public Prefix(Word prefix, CTPath path) { - this(prefix, Bijection.id(path.getMemorable()), path); + this(prefix, Bijection.identity(path.getMemorable()), path); } public Prefix(Prefix prefix, Bijection rpRenaming) { @@ -85,7 +81,7 @@ public Bijection getRpBijection() { public MemorableSet getRegisters() { return path.getMemorable(); } - + public CTPath getPath() { return path; } @@ -101,12 +97,12 @@ public boolean equals(Object other) { // } // return ((Prefix) other).prefix.equals(prefix); } - + @Override public Word getPrefix() { return prefix; } - + @Override public RegisterAssignment getAssignment() { RegisterAssignment ra = new RegisterAssignment(); @@ -119,12 +115,12 @@ public RegisterAssignment getAssignment() { return ra; } - + @Override public int hashCode() { return prefix.hashCode(); } - + @Override public String toString() { return prefix.toString(); @@ -139,32 +135,32 @@ public int length() { public PSymbolInstance getSymbol(int index) { return prefix.getSymbol(index); } - + @Override public Iterator iterator() { return prefix.iterator(); } - + @Override public Spliterator spliterator() { return prefix.spliterator(); } - + @Override public void writeToArray(int offset, @Nullable Object[] array, int tgtOffset, int length) { prefix.writeToArray(offset, array, tgtOffset, length); } - + @Override public List asList() { return prefix.asList(); } - + @Override public PSymbolInstance lastSymbol() { return prefix.lastSymbol(); } - + @Override public Word append(PSymbolInstance symbol) { return prefix.append(symbol); @@ -174,22 +170,22 @@ public Word append(PSymbolInstance symbol) { public Word prepend(PSymbolInstance symbol) { return prefix.prepend(symbol); } - + @Override public boolean isPrefixOf(Word other) { return prefix.isPrefixOf(other); } - + @Override public Word longestCommonPrefix(Word other) { return prefix.longestCommonPrefix(other); } - + @Override public boolean isSuffixOf(Word other) { return prefix.isSuffixOf(other); } - + @Override public Word longestCommonSuffix(Word other) { return prefix.longestCommonSuffix(other); diff --git a/src/main/java/de/learnlib/ralib/data/Bijection.java b/src/main/java/de/learnlib/ralib/data/Bijection.java index 3c4c5d39..e86af73b 100644 --- a/src/main/java/de/learnlib/ralib/data/Bijection.java +++ b/src/main/java/de/learnlib/ralib/data/Bijection.java @@ -2,6 +2,11 @@ import java.util.*; +import de.learnlib.ralib.data.SymbolicDataValue.Register; +import de.learnlib.ralib.words.DataWords; +import de.learnlib.ralib.words.PSymbolInstance; +import net.automatalib.word.Word; + public class Bijection implements Map { @@ -148,4 +153,29 @@ private static void putAll(Map in, sur.put(val, key); } } + + public static Bijection DVtoRegBijection(Bijection bijection, Word keyWord, Word valueWord) { + DataValue[] keyVals = DataWords.valsOf(keyWord); + DataValue[] valueVals = DataWords.valsOf(valueWord); + Bijection ret = new Bijection<>(); + for (Map.Entry e : bijection.entrySet()) { + DataValue key = e.getKey(); + DataValue val = e.getValue(); + int keyId = findFirstDv(key, keyVals); + int valueId = findFirstDv(val, valueVals); + Register regKey = new Register(keyVals[keyId].getDataType(), keyId+1); + Register regValue = new Register(valueVals[valueId].getDataType(), valueId+1); + ret.put(regKey, regValue); + } + return ret; + } + + private static int findFirstDv(DataValue dv, DataValue[] vals) { + for (int i = 0; i < vals.length; i++) { + if (vals[i].equals(dv)) { + return i; + } + } + throw new IllegalArgumentException("No matching data value for " + dv + ": " + vals); + } } diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java index 2da7b1f6..e1fdd18e 100644 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java @@ -33,13 +33,13 @@ import net.automatalib.word.Word; public class SLCT implements RaLearningAlgorithm { - + private final ClassificationTree ct; - + private final Constants consts; private final Deque> counterexamples; - + private Hypothesis hyp; private final TreeOracle sulOracle; @@ -71,7 +71,7 @@ public SLCT(TreeOracle sulOracle, TreeOracleFactory hypOracleFactory, SDTLogicOr suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrictionBuilder); counterexamples = new LinkedList<>(); hyp = null; - ct = new ClassificationTree(sulOracle, solver, restrictionBuilder, suffixBuilder, ioMode, inputs); + ct = new ClassificationTree(sulOracle, solver, restrictionBuilder, suffixBuilder, consts, ioMode, inputs); ct.sift(RaStar.EMPTY_PREFIX); } @@ -81,14 +81,14 @@ public void learn() { while(!checkClosedness()); buildHypothesis(); } - + while(analyzeCounterExample()); - + if (queryStats != null) { queryStats.hypothesisConstructed(); } } - + private boolean checkClosedness() { if (!ct.checkOutputClosed()) { return false; @@ -104,12 +104,12 @@ private boolean checkClosedness() { } return true; } - + private void buildHypothesis() { CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, ioMode); hyp = ab.buildHypothesis(); } - + private boolean analyzeCounterExample() { LOGGER.info(Category.PHASE, "Analyzing Counterexample"); if (counterexamples.isEmpty()) { @@ -117,7 +117,7 @@ private boolean analyzeCounterExample() { } TreeOracle hypOracle = hypOracleFactory.createTreeOracle(hyp); - + Map, LocationComponent> components = new LinkedHashMap<>(); for (CTLeaf leaf : ct.getLeaves()) { // LeafComponent c = new LeafComponent(leaf); @@ -126,9 +126,9 @@ private boolean analyzeCounterExample() { } } CounterexampleAnalysis analysis = new CounterexampleAnalysis(sulOracle, hypOracle, hyp, sdtLogicOracle, components, consts); - + DefaultQuery ce = counterexamples.peek(); - + boolean hypce = hyp.accepts(ce.getInput()); boolean sulce = ce.getOutput(); if (hypce == sulce) { @@ -152,9 +152,9 @@ private boolean analyzeCounterExample() { CTLeaf leaf = ct.getLeaf(accSeq); assert leaf != null : "Prefix not in classification tree: " + accSeq; ct.refine(leaf, res.getSuffix()); - + while(!checkClosedness()); - + buildHypothesis(); return true; } diff --git a/src/main/java/de/learnlib/ralib/oracles/Branching.java b/src/main/java/de/learnlib/ralib/oracles/Branching.java index d8791606..1347f2e5 100644 --- a/src/main/java/de/learnlib/ralib/oracles/Branching.java +++ b/src/main/java/de/learnlib/ralib/oracles/Branching.java @@ -17,7 +17,13 @@ package de.learnlib.ralib.oracles; import java.util.Map; +import java.util.Optional; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.Mapping; +import de.learnlib.ralib.data.SymbolicDataValue; +import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; +import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.words.PSymbolInstance; import gov.nasa.jpf.constraints.api.Expression; import net.automatalib.word.Word; @@ -31,4 +37,29 @@ public interface Branching { Map, Expression> getBranches(); Word transformPrefix(Word prefix); + + default Optional> getPrefix(Expression guard, ConstraintSolver solver) { + Optional> prefix = getBranches().entrySet() + .stream() + .filter(e -> e.getValue().equals(guard)) + .map(e -> e.getKey()) + .findFirst(); + if (prefix.isPresent()) { + return prefix; + } + + for (Map.Entry, Expression> e : getBranches().entrySet()) { + DataValue[] vals = e.getKey().lastSymbol().getParameterValues(); + Mapping valuation = new Mapping<>(); + for (int i = 0; i < vals.length; i++) { + SuffixValue sv = new SuffixValue(vals[i].getDataType(), i+1); + valuation.put(sv, vals[i]); + } + if (solver.isSatisfiable(guard, valuation)) { + return Optional.of(e.getKey()); + } + } + + return Optional.empty(); + } } diff --git a/src/main/java/de/learnlib/ralib/smt/ConstraintSolver.java b/src/main/java/de/learnlib/ralib/smt/ConstraintSolver.java index b7701eea..5de5e884 100644 --- a/src/main/java/de/learnlib/ralib/smt/ConstraintSolver.java +++ b/src/main/java/de/learnlib/ralib/smt/ConstraintSolver.java @@ -37,7 +37,7 @@ public class ConstraintSolver { private final static gov.nasa.jpf.constraints.api.ConstraintSolver solver = new NativeZ3SolverProvider().createSolver(new Properties()); - public boolean isSatisfiable(Expression expr, Mapping val) { + public boolean isSatisfiable(Expression expr, Mapping val) { Expression test = SMTUtil.toExpression(expr, val); Boolean r = cache.get(test); if (r == null) { diff --git a/src/main/java/de/learnlib/ralib/smt/SMTUtil.java b/src/main/java/de/learnlib/ralib/smt/SMTUtil.java index 3c376e2d..43d99bb5 100644 --- a/src/main/java/de/learnlib/ralib/smt/SMTUtil.java +++ b/src/main/java/de/learnlib/ralib/smt/SMTUtil.java @@ -65,16 +65,16 @@ public static Expression valsToRegisters(Expression expr, Regi return replacer.applyRegs(expr, map); } - public static Expression toExpression(Expression expr, Mapping val) { + public static Expression toExpression(Expression expr, Mapping val) { Map map = new HashMap<>(); Expression valExpr = toExpression(val, map); return ExpressionUtil.and(expr, valExpr); } - public static Expression toExpression(Mapping val, Map map) { + public static Expression toExpression(Mapping val, Map map) { Expression[] elems = new Expression[val.size()]; int i = 0; - for (Map.Entry entry : val.entrySet()) { + for (Map.Entry entry : val.entrySet()) { elems[i++] = new NumericBooleanExpression(getOrCreate(entry.getKey(), map), NumericComparator.EQ, toConstant(entry.getValue())); } return ExpressionUtil.and(elems); diff --git a/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java b/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java index eda73309..bbe0644b 100644 --- a/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java +++ b/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java @@ -1,11 +1,9 @@ package de.learnlib.ralib.ct; -import static de.learnlib.ralib.example.priority.PriorityQueueOracle.OFFER; import static de.learnlib.ralib.example.stack.StackAutomatonExample.AUTOMATON; import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_POP; import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_PUSH; import static de.learnlib.ralib.example.stack.StackAutomatonExample.T_INT; -import static org.testng.Assert.assertFalse; import java.math.BigDecimal; import java.util.LinkedHashMap; @@ -41,7 +39,6 @@ import de.learnlib.ralib.tools.theories.IntegerEqualityTheory; import de.learnlib.ralib.words.InputSymbol; import de.learnlib.ralib.words.PSymbolInstance; -import de.learnlib.ralib.words.ParameterizedSymbol; import gov.nasa.jpf.constraints.api.Expression; import gov.nasa.jpf.constraints.expressions.NumericBooleanExpression; import gov.nasa.jpf.constraints.expressions.NumericComparator; @@ -49,11 +46,11 @@ import net.automatalib.word.Word; public class CTConsistencyTest extends RaLibTestSuite { - + private static DataType DT = new DataType("double"); private static InputSymbol A = new InputSymbol("a", new DataType[] {DT}); private static InputSymbol B = new InputSymbol("b"); - + private static InputSymbol ALPHA = new InputSymbol("α", new DataType[] {T_INT}); private static InputSymbol BETA = new InputSymbol("β", new DataType[] {T_INT}); @@ -64,7 +61,7 @@ public void testConsistencyStack() { teachers.put(T_INT, new IntegerEqualityTheory(T_INT)); Constants consts = new Constants(); - + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); @@ -94,30 +91,30 @@ public void testConsistencyStack() { SymbolicSuffix s3 = new SymbolicSuffix(pu0, Word.fromSymbols(pop0)); SymbolicSuffix s4 = new SymbolicSuffix(pu0pu1, Word.fromSymbols(pop1, pop0)); - ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, false, I_PUSH, I_POP); - + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, false, I_PUSH, I_POP); + ct.initialize(); boolean closed = ct.checkLocationClosedness(); closed = ct.checkLocationClosedness(); Assert.assertFalse(closed); - + ct.expand(pu0); closed = ct.checkLocationClosedness(); Assert.assertTrue(closed); - + ct.expand(pu0pu1); closed = ct.checkLocationClosedness(); Assert.assertTrue(closed); - + ct.refine(ct.getLeaf(pu0pu1), s1); boolean consistent = ct.checkLocationConsistency(); Assert.assertFalse(consistent); - + ct.sift(pu0po0); consistent = ct.checkTransitionConsistency(); Assert.assertFalse(consistent); } - + @Test public void testLocationConsistency() { RegisterAutomaton sul = buildLocationConsistencyAutomaton(); @@ -127,20 +124,20 @@ public void testLocationConsistency() { teachers.put(DT, new DoubleInequalityTheory(DT)); Constants consts = new Constants(); - + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); ConstraintSolver solver = TestUtil.getZ3Solver(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, consts, solver); - + System.out.println(sul); - + DataValue dv0 = new DataValue(DT, BigDecimal.ZERO); DataValue dv1 = new DataValue(DT, BigDecimal.ONE); DataValue dv2 = new DataValue(DT, BigDecimal.valueOf(2)); - + Word a1 = Word.fromSymbols(new PSymbolInstance(A, dv1)); Word a1a2 = Word.fromSymbols( new PSymbolInstance(A, dv1), @@ -157,16 +154,16 @@ public void testLocationConsistency() { new PSymbolInstance(A, dv0), new PSymbolInstance(A, dv0)); - ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, true, A, B); + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, true, A, B); ct.initialize(); - + boolean closed = ct.checkLocationClosedness(); Assert.assertFalse(closed); closed = ct.checkLocationClosedness(); // Assert.assertFalse(closed); // closed = ct.checkLocationClosedness(); Assert.assertTrue(closed); - + boolean consistent = ct.checkLocationConsistency(); Assert.assertTrue(consistent); ct.expand(a1); @@ -174,13 +171,13 @@ public void testLocationConsistency() { // Assert.assertFalse(consistent); // consistent = ct.checkLocationConsistency(); Assert.assertTrue(consistent); - + ct.expand(a1a2); closed = ct.checkLocationClosedness(); Assert.assertFalse(closed); consistent = ct.checkLocationConsistency(); Assert.assertFalse(consistent); - + ct.sift(a1a0); ct.expand(a1a0); consistent = ct.checkLocationConsistency(); @@ -189,7 +186,7 @@ public void testLocationConsistency() { Assert.assertTrue(consistent); consistent = ct.checkTransitionConsistency(); Assert.assertTrue(consistent); - + ct.sift(a1a2a2); ct.sift(a1a0a0); consistent = ct.checkLocationConsistency(); @@ -197,20 +194,20 @@ public void testLocationConsistency() { consistent = ct.checkTransitionConsistency(); Assert.assertFalse(consistent); } - + private RegisterAutomaton buildLocationConsistencyAutomaton() { MutableRegisterAutomaton ra = new MutableRegisterAutomaton(); - + RALocation l0 = ra.addInitialState(true); RALocation l1 = ra.addState(true); RALocation l2 = ra.addState(true); RALocation l3 = ra.addState(true); RALocation l4 = ra.addState(false); // RALocation l5 = ra.addState(false); - + Register r1 = new Register(DT, 1); Parameter p1 = new Parameter(DT, 1); - + Expression gT = ExpressionUtil.TRUE; Expression gGE = NumericBooleanExpression.create(p1, NumericComparator.GE, r1); Expression gLt = NumericBooleanExpression.create(p1, NumericComparator.LT, r1); @@ -221,34 +218,34 @@ private RegisterAutomaton buildLocationConsistencyAutomaton() { storeP1.put(r1, p1); VarMapping storeR1 = new VarMapping<>(); storeR1.put(r1, r1); - + Assignment assP1 = new Assignment(storeP1); Assignment assR1 = new Assignment(storeR1); Assignment assNo = new Assignment(new VarMapping<>()); - + ra.addTransition(l0, A, new InputTransition(gT, A, l0, l1, assP1)); ra.addTransition(l0, B, new InputTransition(gT, B, l0, l0, assNo)); - + ra.addTransition(l1, A, new InputTransition(gGE, A, l1, l2, assP1)); ra.addTransition(l1, A, new InputTransition(gLt, A, l1, l3, assP1)); ra.addTransition(l1, B, new InputTransition(gT, B, l1, l0, assNo)); - + ra.addTransition(l2, A, new InputTransition(gEq, A, l2, l4, assNo)); ra.addTransition(l2, A, new InputTransition(gNE, A, l2, l0, assNo)); ra.addTransition(l2, B, new InputTransition(gT, B, l2, l4, assNo)); - + ra.addTransition(l3, A, new InputTransition(gEq, A, l3, l1, assR1)); ra.addTransition(l3, A, new InputTransition(gNE, A, l3, l0, assNo)); ra.addTransition(l3, B, new InputTransition(gT, B, l3, l4, assNo)); - + ra.addTransition(l4, A, new InputTransition(gT, A, l4, l4, assNo)); ra.addTransition(l4, B, new InputTransition(gT, B, l4, l4, assNo)); // ra.addTransition(l5, A, new InputTransition(gT, A, l5, l5, assNo)); // ra.addTransition(l5, B, new InputTransition(gT, B, l5, l5, assNo)); - + return ra; } - + @Test public void testRegisterConsistency() { RegisterAutomaton sul = buildRegisterConsistencyAutomaton(); @@ -260,21 +257,21 @@ public void testRegisterConsistency() { teachers.put(T_INT, iet); Constants consts = new Constants(); - + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); ConstraintSolver solver = TestUtil.getZ3Solver(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, consts, solver); - + System.out.println(sul); - + DataValue dv0 = new DataValue(T_INT, BigDecimal.ZERO); DataValue dv1 = new DataValue(T_INT, BigDecimal.ONE); DataValue dv2 = new DataValue(T_INT, BigDecimal.valueOf(2)); DataValue dv3 = new DataValue(T_INT, BigDecimal.valueOf(3)); - + Word b0 = Word.fromSymbols(new PSymbolInstance(BETA, dv0)); Word a0 = Word.fromSymbols(new PSymbolInstance(ALPHA, dv0)); Word a0a1 = Word.fromSymbols( @@ -294,35 +291,35 @@ public void testRegisterConsistency() { Word b2b1 = Word.fromSymbols( new PSymbolInstance(BETA, dv2), new PSymbolInstance(BETA, dv1)); - + SymbolicSuffix sa = new SymbolicSuffix(RaStar.EMPTY_PREFIX, a0); SymbolicSuffix sb = new SymbolicSuffix(RaStar.EMPTY_PREFIX, b0); SymbolicSuffix sab = new SymbolicSuffix(RaStar.EMPTY_PREFIX, a0b1); SymbolicSuffix sbb = new SymbolicSuffix(a0a1, b2b1); - - ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, false, ALPHA, BETA); + + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, false, ALPHA, BETA); ct.initialize(); - + ct.refine(ct.getLeaf(RaStar.EMPTY_PREFIX), sa); ct.refine(ct.getLeaf(RaStar.EMPTY_PREFIX), sb); ct.refine(ct.getLeaf(RaStar.EMPTY_PREFIX), sab); - + ct.sift(a0a1a0); ct.sift(a0a1); ct.sift(a0); ct.sift(b0); - + Assert.assertEquals(ct.getLeaves().size(), 5); for (int i = 0; i < ct.getLeaves().size(); i++) { Assert.assertFalse(ct.checkLocationClosedness()); } Assert.assertTrue(ct.checkLocationClosedness()); - + boolean consistent = ct.checkRegisterConsistency(); Assert.assertFalse(consistent); consistent = ct.checkRegisterConsistency(); Assert.assertTrue(consistent); - + Assert.assertTrue(ct.getLeaf(a0a1) .getRepresentativePrefix() .getPath() @@ -330,16 +327,16 @@ public void testRegisterConsistency() { .keySet() .contains(sbb)); } - + private RegisterAutomaton buildRegisterConsistencyAutomaton() { MutableRegisterAutomaton ra = new MutableRegisterAutomaton(); - + RALocation l0 = ra.addInitialState(false); RALocation l1 = ra.addState(false); RALocation l2 = ra.addState(false); RALocation l3 = ra.addState(true); RALocation ls = ra.addState(false); - + Register r1 = new Register(T_INT, 1); Register r2 = new Register(T_INT, 2); Parameter p1 = new Parameter(T_INT, 1); @@ -361,13 +358,13 @@ private RegisterAutomaton buildRegisterConsistencyAutomaton() { storeP1inR2andR2inR1.put(r2, r1); VarMapping storeR2inR1 = new VarMapping<>(); storeR2inR1.put(r1, r2); - + Assignment assP1inR1 = new Assignment(storeP1inR1); Assignment assP1inR2 = new Assignment(storeP1inR2); Assignment assP1inR1andR2inR1 = new Assignment(storeP1inR2andR2inR1); Assignment assR2inR1 = new Assignment(storeR2inR1); Assignment assNo = new Assignment(new VarMapping<>()); - + ra.addTransition(l0, ALPHA, new InputTransition(gT, ALPHA, l0, l1, assP1inR1)); ra.addTransition(l0, BETA, new InputTransition(gT, BETA, l0, ls, assNo)); @@ -385,7 +382,7 @@ private RegisterAutomaton buildRegisterConsistencyAutomaton() { ra.addTransition(ls, ALPHA, new InputTransition(gT, ALPHA, ls, ls, assNo)); ra.addTransition(ls, BETA, new InputTransition(gT, BETA, ls, ls, assNo)); - + return ra; } } diff --git a/src/test/java/de/learnlib/ralib/ct/CTTest.java b/src/test/java/de/learnlib/ralib/ct/CTTest.java index 4e90d9d6..21de0c49 100644 --- a/src/test/java/de/learnlib/ralib/ct/CTTest.java +++ b/src/test/java/de/learnlib/ralib/ct/CTTest.java @@ -7,7 +7,6 @@ import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_POP; import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_PUSH; import static de.learnlib.ralib.example.stack.StackAutomatonExample.T_INT; -import static org.testng.Assert.assertEquals; import java.math.BigDecimal; import java.util.ArrayList; @@ -55,14 +54,14 @@ public class CTTest { private final OutputSymbol YES = new OutputSymbol("yes"); private final OutputSymbol NO = new OutputSymbol("no"); - + @Test public void testStackCT() { Map teachers = new LinkedHashMap<>(); teachers.put(T_INT, new IntegerEqualityTheory(T_INT)); Constants consts = new Constants(); - + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); @@ -92,7 +91,7 @@ public void testStackCT() { SymbolicSuffix s3 = new SymbolicSuffix(w1, Word.fromSymbols(pop0)); SymbolicSuffix s4 = new SymbolicSuffix(w2, Word.fromSymbols(pop1, pop0)); - ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, false, I_PUSH, I_POP); + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, false, I_PUSH, I_POP); ct.sift(Word.epsilon()); // ct.expand(Word.epsilon()); @@ -105,7 +104,7 @@ public void testStackCT() { Assert.assertFalse(consistent); consistent = ct.checkLocationClosedness(); Assert.assertTrue(consistent); - + ct.expand(w1); // ct.expand(w2); Assert.assertEquals(ct.getLeaves().size(), 2); @@ -114,7 +113,7 @@ public void testStackCT() { ct.refine(ct.getLeaf(w3), s1); Assert.assertEquals(ct.getLeaves().size(), 3); Assert.assertEquals(ct.getPrefixes().size(), 7); - + consistent = ct.checkLocationClosedness(); Assert.assertFalse(consistent); @@ -145,15 +144,15 @@ public void testStackCT() { Assert.assertFalse(consistent); Assert.assertTrue(ct.getLeaf(w3).getRepresentativePrefix().getRegisters().contains(dv0)); Assert.assertTrue(ct.getLeaf(w3).getRepresentativePrefix().getRegisters().contains(dv1)); - + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, false); Hypothesis hyp = ab.buildHypothesis(); - + Assert.assertEquals(hyp.getStates().size(), 4); Assert.assertEquals(hyp.getTransitions().size(), 10); Assert.assertEquals(hyp.getAccessSequences().size(), hyp.getStates().size()); } - + @Test public void testPQCT() { DataWordOracle dwOracle = new de.learnlib.ralib.example.priority.PriorityQueueOracle(2); @@ -162,14 +161,14 @@ public void testPQCT() { teachers.put(doubleType, new DoubleInequalityTheory(doubleType)); Constants consts = new Constants(); - + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); ConstraintSolver solver = TestUtil.getZ3Solver(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, new Constants(), solver); - + DataValue dv0 = new DataValue(doubleType, BigDecimal.ZERO); DataValue dv1 = new DataValue(doubleType, BigDecimal.ONE); DataValue dv2 = new DataValue(doubleType, BigDecimal.valueOf(2)); @@ -180,7 +179,7 @@ public void testPQCT() { PSymbolInstance poll0 = new PSymbolInstance(POLL, dv0); PSymbolInstance poll1 = new PSymbolInstance(POLL, dv1); PSymbolInstance poll2 = new PSymbolInstance(POLL, dv2); - + Word o1 = Word.fromSymbols(offer1); Word o1o2 = Word.fromSymbols(offer1, offer2); Word o1o1 = Word.fromSymbols(offer1, offer1); @@ -188,38 +187,67 @@ public void testPQCT() { Word o1p1 = Word.fromSymbols(offer1, poll1); Word o1o2p1 = Word.fromSymbols(offer1, offer2, poll1); Word o1o0p0 = Word.fromSymbols(offer1, offer0, poll0); - + SymbolicSuffix s1 = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(offer1, poll1)); SymbolicSuffix s2 = new SymbolicSuffix(o1, Word.fromSymbols(poll1)); SymbolicSuffix s3 = new SymbolicSuffix(o1o2, Word.fromSymbols(poll1, poll2)); - - ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, false, OFFER, POLL); - + + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, false, OFFER, POLL); + ct.sift(Word.epsilon()); - ct.refine(ct.getLeaf(Word.epsilon()), s1); - ct.expand(Word.epsilon()); - Assert.assertEquals(ct.getLeaves().size(), 3); - + boolean closed = ct.checkLocationClosedness(); + Assert.assertFalse(closed); + closed = ct.checkTransitionClosedness(); + Assert.assertTrue(closed); + closed = ct.checkLocationClosedness(); + Assert.assertFalse(closed); + ct.expand(o1); - Assert.assertEquals(ct.getLeaves().size(), 4); - - ct.refine(ct.getLeaf(o1), s2); ct.sift(o1p1); - - ct.refine(ct.getLeaf(o1o1), s3); - ct.expand(o1o1); - ct.expand(o1o0); - Assert.assertEquals(ct.getLeaves().size(), 5); - + boolean consistent = ct.checkTransitionConsistency(); + Assert.assertFalse(consistent); + + ct.expand(o1o2); + consistent = ct.checkLocationConsistency(); + Assert.assertFalse(consistent); + closed = ct.checkRegisterClosedness(); + Assert.assertFalse(closed); + + ct.sift(o1o0); + consistent = ct.checkTransitionConsistency(); + Assert.assertFalse(consistent); + + closed = ct.checkRegisterClosedness(); + Assert.assertTrue(closed); +// ct.sift(o1p1); + + +// ct.refine(ct.getLeaf(Word.epsilon()), s1); +// ct.expand(Word.epsilon()); +// Assert.assertEquals(ct.getLeaves().size(), 3); +// +// ct.expand(o1); +// Assert.assertEquals(ct.getLeaves().size(), 4); +// +// ct.refine(ct.getLeaf(o1), s2); +// ct.sift(o1p1); + +// ct.refine(ct.getLeaf(o1o1), s3); +// ct.expand(o1o1); +// ct.expand(o1o0); +// Assert.assertEquals(ct.getLeaves().size(), 5); + + + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), false); Hypothesis hyp = ab.buildHypothesis(); - + Assert.assertEquals(hyp.getStates().size(), ct.getLeaves().size()); Assert.assertEquals(hyp.getTransitions().size(), ct.getPrefixes().size() - 1); Assert.assertTrue(hyp.accepts(o1o2p1)); Assert.assertTrue(hyp.accepts(o1o0p0));; } - + @Test(enabled=false) public void testCTAutomatonBuilder() { RegisterAutomaton sul = buildTestRA(); @@ -229,14 +257,14 @@ public void testCTAutomatonBuilder() { teachers.put(doubleType, new DoubleInequalityTheory(doubleType)); Constants consts = new Constants(); - + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); ConstraintSolver solver = TestUtil.getZ3Solver(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, consts, solver); - + System.out.println(sul); DataValue dv0 = new DataValue(doubleType, BigDecimal.ZERO); @@ -250,7 +278,7 @@ public void testCTAutomatonBuilder() { PSymbolInstance offer3 = new PSymbolInstance(OFFER, dv3); PSymbolInstance yes = new PSymbolInstance(YES); PSymbolInstance no = new PSymbolInstance(NO); - + Word o1 = Word.fromSymbols(offer1); Word o1y = Word.fromSymbols(offer1, yes); Word o1yo2 = Word.fromSymbols(offer1, yes, offer2); @@ -265,16 +293,16 @@ public void testCTAutomatonBuilder() { Word o1yo2yo3yo2 = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes, offer2); Word o1yo2yo3yo3y = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes, offer3, yes); Word o1yo2yo3yo2n = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes, offer2, no); - + SymbolicSuffix sy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(yes)); SymbolicSuffix sn = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(no)); SymbolicSuffix so = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(offer1)); SymbolicSuffix syoyoyoy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(yes, offer2, yes, offer3, yes, offer3, yes)); SymbolicSuffix soyoyoy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(offer2, yes, offer3, yes, offer3, yes)); SymbolicSuffix syoyoy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(yes, offer3, yes, offer3, yes)); - - ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, true, OFFER, YES, NO); - + + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, true, OFFER, YES, NO); + ct.sift(Word.epsilon()); ct.refine(ct.getLeaf(Word.epsilon()), sn); ct.refine(ct.getLeaf(Word.epsilon()), sy); @@ -291,18 +319,18 @@ public void testCTAutomatonBuilder() { ct.expand(o1yo2yo2); ct.expand(o1yo2yo0y); ct.expand(o1yo2yo2y); - + System.out.println(ct); - + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), true); Hypothesis hyp = ab.buildHypothesis(); - + System.out.println(hyp); } - + private RegisterAutomaton buildTestRA() { MutableRegisterAutomaton ra = new MutableRegisterAutomaton(); - + RALocation l0i = ra.addInitialState(); RALocation l0o = ra.addState(); RALocation l1i = ra.addState(); @@ -312,18 +340,18 @@ private RegisterAutomaton buildTestRA() { RALocation l3i = ra.addState(); RALocation l3o1 = ra.addState(); RALocation l3o2 = ra.addState(); - + Parameter p1 = new Parameter(doubleType, 1); Register r1 = new Register(doubleType, 1); Register r2 = new Register(doubleType, 2); SuffixValue s1 = new SuffixValue(doubleType, 1); - + Expression gT = ExpressionUtil.TRUE; Expression gL = new NumericBooleanExpression(r1, NumericComparator.LE, p1); Expression gG = new NumericBooleanExpression(r1, NumericComparator.GE, p1); Expression gEq = new NumericBooleanExpression(r1, NumericComparator.EQ, p1); Expression gNe = new NumericBooleanExpression(r1, NumericComparator.NE, p1); - + VarMapping storeP1 = new VarMapping<>(); storeP1.put(r1, p1); VarMapping storeR1 = new VarMapping<>(); @@ -338,7 +366,7 @@ private RegisterAutomaton buildTestRA() { storeR1R1.put(r1, r1); storeR1R1.put(r2, r2); VarMapping emptyMapping = new VarMapping<>(); - + Assignment assP1 = new Assignment(storeP1); Assignment assR1 = new Assignment(storeR1); Assignment assP1R1 = new Assignment(storeP1R1); @@ -346,7 +374,7 @@ private RegisterAutomaton buildTestRA() { Assignment assR1R1 = new Assignment(storeR1R1); Assignment assNo = new Assignment(emptyMapping); OutputMapping om = new OutputMapping(new ArrayList<>(), new VarMapping<>()); - + ra.addTransition(l0i, OFFER, new InputTransition(gT, OFFER, l0i, l0o, assNo)); ra.addTransition(l0o, YES, new OutputTransition(gT, om, YES, l0o, l1i, assNo)); ra.addTransition(l1i, OFFER, new InputTransition(gT, OFFER, l1i, l1o, assP1)); @@ -358,7 +386,7 @@ private RegisterAutomaton buildTestRA() { ra.addTransition(l3o1, YES, new OutputTransition(gT, om, YES, l3o1, l1i, assNo)); ra.addTransition(l3i, OFFER, new InputTransition(gNe, OFFER, l3i, l3o2, assNo)); ra.addTransition(l3o2, YES, new OutputTransition(gT, om, NO, l3o2, l3i, assR1R1)); - + return ra; } } From 7f37b3dac8354717ddce3df8b7b73143b895434d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Wed, 5 Nov 2025 16:47:54 +0100 Subject: [PATCH 03/31] add sllambda algorithm and replace ralambda with sllambda --- .../automata/MutableRegisterAutomaton.java | 37 + .../de/learnlib/ralib/automata/RARun.java | 63 ++ .../ralib/ceanalysis/PrefixFinder.java | 518 +++++---- .../ralib/ceanalysis/PrefixFinderResult.java | 6 + .../learnlib/ralib/ct/CTAutomatonBuilder.java | 137 ++- .../learnlib/ralib/ct/ClassificationTree.java | 87 +- .../ralib/data/RegisterAssignment.java | 14 +- src/main/java/de/learnlib/ralib/dt/DT.java | 6 +- .../ralib/learning/ralambda/RaLambda.java | 1000 ++++++++--------- .../ralib/learning/ralambda/SLCT.java | 7 +- .../ralib/learning/ralambda/SLLambda.java | 213 ++++ .../de/learnlib/ralib/oracles/Branching.java | 9 + .../learnlib/ralib/smt/ConstraintSolver.java | 12 + .../java/de/learnlib/ralib/theory/Theory.java | 8 + .../ralib/theory/equality/EqualityTheory.java | 39 + .../inequality/InequalityTheoryWithEq.java | 56 + .../learnlib/ralib/tools/ClassAnalyzer.java | 12 +- .../de/learnlib/ralib/tools/IOSimulator.java | 12 +- .../theories/UniqueIntegerEqualityTheory.java | 10 + .../ralib/RaLibLearningExperimentRunner.java | 12 +- .../de/learnlib/ralib/automata/RaRunTest.java | 80 ++ .../ralib/ceanalysis/PrefixFinderTest.java | 251 ++++- .../java/de/learnlib/ralib/ct/CTTest.java | 6 +- .../ralambda/GeneratedHypothesesTest.java | 141 +-- .../learning/ralambda/IOHandlingTest.java | 39 +- .../learning/ralambda/LearnABPOutputTest.java | 13 +- .../learning/ralambda/LearnEchoTest.java | 3 +- .../learning/ralambda/LearnLoginTest.java | 20 +- .../learning/ralambda/LearnMixedIOTest.java | 13 +- .../learning/ralambda/LearnPQIOTest.java | 14 +- .../ralib/learning/ralambda/LearnPQTest.java | 19 +- .../ralib/learning/ralambda/LearnPadlock.java | 15 +- .../ralambda/LearnPalindromeIOTest.java | 15 +- .../learning/ralambda/LearnRepeaterTest.java | 4 +- .../learning/ralambda/LearnSipIOTest.java | 13 +- .../learning/ralambda/LearnStackTest.java | 91 +- .../TestDistinguishingSuffixOptimization.java | 9 +- .../learning/ralambda/TestOutputSuffixes.java | 11 +- .../learning/ralambda/TestQueryCount.java | 16 +- .../ralambda/TestSuffixOptimization.java | 10 +- .../ralib/learning/ralambda/TestSymmetry.java | 12 +- .../ralambda/TestUnknownMemorable.java | 39 +- 42 files changed, 1986 insertions(+), 1106 deletions(-) create mode 100644 src/main/java/de/learnlib/ralib/automata/RARun.java create mode 100644 src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinderResult.java create mode 100644 src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java create mode 100644 src/test/java/de/learnlib/ralib/automata/RaRunTest.java diff --git a/src/main/java/de/learnlib/ralib/automata/MutableRegisterAutomaton.java b/src/main/java/de/learnlib/ralib/automata/MutableRegisterAutomaton.java index 9604c225..74392ab5 100644 --- a/src/main/java/de/learnlib/ralib/automata/MutableRegisterAutomaton.java +++ b/src/main/java/de/learnlib/ralib/automata/MutableRegisterAutomaton.java @@ -300,4 +300,41 @@ public Transition copyTransition(Transition t, RALocation s) { throw new UnsupportedOperationException("Not supported yet."); } + public RARun getRun(Word word) { + int n = word.length(); + RALocation[] locs = new RALocation[n+1]; + RegisterValuation[] vals = new RegisterValuation[n+1]; + PSymbolInstance[] symbols = new PSymbolInstance[n]; + + locs[0] = getInitialState(); + vals[0] = new RegisterValuation(); + + for (int i = 0; i < n; i++) { + symbols[i] = word.getSymbol(i); + ParameterValuation pars = ParameterValuation.fromPSymbolInstance(symbols[i]); + + Collection candidates = locs[i].getOut(symbols[i].getBaseSymbol()); + if (candidates == null) { + return null; + } + + boolean found = false; + + for (Transition t : candidates) { + if (t.isEnabled(vals[i], pars, constants)) { + vals[i+1] = t.execute(vals[i], pars, constants); + locs[i+1] = t.getDestination(); + found = true; + break; + } + } + + if (!found) { + return null; + } + } + + return new RARun(locs, vals, symbols); + } + } diff --git a/src/main/java/de/learnlib/ralib/automata/RARun.java b/src/main/java/de/learnlib/ralib/automata/RARun.java new file mode 100644 index 00000000..d9c82cba --- /dev/null +++ b/src/main/java/de/learnlib/ralib/automata/RARun.java @@ -0,0 +1,63 @@ +package de.learnlib.ralib.automata; + +import java.util.ArrayList; + +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.RegisterValuation; +import de.learnlib.ralib.words.PSymbolInstance; + +public class RARun { + + private final RALocation[] locations; + private final RegisterValuation[] valuations; + private final PSymbolInstance[] transitions; + + public RARun(RALocation[] locations, RegisterValuation[] valuations, PSymbolInstance[] transitions) { + this.locations = locations; + this.valuations = valuations; + this.transitions = transitions; + } + + public RALocation getLocation(int i) { + return locations[i]; + } + + public RegisterValuation getValuation(int i) { + return valuations[i]; + } + + public PSymbolInstance getTransition(int i) { + return transitions[i-1]; + } + + public DataValue[] getDataValues(int i) { + ArrayList vals = new ArrayList<>(); + for (int id = 0; id < i; id++) { + for (DataValue dv : transitions[id].getParameterValues()) { + vals.add(dv); + } + } + return vals.toArray(new DataValue[vals.size()]); + } + + @Override + public String toString() { + if (locations.length == 0) { + return "ε"; + } + + String str = "<" + locations[0] + ", " + valuations[0] + ">"; + for (int i = 1; i < locations.length; i++) { + str = str + + " -- " + + transitions[i-1] + + " -- <" + + locations[i] + + ", " + + valuations[i] + + ">"; + } + + return str; + } +} diff --git a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java index 0f73dc13..ed077f08 100644 --- a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java +++ b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java @@ -1,26 +1,44 @@ package de.learnlib.ralib.ceanalysis; -import java.util.*; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import de.learnlib.logging.Category; -import de.learnlib.query.DefaultQuery; -import de.learnlib.ralib.data.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import de.learnlib.ralib.automata.RALocation; +import de.learnlib.ralib.automata.RARun; +import de.learnlib.ralib.ct.CTHypothesis; +import de.learnlib.ralib.ct.CTLeaf; +import de.learnlib.ralib.ct.ClassificationTree; +import de.learnlib.ralib.ct.Prefix; +import de.learnlib.ralib.ct.ShortPrefix; +import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.data.Constants; +import de.learnlib.ralib.data.DataType; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.Mapping; +import de.learnlib.ralib.data.RegisterValuation; +import de.learnlib.ralib.data.SymbolicDataValue; import de.learnlib.ralib.data.SymbolicDataValue.Parameter; +import de.learnlib.ralib.data.SymbolicDataValue.Register; import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; +import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.SuffixValueGenerator; +import de.learnlib.ralib.data.util.PermutationIterator; import de.learnlib.ralib.data.util.RemappingIterator; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; -import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.SuffixValueGenerator; -import de.learnlib.ralib.learning.*; -import de.learnlib.ralib.learning.rastar.CEAnalysisResult; -import de.learnlib.ralib.oracles.SDTLogicOracle; +import de.learnlib.ralib.learning.SymbolicSuffix; +import de.learnlib.ralib.oracles.Branching; import de.learnlib.ralib.oracles.TreeOracle; import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; -import de.learnlib.ralib.smt.SMTUtil; -import de.learnlib.ralib.theory.Memorables; +import de.learnlib.ralib.smt.ConstraintSolver; +import de.learnlib.ralib.smt.ReplacingValuesVisitor; import de.learnlib.ralib.theory.SDT; +import de.learnlib.ralib.theory.Theory; +import de.learnlib.ralib.words.DataWords; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; import gov.nasa.jpf.constraints.api.Expression; @@ -29,262 +47,266 @@ public class PrefixFinder { - private final TreeOracle sulOracle; - - private TreeOracle hypOracle; - - private Hypothesis hypothesis; - - private final SDTLogicOracle sdtOracle; - - private final SymbolicSuffixRestrictionBuilder restrictionBuilder; - - private final Constants consts; - - private SymbolicWord[] candidates; - - private final Map candidateCEs = new LinkedHashMap(); - private final Map storedQueries = new LinkedHashMap(); - - private static final Logger LOGGER = LoggerFactory.getLogger(PrefixFinder.class); - - public PrefixFinder(TreeOracle sulOracle, TreeOracle hypOracle, - Hypothesis hypothesis, SDTLogicOracle sdtOracle, - Constants consts) { - - this.sulOracle = sulOracle; - this.hypOracle = hypOracle; - this.hypothesis = hypothesis; - this.sdtOracle = sdtOracle; - this.consts = consts; - this.restrictionBuilder = sulOracle.getRestrictionBuilder(); - } - - public CEAnalysisResult analyzeCounterexample(Word ce) { - int idx = findIndex(ce); - SymbolicWord sw = new SymbolicWord(candidates[idx].getPrefix(), candidates[idx].getSuffix()); - SDT tqr = null; //storedQueries.get(sw); - if (tqr == null) { - // THIS CAN (possibly) BE DONE WITHOUT A NEW TREE QUERY - tqr = sulOracle.treeQuery(sw.getPrefix(), sw.getSuffix()); - } - CEAnalysisResult result = new CEAnalysisResult(candidates[idx].getPrefix(), - candidates[idx].getSuffix(), - tqr); - - candidateCEs.put(candidates[idx], tqr); - storeCandidateCEs(ce, idx); - - return result; - } - - private int findIndex(Word ce) { - candidates = new SymbolicWord[ce.length()]; - int max = ce.length() - 1; - for (int idx=max; idx>=0; idx = idx-1) { + public enum ResultType { + TRANSITION, + LOCATION + } - Word prefix = ce.prefix(idx); - Word nextPrefix = ce.prefix(idx+1); + public record Result(Word prefix, ResultType result) {}; - LOGGER.trace(Category.DATASTRUCTURE, "idx: {} ce: {}", idx, ce); - LOGGER.trace(Category.DATASTRUCTURE, "idx: {} prefix: {}", idx, prefix); - LOGGER.trace(Category.DATASTRUCTURE, "idx: {} next: {}", idx, nextPrefix); + private final CTHypothesis hyp; + private final ClassificationTree ct; - // check for location counterexample ... - // - Word suffix = ce.suffix(ce.length() - nextPrefix.length()); - SymbolicSuffix symSuffix = new SymbolicSuffix(nextPrefix, suffix, restrictionBuilder); - LOC_CHECK: for (Word u : hypothesis.possibleAccessSequences(prefix)) { - Word uAlpha = hypothesis.transformTransitionSequence(nextPrefix, u); - SDT uAlphaResult = sulOracle.treeQuery(uAlpha, symSuffix); - storedQueries.put(new SymbolicWord(uAlpha, symSuffix), uAlphaResult); + private final TreeOracle sulOracle; + private final Map teachers; - // check if the word is inequivalent to all access sequences - // - for (Word uPrime : hypothesis.possibleAccessSequences(nextPrefix)) { - SDT uPrimeResult = sulOracle.treeQuery(uPrime, symSuffix); - storedQueries.put(new SymbolicWord(uPrime, symSuffix), uPrimeResult); + private final SymbolicSuffixRestrictionBuilder restrBuilder; - LOGGER.trace(Category.DATASTRUCTURE, "idx: {} u: {}", idx, u); - LOGGER.trace(Category.DATASTRUCTURE, "idx: {} ua: {}", idx, uAlpha); - LOGGER.trace(Category.DATASTRUCTURE, "idx: {} u': {}", idx, uPrime); - LOGGER.trace(Category.DATASTRUCTURE, "idx: {} v: {}", idx, symSuffix); + private final ConstraintSolver solver; - // different sizes - // - if (!Memorables.typedSize(uPrimeResult.getDataValues()).equals( - Memorables.typedSize(uAlphaResult.getDataValues()))) { - continue; - } + private final Constants consts; - // remapping - // - RemappingIterator iterator = new RemappingIterator<>( - uPrimeResult.getDataValues(), uAlphaResult.getDataValues()); + public PrefixFinder(TreeOracle sulOracle, CTHypothesis hyp, ClassificationTree ct, + Map teachers, SymbolicSuffixRestrictionBuilder restrBuilder, + ConstraintSolver solver, Constants consts) { + this.hyp = hyp; + this.ct = ct; + this.sulOracle = sulOracle; + this.teachers = teachers; + this.restrBuilder = restrBuilder; + this.solver = solver; + this.consts = consts; + } - for (Bijection m : iterator) { - if (uAlphaResult.isEquivalent(uPrimeResult, m)) { - continue LOC_CHECK; + public Result analyzeCounterExample(Word ce) { + RARun run = hyp.getRun(ce); + for (int i = ce.length(); i >= 1; i--) { + RALocation loc = run.getLocation(i-1); + RALocation locNext = run.getLocation(i); + PSymbolInstance symbol = run.getTransition(i); + RegisterValuation mu = run.getValuation(i-1); + ParameterizedSymbol action = symbol.getBaseSymbol(); + + SymbolicSuffix vNext = new SymbolicSuffix(ce.prefix(i), ce.suffix(ce.length() - i), restrBuilder); + SymbolicSuffix v = new SymbolicSuffix(ce.prefix(i-1), ce.suffix(ce.length() - i + 1), restrBuilder); + + Optional> gOpt = getHypGuard(run, i); + assert gOpt.isPresent() : "No guard satisfying valuation at index " + i; + Expression gHyp = gOpt.get(); + + for (ShortPrefix u : hyp.getLeaf(loc).getShortPrefixes()) { + SDT sdt = sulOracle.treeQuery(u, v); + Set uVals = hyp.getLeaf(loc).getPrefix(u).getRegisters(); + Mapping muRenaming = valuationRenaming(u, mu); + Set> renamings = extendedValuationRenamings(sdt, uVals, run, i); + Branching branching = sulOracle.getInitialBranching(u, action, sdt); + for (Expression gSul : branching.guardSet()) { + for (Mapping renaming : renamings) { + renaming.putAll(muRenaming); + if (isGuardSatisfied(gSul, renaming, symbol)) { + Optional res = checkTransition(locNext, u, action, vNext, gHyp, gSul); + if (res.isEmpty()) { + res = checkLocation(locNext, u, action, vNext); + } + if (res.isPresent()) { + return res.get(); + } } } - } - // found a counterexample! - candidates[idx] = new SymbolicWord(uAlpha, symSuffix); - LOGGER.trace(Category.COUNTEREXAMPLE, "Counterexample for location"); - return idx; } + } - // check for transition counterexample ... - // - if (transitionHasCE(ce, idx-1)) { - LOGGER.trace(Category.COUNTEREXAMPLE, "Counterexample for transition"); - return idx; + throw new IllegalStateException("Found no counterexample in " + ce); + } + + /* + * Generate a mapping from the register valuation of u on the hypothesis to val + */ + private Mapping valuationRenaming(Word u, RegisterValuation val) { + RARun uRun = hyp.getRun(u); + RegisterValuation uVal = uRun.getValuation(u.size()); + Mapping ret = new Mapping<>(); + for (Map.Entry e : uVal.entrySet()) { + DataValue replace = e.getValue(); + DataValue by = val.get(e.getKey()); + if (by == null) { + by = replace; } +// assert by != null; + ret.put(replace, by); } - throw new RuntimeException("should not reach here"); + return ret; } - -// private Pair checkForCE(Word prefix, SymbolicSuffix suffix, Word transition) { -// SymbolicWord symWord = new SymbolicWord(prefix, suffix); -// SDT resHyp = hypOracle.treeQuery(prefix, suffix); -// SDT resSul; -// if (storedQueries.containsKey(symWord)) -// resSul = storedQueries.get(symWord); -// else { -// resSul = sulOracle.treeQuery(prefix, suffix); -// storedQueries.put(symWord, resSul); -// } -// -// boolean hasCE = sdtOracle.hasCounterexample(prefix, -// resHyp.getSdt(), resHyp.getPiv(), -// resSul.getSdt(), resSul.getPiv(), -// new TransitionGuard(), transition); -// -// return hasCE ? new ImmutablePair(resHyp, resSul) : null; -// } - - private boolean transitionHasCE(Word ce, int idx) { - if (idx+1 >= ce.length()) - return false; - - Word prefix = ce.prefix(idx+1); - - Word suffix = ce.suffix(ce.length() - (idx+1)); - SymbolicSuffix symSuffix = new SymbolicSuffix(prefix, suffix, restrictionBuilder); - - Set> locations = hypothesis.possibleAccessSequences(prefix); - for (Word location : locations) { - Word transition = hypothesis.transformTransitionSequence( - ce.prefix(idx+2), location); - - SDT resHyp = hypOracle.treeQuery(location, symSuffix); - SDT resSul; - SymbolicWord symWord = new SymbolicWord(location, symSuffix); - if (storedQueries.containsKey(symWord)) - resSul = storedQueries.get(symWord); - else { - resSul = sulOracle.treeQuery(location, symSuffix); - storedQueries.put(symWord, resSul); - } - - boolean hasCE = sdtOracle.hasCounterexample(location, - resHyp, - resSul, - ExpressionUtil.TRUE, transition); - - if (hasCE) { - SymbolicWord sw = candidate(location, symSuffix, resSul, resHyp, ce); - // new by falk - candidates[idx+1] = sw; - return true; + + private Set> extendedValuationRenamings(SDT uSDT, Set uValuation, RARun run, int id) { + Set> identity = new LinkedHashSet<>(); + identity.add(new Mapping<>()); + if (id <= 1) { + return identity; + } + Set sdtVals = new LinkedHashSet<>(uSDT.getDataValues()); + for (DataValue d : uValuation) { + sdtVals.remove(d); + } + if (sdtVals.isEmpty()) { + return identity; + } + DataValue[] sdtValsArr = sdtVals.toArray(new DataValue[sdtVals.size()]); + + ArrayList runVals = new ArrayList<>(); + for (int i = 1; i <= id-1; i++) { + for (DataValue d : run.getTransition(i).getParameterValues()) { + runVals.add(d); } - } - return false; - } - - private void storeCandidateCEs(Word ce, int idx) { - if (idx+1 >= ce.length()) - return; - Word prefix = ce.prefix(idx+1); - - Word suffix = ce.suffix(ce.length() - (idx+1)); - SymbolicSuffix symSuffix = new SymbolicSuffix(prefix, suffix, restrictionBuilder); - - Set> locations = hypothesis.possibleAccessSequences(prefix); - for (Word location : locations) { - SymbolicWord symWord = new SymbolicWord(location, symSuffix); - SDT tqr = storedQueries.get(symWord); - - assert tqr != null; - - candidateCEs.put(symWord, tqr); - } - } - - private SymbolicWord candidate(Word prefix, - SymbolicSuffix symSuffix, SDT sdtSul, - SDT sdtHyp, Word ce) { - Word candidate = null; - - Expression expr = sdtOracle.getCEGuard(prefix, sdtSul, sdtHyp); - - Map, Boolean> sulPaths = sulOracle.instantiate(prefix, symSuffix, sdtSul); - for (Word path : sulPaths.keySet()) { - ParameterGenerator parGen = new ParameterGenerator(); - for (PSymbolInstance psi : prefix) { - for (DataType dt : psi.getBaseSymbol().getPtypes()) - parGen.next(dt); - } - - VarMapping renaming = new VarMapping<>(); - SuffixValueGenerator svGen = new SuffixValueGenerator(); - for (ParameterizedSymbol ps : symSuffix.getActions()) { - for (DataType dt : ps.getPtypes()) { - Parameter p = parGen.next(dt); - SuffixValue sv = svGen.next(dt); - renaming.put(sv, p); - } - } - Expression exprR = SMTUtil.renameVars(expr, renaming); - - ParameterValuation pars = ParameterValuation.fromPSymbolWord(path); - Mapping vals = new Mapping<>(); - vals.putAll(pars); - vals.putAll(consts); + } + for (DataValue d : run.getValuation(id-1).values()) { + runVals = removeFirst(runVals, d); + } + + Set> renamings = new LinkedHashSet<>(); + PermutationIterator permit = new PermutationIterator(runVals.size()); + for (int[] order : permit) { + Mapping remapping = new Mapping<>(); + boolean valid = true; + for (int i = 0; i < sdtValsArr.length; i++) { + DataValue sdtVal = sdtValsArr[i]; + DataValue runVal = runVals.get(order[i]); + if (!sdtVal.getDataType().equals(runVal.getDataType())) { + valid = false; + break; + } + remapping.put(sdtVal, runVal); + } + if (valid) { + renamings.add(remapping); + } + } + + return renamings; + } + + private ArrayList removeFirst(ArrayList list, DataValue d) { + ArrayList ret = new ArrayList<>(); + ret.addAll(list); + for (int i = 0; i < list.size(); i++) { + if (list.get(i).equals(d)) { + ret.remove(i); + break; + } + } + return ret; + } - if (exprR.evaluateSMT(SMTUtil.compose(vals))) { - candidate = path.prefix(prefix.length() + 1); - SymbolicSuffix suffix = new SymbolicSuffix(candidate, ce.suffix(symSuffix.length() - 1), restrictionBuilder); - return new SymbolicWord(candidate, suffix); - } + private Optional checkTransition(RALocation loc_i, + ShortPrefix u, + ParameterizedSymbol action, + SymbolicSuffix vi, + Expression gi, + Expression giPrime) { + ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); + Expression giRenamed = rvv.apply(gi, u.getRpBijection().inverse().toVarMapping()); + Expression con = ExpressionUtil.and(giRenamed, giPrime); + + DataType[] types = action.getPtypes(); + DataValue[] reprDataVals = new DataValue[types.length]; + Set prior = new LinkedHashSet<>(); + for (int i = 0; i < types.length; i++) { + reprDataVals[i] = teachers.get(types[i]).instantiate(u, action, prior, consts, con, i+1, solver); + prior.add(reprDataVals[i]); } - throw new IllegalStateException("No CE transition found"); - } + PSymbolInstance psi = new PSymbolInstance(action, reprDataVals); + Word uExtSul = u.append(psi); + + CTLeaf leaf_i = hyp.getLeaf(loc_i); + Iterator> extensions = ct.getExtensions(u, action) + .stream() + .filter(w -> leaf_i.getPrefixes().contains(w)) + .iterator(); + while (extensions.hasNext()) { + Word uExtHyp = extensions.next(); // u_{i-1}\alpha_i(d_i') + SDT uExtHypSDT = sulOracle.treeQuery(uExtHyp, vi).toRegisterSDT(uExtHyp, consts); + SDT uExtSulSDT = sulOracle.treeQuery(uExtSul, vi).toRegisterSDT(uExtSul, consts); +// assert false : "Remember to convert SDTs to register SDTs"; + + if (SDT.equivalentUnderId(uExtHypSDT, uExtSulSDT)) { + return Optional.empty(); + } + } - public Set> getCounterExamples() { - Set> ces = new LinkedHashSet>(); - for (Map.Entry e : candidateCEs.entrySet()) { - SymbolicWord sw = e.getKey(); - SDT tqr = e.getValue(); - Map, Boolean> cemaps = sulOracle.instantiate(sw.getPrefix(), sw.getSuffix(), tqr); - for (Map.Entry, Boolean> c : cemaps.entrySet()) { - ces.add(new DefaultQuery(c.getKey(), c.getValue())); - } - } + Result res = new Result(uExtSul, ResultType.TRANSITION); + return Optional.of(res); + } - return ces; - } + private Optional checkLocation(RALocation loc_i, + Word u, + ParameterizedSymbol action, + SymbolicSuffix vi) { + CTLeaf leaf_i = hyp.getLeaf(loc_i); + Iterator extensions = ct.getExtensions(u, action) + .stream() + .filter(w -> leaf_i.getPrefixes().contains(w)) + .map(w -> leaf_i.getPrefix(w)) + .iterator(); + while (extensions.hasNext()) { + Prefix uExt = extensions.next(); + Bijection uExtBi = uExt.getRpBijection(); + boolean noEquivUi = true; + for (Prefix ui : leaf_i.getShortPrefixes()) { + Bijection uiBi = ui.getRpBijection(); + Bijection gamma = uiBi.compose(uExtBi.inverse()); + SDT uExtSDT = sulOracle.treeQuery(uExt, vi); + SDT uiSDT = sulOracle.treeQuery(ui, vi); + if (SDT.equivalentUnderBijection(uiSDT, uExtSDT, gamma) != null) { + noEquivUi = false; + break; + } + } + if (noEquivUi) { + Result res = new Result(uExt, ResultType.LOCATION); + return Optional.of(res); + } + } - public void setHypothesisTreeOracle(TreeOracle hypOracle) { - this.hypOracle = hypOracle; - } + return Optional.empty(); + } - public void setHypothesis(Hypothesis hyp) { - this.hypothesis = hyp; - } + private Optional> getHypGuard(RARun run, int idx) { + RALocation locNext = run.getLocation(idx); + RALocation loc = run.getLocation(idx - 1); + CTLeaf leafNext = hyp.getLeaf(locNext); + RegisterValuation mu = run.getValuation(idx-1); + PSymbolInstance a = run.getTransition(idx); +// ShortPrefix rp = (ShortPrefix) hyp.getLeaf(loc).getRepresentativePrefix(); + ShortPrefix sp = hyp.getLeaf(loc).getShortPrefixes().iterator().next(); + Mapping renaming = valuationRenaming(sp, mu); + for (Word ua : ct.getExtensions(sp, a.getBaseSymbol())) { + if (leafNext.getPrefixes().contains(ua)) { +// Expression g = sp.getBranching(a.getBaseSymbol()).getBranches().get(ua); + for (Expression g : sp.getBranching(a.getBaseSymbol()).getBranches().values()) { + if (isGuardSatisfied(g, renaming, a)) { + return Optional.of(g); + } + } + } + } + return Optional.empty(); + } - //public void setComponents(Map, LocationComponent> components) { - // this.components = components; - //} + private boolean isGuardSatisfied(Expression guard, Mapping renaming, PSymbolInstance symbol) { + Mapping mapping = new Mapping<>(); + DataValue[] vals = symbol.getParameterValues(); + ParameterGenerator pgen = new ParameterGenerator(); + + ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); + Expression guardRenamed = rvv.apply(guard, renaming); + + for (int i = 0; i < vals.length; i++) { + Parameter p = pgen.next(vals[i].getDataType()); + mapping.put(p, vals[i]); + } + mapping.putAll(consts); + + return solver.isSatisfiable(guardRenamed, mapping); + } } diff --git a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinderResult.java b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinderResult.java new file mode 100644 index 00000000..ac7a5180 --- /dev/null +++ b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinderResult.java @@ -0,0 +1,6 @@ +package de.learnlib.ralib.ceanalysis; + +public enum PrefixFinderResult { + TRANSITION, + LOCATION +} diff --git a/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java index 92ce51b7..aaef57dc 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java +++ b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java @@ -1,14 +1,11 @@ package de.learnlib.ralib.ct; -import java.util.ArrayList; -import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; -import de.learnlib.logging.Category; import de.learnlib.ralib.automata.Assignment; import de.learnlib.ralib.automata.RALocation; import de.learnlib.ralib.automata.Transition; @@ -18,20 +15,21 @@ import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.Mapping; +import de.learnlib.ralib.data.ParameterValuation; import de.learnlib.ralib.data.RegisterAssignment; +import de.learnlib.ralib.data.RegisterValuation; import de.learnlib.ralib.data.SymbolicDataValue; import de.learnlib.ralib.data.SymbolicDataValue.Parameter; import de.learnlib.ralib.data.SymbolicDataValue.Register; import de.learnlib.ralib.data.VarMapping; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; -import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.RegisterGenerator; import de.learnlib.ralib.learning.AutomatonBuilder; import de.learnlib.ralib.learning.Hypothesis; import de.learnlib.ralib.learning.rastar.RaStar; import de.learnlib.ralib.oracles.Branching; +import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.smt.ReplacingValuesVisitor; -import de.learnlib.ralib.smt.SMTUtil; -import de.learnlib.ralib.words.DataWords; import de.learnlib.ralib.words.OutputSymbol; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; @@ -45,46 +43,56 @@ public class CTAutomatonBuilder { private final ClassificationTree ct; - + private final Map, RALocation> locations; private final Map leaves; // private final Map, Bijection> rpRenamings; - + // private final Set> visitedTransitions; - + private final CTHypothesis hyp; + private final ConstraintSolver solver; + // private final Constants consts; - + private boolean ioMode; - - public CTAutomatonBuilder(ClassificationTree ct, Constants consts, boolean ioMode) { + + public CTAutomatonBuilder(ClassificationTree ct, Constants consts, boolean ioMode, ConstraintSolver solver) { this.ct = ct; // this.consts = consts; this.ioMode = ioMode; - + this.solver = solver; + locations = new LinkedHashMap<>(); leaves = new LinkedHashMap<>(); // rpRenamings = new LinkedHashMap<>(); // visitedTransitions = new LinkedHashSet<>(); - hyp = new CTHypothesis(consts, ct.getLeaves().size()); + hyp = new CTHypothesis(consts, ct.getLeaves().size(), ioMode); } - - public Hypothesis buildHypothesis() { + + public CTHypothesis buildHypothesis() { computeLocations(); computeTransitions(); hyp.putLeaves(leaves); + Optional sink = ct.getSink(); + if (sink.isPresent()) { + hyp.setSink(hyp.getLocation(sink.get())); + } return hyp; } - + private void computeLocations() { CTLeaf initial = ct.getLeaf(RaStar.EMPTY_PREFIX); RALocation l0 = hyp.addInitialState(initial.isAccepting()); locations.put(RaStar.EMPTY_PREFIX, l0); + for (Word sp : initial.getShortPrefixes()) { + locations.put(sp, l0); + } hyp.setAccessSequence(l0, RaStar.EMPTY_PREFIX); // rpRenamings.put(RaStar.EMPTY_PREFIX, new Bijection()); leaves.put(initial, l0); - + for (CTLeaf leaf : ct.getLeaves()) { if (leaf != initial) { RALocation l = hyp.addState(leaf.isAccepting()); @@ -93,11 +101,12 @@ private void computeLocations() { for (Word sp : leaf.getShortPrefixes()) { locations.put(sp, l); } + locations.put(leaf.getRepresentativePrefix(), l); leaves.put(leaf, l); } } } - + private void computeTransitions() { for (CTLeaf leaf : ct.getLeaves()) { // computeTransition(leaf, leaf.getRepresentativePrefix()); @@ -106,71 +115,103 @@ private void computeTransitions() { } } } - + private void computeTransition(CTLeaf dest_l, Prefix prefix) { // if (visitedTransitions.contains(prefix)) { // return; // } - + if (prefix.length() < 1) { return; } - + // Word dest_id = prefix; Prefix dest_rp = dest_l.getRepresentativePrefix(); Word src_id = prefix.prefix(prefix.length() - 1); CTLeaf src_l = ct.getLeaf(src_id); +// if (!src_id.equals(src_l.getRepresentativePrefix())) { +// return; +// } + assert src_l != null : "Source prefix not present in classification tree: " + src_id; assert src_l.getPrefix(src_id) instanceof ShortPrefix : "Source prefix is not short: " + src_id; - assert dest_rp instanceof ShortPrefix : "Representative prefix is not short: " + dest_rp; - +// assert dest_rp instanceof ShortPrefix : "Representative prefix is not short: " + dest_rp; + RALocation src_loc = locations.get(src_id); RALocation dest_loc = locations.get(dest_rp); + assert src_loc != null; + assert dest_loc != null; + ParameterizedSymbol action = prefix.lastSymbol().getBaseSymbol(); - assert src_l.getRepresentativePrefix() instanceof ShortPrefix : "Representative prefix is not a short prefix: " + src_l; - +// assert src_l.getRepresentativePrefix() instanceof ShortPrefix : "Representative prefix is not a short prefix: " + src_l; + Prefix src_prefix = src_l.getPrefix(src_id); ShortPrefix src_u = (ShortPrefix)(src_prefix instanceof ShortPrefix ? src_prefix : src_l.getRepresentativePrefix()); - + // guard Branching b = src_u.getBranching(action); Expression guard = b.getBranches().get(prefix); + if (guard == null) { + for (Expression g : b.getBranches().values()) { + DataValue[] vals = prefix.lastSymbol().getParameterValues(); + ParameterValuation pars = new ParameterValuation(); + for (int i = 0; i < vals.length; i++) { + Parameter p = new Parameter(vals[i].getDataType(), i+1); + pars.put(p, vals[i]); + } + if (solver.isSatisfiable(g, pars)) { + guard = g; + break; + } + } + } + assert guard != null : "No guard for prefix " + prefix; + + for (Transition tr : hyp.getTransitions(src_loc, action)) { + if (tr.getGuard().equals(guard)) { + return; + } + } ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); - guard = rvv.apply(guard, src_u.getAssignment()); - RegisterAssignment srcAssign = src_u.getAssignment(); + RegisterAssignment rpAssign = src_l.getRepresentativePrefix().getAssignment(); + RegisterAssignment srcAssignRemapped = srcAssign.relabel(registerRemapping(srcAssign, rpAssign, src_u.getRpBijection())); + guard = rvv.apply(guard, srcAssignRemapped); +// guard = rvv.apply(guard, src_u.getAssignment()); + RegisterAssignment destAssign = dest_rp.getAssignment(); Bijection remapping = prefix.getRpBijection(); - Assignment assign = AutomatonBuilder.computeAssignment(prefix, srcAssign, destAssign, remapping); + Assignment assign = AutomatonBuilder.computeAssignment(prefix, srcAssignRemapped, destAssign, remapping); Transition t = createTransition(action, guard, src_loc, dest_loc, assign); + if (t != null) { hyp.addTransition(src_loc, action, t); hyp.setTransitionSequence(t, prefix); } -// +// // Word src_rp = src_l.getRepresentativePrefix(); // Bijection src_renaming = rpRenamings.get(src_rp); // if (src_renaming == null) { // computeTransition(src_l, src_l.getRepresentativePrefix()); // src_renaming = rpRenamings.get(src_rp); // } -// +// // int max = DataWords.paramValLength(src_id); // List regs = new ArrayList<>(prefix.getRegisters()); // regs.sort((r1, r2) -> Integer.compare(r1.getId(), r2.getId())); // RegisterGenerator rgen = new RegisterGenerator(); // // Map mapping = new LinkedHashMap<>(); -// +// // Bijection dest_renaming; // if (prefix == dest_l.getRepresentativePrefix()) { // // case 1 : prefix is the rp @@ -207,34 +248,34 @@ private void computeTransition(CTLeaf dest_l, Prefix prefix) { // } // } // } -// +// // VarMapping vars = new VarMapping<>(); // vars.putAll(mapping); // Assignment assignment = new Assignment(vars); -// +// // VarMapping guardRenaming = new VarMapping<>(); // guardRenaming.putAll(src_renaming); // Expression guardRenamed = SMTUtil.renameVars(guard, guardRenaming); -// +// // Transition transition = createTransition(action, guardRenamed, src_loc, dest_loc, assignment); // if (transition != null) { // hyp.addTransition(src_loc, action, transition); // hyp.setTransitionSequence(transition, dest_id); // } -// +// // visitedTransitions.add(dest_id); } - + private Transition createTransition(ParameterizedSymbol action, Expression guard, RALocation src_loc, RALocation dest_loc, Assignment assignment) { if (ioMode && !dest_loc.isAccepting()) { return null; } - + if (!ioMode || !(action instanceof OutputSymbol)) { return new Transition(action, guard, src_loc, dest_loc, assignment); } - + //IfGuard _guard = (IfGuard) guard; Expression expr = guard; @@ -255,7 +296,7 @@ private Transition createTransition(ParameterizedSymbol action, Expression expr, VarMapping outmap) { @@ -296,4 +337,16 @@ else if (expr instanceof NumericBooleanExpression nbe) { //throw new IllegalStateException("Unsupported: " + expr.getClass()); } } + + private VarMapping registerRemapping(RegisterAssignment raa, RegisterAssignment rab, Bijection bijection) { + VarMapping ret = new VarMapping<>(); + + for (Map.Entry be : bijection.entrySet()) { + Register replace = raa.get(be.getKey()); + Register by = rab.get(be.getValue()); + ret.put(replace, by); + } + + return ret; + } } diff --git a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java index ac42b312..4d4ee7cd 100644 --- a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java +++ b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java @@ -13,10 +13,15 @@ import de.learnlib.ralib.data.Bijection; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.Mapping; +import de.learnlib.ralib.data.ParameterValuation; import de.learnlib.ralib.data.SuffixValuation; +import de.learnlib.ralib.data.SymbolicDataValue; +import de.learnlib.ralib.data.SymbolicDataValue.Parameter; import de.learnlib.ralib.data.SymbolicDataValue.Register; import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; import de.learnlib.ralib.data.util.RemappingIterator; +import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.SuffixValueGenerator; import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.learning.rastar.RaStar; @@ -35,7 +40,7 @@ import net.automatalib.word.Word; public class ClassificationTree { - private final CTNode root; + private final CTInnerNode root; private final Map, CTLeaf> prefixes; private final Set> shortPrefixes; @@ -105,7 +110,7 @@ public Set getExtensions(Word u) { for (ParameterizedSymbol action : inputs) { extensions.addAll(getExtensions(u, action) .stream() - .map(w -> getLeaf(u).getPrefix(u)) + .map(w -> getLeaf(w).getPrefix(w)) .collect(Collectors.toList())); } return extensions; @@ -138,7 +143,7 @@ public void expand(Word u) { public void refine(CTLeaf leaf, SymbolicSuffix suffix) { CTInnerNode parent = (CTInnerNode) leaf.getParent(); assert parent != null; - Map, CTLeaf> leaves = parent.refine(leaf, suffix, oracle, solver, ioMode); + Map, CTLeaf> leaves = parent.refine(leaf, suffix, oracle, solver, ioMode, inputs); prefixes.putAll(leaves); for (Word sp : shortPrefixes) { @@ -368,9 +373,9 @@ public boolean checkLocationConsistency() { public boolean checkTransitionConsistency() { for (ShortPrefix u : getShortPrefixes()) { - if (u.length() < 1) { - continue; - } +// if (u.length() < 1) { +// continue; +// } for (ParameterizedSymbol action : inputs) { Set> extensions = getExtensions(u, action); for (Map.Entry, Expression> e : u.getBranching(action).getBranches().entrySet()) { @@ -380,8 +385,11 @@ public boolean checkTransitionConsistency() { if (uB.equals(uA)) { continue; } - SuffixValuation uBVals = actionValuation(uB); - if (solver.isSatisfiable(g, uBVals)) { +// ParameterValuation uBVals = actionValuation(uB); + Mapping mapping = new Mapping<>(); + mapping.putAll(actionValuation(uB)); + mapping.putAll(consts); + if (solver.isSatisfiable(g, mapping)) { Optional av = transitionConsistentA(uA, uB); if (av.isEmpty()) { av = transitionConsistentB(uA, uB); @@ -425,11 +433,27 @@ private Optional transitionConsistentB(Word uA, Register[] regs = inequivalentMapping(rpRegBijection(pA.getRpBijection(), pA), rpRegBijection(pB.getRpBijection(), pB)); DataValue[] regVals = regsToDvs(regs, uA); SymbolicSuffix av = extendSuffix(uA, v, regVals); - return Optional.of(av); + if (suffixRevealsNewGuard(av, getLeaf(uA.prefix(uA.length() - 1)))) { + return Optional.of(av); + } } } return Optional.empty(); } + + private boolean suffixRevealsNewGuard(SymbolicSuffix av, CTLeaf leaf) { + Word u = leaf.getRepresentativePrefix(); + SDT sdt = oracle.treeQuery(u, av); + ParameterizedSymbol a = av.getActions().firstSymbol(); + Branching branching = leaf.getBranching(a); + Branching newBranching = oracle.updateBranching(u, a, branching, sdt); + for (Expression guard : newBranching.getBranches().values()) { + if (!branching.getBranches().values().contains(guard)) { + return true; + } + } + return false; + } private Bijection rpRegBijection(Bijection bijection, Word prefx) { return Bijection.DVtoRegBijection(bijection, prefx, getLeaf(prefx).getRepresentativePrefix()); @@ -504,19 +528,19 @@ private SymbolicSuffix extendSuffix(Word u1, Word ua) { - SuffixValueGenerator svgen = new SuffixValueGenerator(); + private ParameterValuation actionValuation(Word ua) { + ParameterGenerator pgen = new ParameterGenerator(); DataValue[] vals = ua.lastSymbol().getParameterValues(); - SuffixValuation valuation = new SuffixValuation(); + ParameterValuation valuation = new ParameterValuation(); for (int i = 0; i < vals.length; i++) { - SuffixValue sv = svgen.next(vals[i].getDataType()); - valuation.put(sv, vals[i]); + Parameter p = pgen.next(vals[i].getDataType()); + valuation.put(p, vals[i]); } return valuation; } public Set> getExtensions(Word u, ParameterizedSymbol action) { - assert u.length() > 0; +// assert u.length() > 0; return prefixes.keySet() .stream() .filter(w -> w.length() == u.length() + 1) @@ -528,13 +552,42 @@ private Register[] inequivalentMapping(Bijection a, Bijection ret = new LinkedHashSet<>(); for (Map.Entry ea : a.entrySet()) { Register key = ea.getKey(); - if (!b.get(key).equals(ea.getValue())) { + Register val = b.get(key); + if (val == null) { ret.add(key); - ret.add(b.get(key)); + ret.add(ea.getValue()); + } else if (!val.equals(ea.getValue())) { + ret.add(key); + ret.add(val); } } return ret.toArray(new Register[ret.size()]); } + + /* + * Returns the sink node for IO automata + */ + public Optional getSink() { + if (!ioMode) { + return Optional.empty(); + } + + for (CTBranch branch : root.getBranches()) { + if (!branch.getPath().isAccepting()) { + CTNode node = branch.getChild(); + while (!node.isLeaf()) { + CTInnerNode inner = (CTInnerNode) node; + List children = inner.getBranches(); + if (children.isEmpty()) { + return Optional.empty(); + } + node = children.getFirst().getChild(); + } + return Optional.of((CTLeaf) node); + } + } + return Optional.empty(); + } @Override public String toString() { diff --git a/src/main/java/de/learnlib/ralib/data/RegisterAssignment.java b/src/main/java/de/learnlib/ralib/data/RegisterAssignment.java index 17587cd0..06d4f070 100644 --- a/src/main/java/de/learnlib/ralib/data/RegisterAssignment.java +++ b/src/main/java/de/learnlib/ralib/data/RegisterAssignment.java @@ -2,17 +2,27 @@ import java.util.Map; +import de.learnlib.ralib.data.SymbolicDataValue.Register; + /** * A register assignment models which data values * of a prefix are stored in which registers. */ -public class RegisterAssignment extends Mapping { +public class RegisterAssignment extends Mapping { public RegisterValuation registerValuation() { RegisterValuation vars = new RegisterValuation(); - for (Map.Entry e : this.entrySet()) { + for (Map.Entry e : this.entrySet()) { vars.put(e.getValue(), e.getKey()); } return vars; } + + public RegisterAssignment relabel(VarMapping remapping) { + RegisterAssignment ret = new RegisterAssignment(); + for (Map.Entry e : entrySet()) { + ret.put(e.getKey(), remapping.get(e.getValue())); + } + return ret; + } } diff --git a/src/main/java/de/learnlib/ralib/dt/DT.java b/src/main/java/de/learnlib/ralib/dt/DT.java index 315b2485..b62d70f4 100644 --- a/src/main/java/de/learnlib/ralib/dt/DT.java +++ b/src/main/java/de/learnlib/ralib/dt/DT.java @@ -22,7 +22,7 @@ import de.learnlib.ralib.learning.LocationComponent; import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.learning.ralambda.DiscriminationTree; -import de.learnlib.ralib.learning.ralambda.RaLambda; +import de.learnlib.ralib.learning.rastar.RaStar; import de.learnlib.ralib.oracles.TreeOracle; import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; @@ -96,7 +96,7 @@ public DTLeaf sift(Word prefix, boolean add) { public void initialize() { if (ioMode) { DTInnerNode parent = root; - MappedPrefix epsilon = new MappedPrefix(RaLambda.EMPTY_PREFIX, new Bijection<>()); + MappedPrefix epsilon = new MappedPrefix(RaStar.EMPTY_PREFIX, new Bijection<>()); for (ParameterizedSymbol symbol : inputs) { if (symbol instanceof OutputSymbol) { DTInnerNode outputNode = new DTInnerNode(new SymbolicSuffix(symbol)); @@ -114,7 +114,7 @@ public void initialize() { sink = (DTLeaf) branch.getChild(); } } else { - sift(RaLambda.EMPTY_PREFIX, true); + sift(RaStar.EMPTY_PREFIX, true); } } diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/RaLambda.java b/src/main/java/de/learnlib/ralib/learning/ralambda/RaLambda.java index cdde4ca9..bcccb8cb 100644 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/RaLambda.java +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/RaLambda.java @@ -1,500 +1,500 @@ -package de.learnlib.ralib.learning.ralambda; - -import java.util.ArrayDeque; -import java.util.Collection; -import java.util.Collections; -import java.util.Deque; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import de.learnlib.logging.Category; -import de.learnlib.query.DefaultQuery; -import de.learnlib.ralib.ceanalysis.PrefixFinder; -import de.learnlib.ralib.data.*; -import de.learnlib.ralib.dt.DT; -import de.learnlib.ralib.dt.DTHyp; -import de.learnlib.ralib.dt.DTLeaf; -import de.learnlib.ralib.dt.MappedPrefix; -import de.learnlib.ralib.dt.ShortPrefix; -import de.learnlib.ralib.learning.AutomatonBuilder; -import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.learning.IOAutomatonBuilder; -import de.learnlib.ralib.learning.LocationComponent; -import de.learnlib.ralib.learning.QueryStatistics; -import de.learnlib.ralib.learning.RaLearningAlgorithm; -import de.learnlib.ralib.learning.RaLearningAlgorithmName; -import de.learnlib.ralib.learning.SymbolicSuffix; -import de.learnlib.ralib.learning.rastar.CEAnalysisResult; -import de.learnlib.ralib.oracles.Branching; -import de.learnlib.ralib.oracles.SDTLogicOracle; -import de.learnlib.ralib.oracles.TreeOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; -import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; -import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; -import de.learnlib.ralib.smt.ConstraintSolver; -import de.learnlib.ralib.theory.SDT; -import de.learnlib.ralib.words.PSymbolInstance; -import de.learnlib.ralib.words.ParameterizedSymbol; -import net.automatalib.word.Word; - -public class RaLambda implements RaLearningAlgorithm { - - public static final Word EMPTY_PREFIX = Word.epsilon(); - - public static final SymbolicSuffix EMPTY_SUFFIX = new SymbolicSuffix(Word.epsilon(), - Word.epsilon()); - - private final DT dt; - - private final Constants consts; - - private final Deque> counterexamples = new LinkedList<>(); - private final Deque> candidateCEs = new LinkedList<>(); - - private DTHyp hyp = null; - - private final TreeOracle sulOracle; - - private final SDTLogicOracle sdtLogicOracle; - - private final TreeOracleFactory hypOracleFactory; - - private final OptimizedSymbolicSuffixBuilder suffixBuilder; - private final SymbolicSuffixRestrictionBuilder restrictionBuilder; - private ConstraintSolver solver = null; - - private QueryStatistics queryStats = null; - - private final boolean ioMode; - - private static final Logger LOGGER = LoggerFactory.getLogger(RaLambda.class); - - private boolean useOldAnalyzer; - - private final Map, Boolean> guardPrefixes = new LinkedHashMap, Boolean>(); - - private PrefixFinder prefixFinder = null; - - public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, - boolean ioMode, ParameterizedSymbol... inputs) { - - this(oracle, hypOracleFactory, sdtLogicOracle, consts, ioMode, false, inputs); - } - - public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, - boolean ioMode, boolean useOldAnalyzer, ParameterizedSymbol... inputs) { - - this(oracle, hypOracleFactory, sdtLogicOracle, consts, ioMode, useOldAnalyzer, false, inputs); - } - - public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, - boolean ioMode, boolean useOldAnalyzer, boolean thoroughSearch, ParameterizedSymbol... inputs) { - - this.ioMode = ioMode; - this.consts = consts; - this.sulOracle = oracle; - this.sdtLogicOracle = sdtLogicOracle; - this.hypOracleFactory = hypOracleFactory; - this.useOldAnalyzer = useOldAnalyzer; - this.restrictionBuilder = oracle.getRestrictionBuilder(); - this.suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrictionBuilder); - this.dt = new DT(oracle, ioMode, consts, inputs); - this.dt.initialize(); - } - - public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, - ParameterizedSymbol... inputs) { - this(oracle, hypOracleFactory, sdtLogicOracle, consts, false, false, inputs); - } - - @Override - public void addCounterexample(DefaultQuery ce) { - LOGGER.info(Category.EVENT, "adding counterexample: {}", ce); - counterexamples.add(ce); - } - - @Override - public void learn() { - - if (hyp == null) { - buildNewHypothesis(); - } - - while (analyzeCounterExample()); - - if (queryStats != null) - queryStats.hypothesisConstructed(); - - } - - private void buildNewHypothesis() { - - Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); - components.putAll(dt.getComponents()); - AutomatonBuilder ab = new AutomatonBuilder(components, consts, dt); - - hyp = (DTHyp) ab.toRegisterAutomaton(); - if (prefixFinder != null) { - prefixFinder.setHypothesis(hyp); - //prefixFinder.setComponents(components); - prefixFinder.setHypothesisTreeOracle(hypOracleFactory.createTreeOracle(hyp)); - } - } - - private boolean analyzeCounterExample() { -// if (useOldAnalyzer) -// return analyzeCounterExampleOld(); - LOGGER.info(Category.PHASE, "Analyzing Counterexample"); - - if (candidateCEs.isEmpty()) { - prefixFinder = null; - if (counterexamples.isEmpty()) { - assert noShortPrefixes() || !dt.isMissingParameter(); - return false; - } - else { - DefaultQuery ce = counterexamples.poll(); - candidateCEs.push(ce); - } - } - - TreeOracle hypOracle = hypOracleFactory.createTreeOracle(hyp); - - if (prefixFinder == null) { - //Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); - //components.putAll(dt.getComponents()); - prefixFinder = new PrefixFinder(sulOracle, hypOracle, hyp, sdtLogicOracle, consts); - } - - boolean foundce = false; - DefaultQuery ce = null; - Deque> ces = new ArrayDeque>(); - ces.addAll(candidateCEs); - while(!foundce && !ces.isEmpty()) { - ce = ces.poll(); - boolean hypce = hyp.accepts(ce.getInput()); - boolean sulce = ce.getOutput(); - //System.out.println("ce: " + ce + " - " + sulce + " vs. " + hypce); - foundce = hypce != sulce; - } - - if (!foundce) { - candidateCEs.clear(); - return true; - } - - if (queryStats != null) { - queryStats.analyzingCounterExample(); - queryStats.analyzeCE(ce.getInput()); - } - Word ceWord = ce.getInput(); - CEAnalysisResult result = prefixFinder.analyzeCounterexample(ceWord); - Word transition = result.getPrefix(); // u alpha(d) - //System.out.println("new prefix: " + transition); - - for (DefaultQuery q : prefixFinder.getCounterExamples()) { - if (!candidateCEs.contains(q)) - candidateCEs.addLast(q); - } - - if (queryStats != null) - queryStats.processingCounterExample(); - - if (isGuardRefinement(transition)) { - addPrefix(transition); - } - else { - expand(transition); - } - - while (!dt.checkIOSuffixes()); - - boolean consistent = false; - while (!consistent) { - - consistent = checkLocationConsistency(); - - if (!checkRegisterClosedness()) { - consistent = false; - } - - if (!checkGuardConsistency()) { - consistent = false; - } - - if (!checkRegisterConsistency()) { - consistent = false; - } - } - - if (noShortPrefixes() && !dt.isMissingParameter()) { - buildNewHypothesis(); - } - //System.out.println(hyp); - return true; - } - - private boolean isGuardRefinement(Word word) { - return dt.getLeaf(word) == null; - } - - private void addPrefix(Word u) { - dt.sift(u, true); - } - - private void expand(Word u) { - DTLeaf l = dt.getLeaf(u); - assert l != null; - l.elevatePrefix(dt, u, hyp, sdtLogicOracle); - } - - private boolean checkLocationConsistency() { - - for (DTLeaf l : dt.getLeaves()) { - MappedPrefix mp = l.getPrimePrefix(); - Iterator it = l.getShortPrefixes().iterator(); - while (it.hasNext()) { - ShortPrefix sp = (ShortPrefix)it.next(); - SymbolicSuffix suffix = null; - for (ParameterizedSymbol psi : dt.getInputs()) { - Branching access_b = l.getBranching(psi); - Branching prefix_b = sp.getBranching(psi); - for (Word ws : prefix_b.getBranches().keySet()) { - Word wa = DTLeaf.branchWithSameGuard(ws, prefix_b, l.getRemapping(sp), access_b, sdtLogicOracle); - //System.out.println("wa: " + wa + ", ws: " + ws); - DTLeaf la = dt.getLeaf(wa); - DTLeaf ls = dt.getLeaf(ws); - if (la != ls) { - SymbolicSuffix v = distinguishingSuffix(wa, la, ws, ls); - if (suffix == null || suffix.length() > v.length()) { - suffix = v; - } - assert suffix != null; - } - } - } - if (suffix != null) { - dt.split(sp.getPrefix(), suffix, l); - return false; - } - } - } - return true; - } - - private boolean checkRegisterClosedness() { - return dt.checkVariableConsistency(suffixBuilder); - } - - private boolean checkRegisterConsistency() { - return dt.checkRegisterConsistency(suffixBuilder); - } - - private boolean checkGuardConsistency() { - for (DTLeaf dest_c : dt.getLeaves()) { - Collection> words = new LinkedHashSet<>(); - words.add(dest_c.getAccessSequence()); - words.addAll(dest_c.getPrefixes().getWords()); - words.addAll(dest_c.getShortPrefixes().getWords()); - for (Word dest_id : words) { - if (dest_id.length() == 0) { - continue; - } - Word src_id = dest_id.prefix(dest_id.length() - 1); - DTLeaf src_c = dt.getLeaf(src_id); - - Branching hypBranching = null; - if (src_c.getAccessSequence().equals(src_id)) { - hypBranching = src_c.getBranching(dest_id.lastSymbol().getBaseSymbol()); - } else { - ShortPrefix sp = (ShortPrefix) src_c.getShortPrefixes().get(src_id); - assert sp != null; - hypBranching = sp.getBranching(dest_id.lastSymbol().getBaseSymbol()); - } - if (hypBranching.getBranches().get(dest_id) != null) { - // word already in branching, no guard refinement needed - continue; - } - Word hyp_id = branchWithSameGuard(dest_c.getPrefix(dest_id), hypBranching); - - SymbolicSuffix suffix = null; - - DTLeaf hyp_c = dt.getLeaf(hyp_id); - if (hyp_c != dest_c) { - suffix = distinguishingSuffix(hyp_id, hyp_c, dest_id, dest_c); - } else { - List suffixes = new LinkedList<>(); - Map dest_sdts = new LinkedHashMap<>(); - Map hyp_sdts = new LinkedHashMap<>(); - for (Map.Entry e : dest_c.getPrefix(dest_id).getTQRs().entrySet()) { - SymbolicSuffix s = e.getKey(); - SDT dest_sdt = e.getValue(); - SDT hyp_sdt = hyp_c.getPrefix(hyp_id).getTQRs().get(s); - assert hyp_sdt != null; - - if (!SDT.equivalentUnderId(dest_sdt.toRegisterSDT(dest_id, consts), hyp_sdt.toRegisterSDT(hyp_id, consts))) { - suffixes.add(s); - dest_sdts.put(s, dest_sdt); - hyp_sdts.put(s, hyp_sdt); - } - } - - if (suffixes.isEmpty()) { - continue; - } - - Collections.sort(suffixes, (sa, sb) -> sa.length() > sb.length() ? 1 : - sa.length() < sb.length() ? -1 : 0); - - for (SymbolicSuffix s : suffixes) { - SymbolicSuffix testSuffix; - SDT hyp_sdt = hyp_sdts.get(s); - - if (suffixBuilder != null) { - SDT dest_sdt = dest_sdts.get(s); - DataValue[] regs = remappedRegisters(dest_sdt, hyp_sdt); - testSuffix = suffixBuilder.extendSuffix(dest_id, dest_sdt, s, regs); - } else { - testSuffix = new SymbolicSuffix(src_id, dest_id.suffix(1), restrictionBuilder); - testSuffix = testSuffix.concat(s); - } - - SDT testSDT = sulOracle.treeQuery(src_id, testSuffix); - Branching testBranching = sulOracle.updateBranching(src_id, dest_id.lastSymbol().getBaseSymbol(), hypBranching, testSDT); - if (testBranching.getBranches().get(dest_id) != null) { - suffix = testSuffix; - break; - } - } - } - - if (suffix != null) { - dt.addSuffix(suffix, src_c); - return false; - } - } - } - - return true; - } - - private SymbolicSuffix distinguishingSuffix(Word wa, DTLeaf ca, Word wb, DTLeaf cb) { - Word sa = wa.suffix(1); - Word sb = wb.suffix(1); - - assert sa.getSymbol(0).getBaseSymbol().equals(sb.getSymbol(0).getBaseSymbol()); - - SymbolicSuffix v = dt.findLCA(ca, cb).getSuffix(); - - Word prefixA = wa.prefix(wa.length() - 1); - Word prefixB = wb.prefix(wb.length() - 1); - - SDT tqrA = ca.getTQR(wa, v); - SDT tqrB = cb.getTQR(wb, v); - - assert tqrA != null && tqrB != null; - - SDT sdtA = tqrA; - SDT sdtB = tqrB; - - if (suffixBuilder != null && solver != null) { - //return suffixBuilder.extendDistinguishingSuffix(wa, sdtA, wb, sdtB, v); - SymbolicSuffix suffix = suffixBuilder.distinguishingSuffixFromSDTs(wa, sdtA, wb, sdtB, v.getActions(), solver); - return suffix; - } - - SymbolicSuffix alpha_a = new SymbolicSuffix(prefixA, sa, restrictionBuilder); - SymbolicSuffix alpha_b = new SymbolicSuffix(prefixB, sb, restrictionBuilder); - return alpha_a.getFreeValues().size() > alpha_b.getFreeValues().size() - ? alpha_a.concat(v) - : alpha_b.concat(v); - } - - private boolean noShortPrefixes() { - for (DTLeaf l : dt.getLeaves()) { - if (!l.getShortPrefixes().isEmpty()) { - return false; - } - } - return true; - } - - public void setUseOldAnalyzer(boolean useOldAnalyzer) { - this.useOldAnalyzer = useOldAnalyzer; - } - - private Word branchWithSameGuard(MappedPrefix mp, Branching branching) { - Word dw = mp.getPrefix(); - - return branching.transformPrefix(dw); - } - - private DataValue[] remappedRegisters(SDT sdt1, SDT sdt2) { - Bijection bijection = SDT.equivalentUnderBijection(sdt1, sdt2); - assert bijection != null; - List vals = new LinkedList<>(); - for (Map.Entry e : bijection.entrySet()) { - if (!e.getKey().equals(e.getValue())) { - vals.add(e.getKey()); - vals.add(e.getValue()); - } - } - return vals.toArray(new DataValue[vals.size()]); - } - - @Override - public Hypothesis getHypothesis() { - Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); - components.putAll(dt.getComponents()); - AutomatonBuilder ab; - if (ioMode) { - ab = new IOAutomatonBuilder(components, consts); - } else { - ab = new AutomatonBuilder(components, consts); - } - return ab.toRegisterAutomaton(); - } - - public DT getDT() { - return dt; - } - - public DTHyp getDTHyp() { - return hyp; - } - - public Map, LocationComponent> getComponents() { - return dt.getComponents(); - } - - @Override - public void setStatisticCounter(QueryStatistics queryStats) { - this.queryStats = queryStats; - } - - @Override - public QueryStatistics getQueryStatistics() { - return queryStats; - } - - public void setSolver(ConstraintSolver solver) { - this.solver = solver; - } - - @Override - public RaLearningAlgorithmName getName() { - return RaLearningAlgorithmName.RALAMBDA; - } - - @Override - public String toString() { - return dt.toString(); - } -} +//package de.learnlib.ralib.learning.ralambda; +// +//import java.util.ArrayDeque; +//import java.util.Collection; +//import java.util.Collections; +//import java.util.Deque; +//import java.util.Iterator; +//import java.util.LinkedHashMap; +//import java.util.LinkedHashSet; +//import java.util.LinkedList; +//import java.util.List; +//import java.util.Map; +// +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import de.learnlib.logging.Category; +//import de.learnlib.query.DefaultQuery; +//import de.learnlib.ralib.ceanalysis.PrefixFinder; +//import de.learnlib.ralib.data.*; +//import de.learnlib.ralib.dt.DT; +//import de.learnlib.ralib.dt.DTHyp; +//import de.learnlib.ralib.dt.DTLeaf; +//import de.learnlib.ralib.dt.MappedPrefix; +//import de.learnlib.ralib.dt.ShortPrefix; +//import de.learnlib.ralib.learning.AutomatonBuilder; +//import de.learnlib.ralib.learning.Hypothesis; +//import de.learnlib.ralib.learning.IOAutomatonBuilder; +//import de.learnlib.ralib.learning.LocationComponent; +//import de.learnlib.ralib.learning.QueryStatistics; +//import de.learnlib.ralib.learning.RaLearningAlgorithm; +//import de.learnlib.ralib.learning.RaLearningAlgorithmName; +//import de.learnlib.ralib.learning.SymbolicSuffix; +//import de.learnlib.ralib.learning.rastar.CEAnalysisResult; +//import de.learnlib.ralib.oracles.Branching; +//import de.learnlib.ralib.oracles.SDTLogicOracle; +//import de.learnlib.ralib.oracles.TreeOracle; +//import de.learnlib.ralib.oracles.TreeOracleFactory; +//import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; +//import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; +//import de.learnlib.ralib.smt.ConstraintSolver; +//import de.learnlib.ralib.theory.SDT; +//import de.learnlib.ralib.words.PSymbolInstance; +//import de.learnlib.ralib.words.ParameterizedSymbol; +//import net.automatalib.word.Word; +// +//public class RaLambda implements RaLearningAlgorithm { +// +// public static final Word EMPTY_PREFIX = Word.epsilon(); +// +// public static final SymbolicSuffix EMPTY_SUFFIX = new SymbolicSuffix(Word.epsilon(), +// Word.epsilon()); +// +// private final DT dt; +// +// private final Constants consts; +// +// private final Deque> counterexamples = new LinkedList<>(); +// private final Deque> candidateCEs = new LinkedList<>(); +// +// private DTHyp hyp = null; +// +// private final TreeOracle sulOracle; +// +// private final SDTLogicOracle sdtLogicOracle; +// +// private final TreeOracleFactory hypOracleFactory; +// +// private final OptimizedSymbolicSuffixBuilder suffixBuilder; +// private final SymbolicSuffixRestrictionBuilder restrictionBuilder; +// private ConstraintSolver solver = null; +// +// private QueryStatistics queryStats = null; +// +// private final boolean ioMode; +// +// private static final Logger LOGGER = LoggerFactory.getLogger(RaLambda.class); +// +// private boolean useOldAnalyzer; +// +// private final Map, Boolean> guardPrefixes = new LinkedHashMap, Boolean>(); +// +// private PrefixFinder prefixFinder = null; +// +// public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, +// boolean ioMode, ParameterizedSymbol... inputs) { +// +// this(oracle, hypOracleFactory, sdtLogicOracle, consts, ioMode, false, inputs); +// } +// +// public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, +// boolean ioMode, boolean useOldAnalyzer, ParameterizedSymbol... inputs) { +// +// this(oracle, hypOracleFactory, sdtLogicOracle, consts, ioMode, useOldAnalyzer, false, inputs); +// } +// +// public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, +// boolean ioMode, boolean useOldAnalyzer, boolean thoroughSearch, ParameterizedSymbol... inputs) { +// +// this.ioMode = ioMode; +// this.consts = consts; +// this.sulOracle = oracle; +// this.sdtLogicOracle = sdtLogicOracle; +// this.hypOracleFactory = hypOracleFactory; +// this.useOldAnalyzer = useOldAnalyzer; +// this.restrictionBuilder = oracle.getRestrictionBuilder(); +// this.suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrictionBuilder); +// this.dt = new DT(oracle, ioMode, consts, inputs); +// this.dt.initialize(); +// } +// +// public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, +// ParameterizedSymbol... inputs) { +// this(oracle, hypOracleFactory, sdtLogicOracle, consts, false, false, inputs); +// } +// +// @Override +// public void addCounterexample(DefaultQuery ce) { +// LOGGER.info(Category.EVENT, "adding counterexample: {}", ce); +// counterexamples.add(ce); +// } +// +// @Override +// public void learn() { +// +// if (hyp == null) { +// buildNewHypothesis(); +// } +// +// while (analyzeCounterExample()); +// +// if (queryStats != null) +// queryStats.hypothesisConstructed(); +// +// } +// +// private void buildNewHypothesis() { +// +// Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); +// components.putAll(dt.getComponents()); +// AutomatonBuilder ab = new AutomatonBuilder(components, consts, dt); +// +// hyp = (DTHyp) ab.toRegisterAutomaton(); +// if (prefixFinder != null) { +// prefixFinder.setHypothesis(hyp); +// //prefixFinder.setComponents(components); +// prefixFinder.setHypothesisTreeOracle(hypOracleFactory.createTreeOracle(hyp)); +// } +// } +// +// private boolean analyzeCounterExample() { +//// if (useOldAnalyzer) +//// return analyzeCounterExampleOld(); +// LOGGER.info(Category.PHASE, "Analyzing Counterexample"); +// +// if (candidateCEs.isEmpty()) { +// prefixFinder = null; +// if (counterexamples.isEmpty()) { +// assert noShortPrefixes() || !dt.isMissingParameter(); +// return false; +// } +// else { +// DefaultQuery ce = counterexamples.poll(); +// candidateCEs.push(ce); +// } +// } +// +// TreeOracle hypOracle = hypOracleFactory.createTreeOracle(hyp); +// +// if (prefixFinder == null) { +// //Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); +// //components.putAll(dt.getComponents()); +// prefixFinder = new PrefixFinder(sulOracle, hypOracle, hyp, sdtLogicOracle, consts); +// } +// +// boolean foundce = false; +// DefaultQuery ce = null; +// Deque> ces = new ArrayDeque>(); +// ces.addAll(candidateCEs); +// while(!foundce && !ces.isEmpty()) { +// ce = ces.poll(); +// boolean hypce = hyp.accepts(ce.getInput()); +// boolean sulce = ce.getOutput(); +// //System.out.println("ce: " + ce + " - " + sulce + " vs. " + hypce); +// foundce = hypce != sulce; +// } +// +// if (!foundce) { +// candidateCEs.clear(); +// return true; +// } +// +// if (queryStats != null) { +// queryStats.analyzingCounterExample(); +// queryStats.analyzeCE(ce.getInput()); +// } +// Word ceWord = ce.getInput(); +// CEAnalysisResult result = prefixFinder.analyzeCounterexample(ceWord); +// Word transition = result.getPrefix(); // u alpha(d) +// //System.out.println("new prefix: " + transition); +// +// for (DefaultQuery q : prefixFinder.getCounterExamples()) { +// if (!candidateCEs.contains(q)) +// candidateCEs.addLast(q); +// } +// +// if (queryStats != null) +// queryStats.processingCounterExample(); +// +// if (isGuardRefinement(transition)) { +// addPrefix(transition); +// } +// else { +// expand(transition); +// } +// +// while (!dt.checkIOSuffixes()); +// +// boolean consistent = false; +// while (!consistent) { +// +// consistent = checkLocationConsistency(); +// +// if (!checkRegisterClosedness()) { +// consistent = false; +// } +// +// if (!checkGuardConsistency()) { +// consistent = false; +// } +// +// if (!checkRegisterConsistency()) { +// consistent = false; +// } +// } +// +// if (noShortPrefixes() && !dt.isMissingParameter()) { +// buildNewHypothesis(); +// } +// //System.out.println(hyp); +// return true; +// } +// +// private boolean isGuardRefinement(Word word) { +// return dt.getLeaf(word) == null; +// } +// +// private void addPrefix(Word u) { +// dt.sift(u, true); +// } +// +// private void expand(Word u) { +// DTLeaf l = dt.getLeaf(u); +// assert l != null; +// l.elevatePrefix(dt, u, hyp, sdtLogicOracle); +// } +// +// private boolean checkLocationConsistency() { +// +// for (DTLeaf l : dt.getLeaves()) { +// MappedPrefix mp = l.getPrimePrefix(); +// Iterator it = l.getShortPrefixes().iterator(); +// while (it.hasNext()) { +// ShortPrefix sp = (ShortPrefix)it.next(); +// SymbolicSuffix suffix = null; +// for (ParameterizedSymbol psi : dt.getInputs()) { +// Branching access_b = l.getBranching(psi); +// Branching prefix_b = sp.getBranching(psi); +// for (Word ws : prefix_b.getBranches().keySet()) { +// Word wa = DTLeaf.branchWithSameGuard(ws, prefix_b, l.getRemapping(sp), access_b, sdtLogicOracle); +// //System.out.println("wa: " + wa + ", ws: " + ws); +// DTLeaf la = dt.getLeaf(wa); +// DTLeaf ls = dt.getLeaf(ws); +// if (la != ls) { +// SymbolicSuffix v = distinguishingSuffix(wa, la, ws, ls); +// if (suffix == null || suffix.length() > v.length()) { +// suffix = v; +// } +// assert suffix != null; +// } +// } +// } +// if (suffix != null) { +// dt.split(sp.getPrefix(), suffix, l); +// return false; +// } +// } +// } +// return true; +// } +// +// private boolean checkRegisterClosedness() { +// return dt.checkVariableConsistency(suffixBuilder); +// } +// +// private boolean checkRegisterConsistency() { +// return dt.checkRegisterConsistency(suffixBuilder); +// } +// +// private boolean checkGuardConsistency() { +// for (DTLeaf dest_c : dt.getLeaves()) { +// Collection> words = new LinkedHashSet<>(); +// words.add(dest_c.getAccessSequence()); +// words.addAll(dest_c.getPrefixes().getWords()); +// words.addAll(dest_c.getShortPrefixes().getWords()); +// for (Word dest_id : words) { +// if (dest_id.length() == 0) { +// continue; +// } +// Word src_id = dest_id.prefix(dest_id.length() - 1); +// DTLeaf src_c = dt.getLeaf(src_id); +// +// Branching hypBranching = null; +// if (src_c.getAccessSequence().equals(src_id)) { +// hypBranching = src_c.getBranching(dest_id.lastSymbol().getBaseSymbol()); +// } else { +// ShortPrefix sp = (ShortPrefix) src_c.getShortPrefixes().get(src_id); +// assert sp != null; +// hypBranching = sp.getBranching(dest_id.lastSymbol().getBaseSymbol()); +// } +// if (hypBranching.getBranches().get(dest_id) != null) { +// // word already in branching, no guard refinement needed +// continue; +// } +// Word hyp_id = branchWithSameGuard(dest_c.getPrefix(dest_id), hypBranching); +// +// SymbolicSuffix suffix = null; +// +// DTLeaf hyp_c = dt.getLeaf(hyp_id); +// if (hyp_c != dest_c) { +// suffix = distinguishingSuffix(hyp_id, hyp_c, dest_id, dest_c); +// } else { +// List suffixes = new LinkedList<>(); +// Map dest_sdts = new LinkedHashMap<>(); +// Map hyp_sdts = new LinkedHashMap<>(); +// for (Map.Entry e : dest_c.getPrefix(dest_id).getTQRs().entrySet()) { +// SymbolicSuffix s = e.getKey(); +// SDT dest_sdt = e.getValue(); +// SDT hyp_sdt = hyp_c.getPrefix(hyp_id).getTQRs().get(s); +// assert hyp_sdt != null; +// +// if (!SDT.equivalentUnderId(dest_sdt.toRegisterSDT(dest_id, consts), hyp_sdt.toRegisterSDT(hyp_id, consts))) { +// suffixes.add(s); +// dest_sdts.put(s, dest_sdt); +// hyp_sdts.put(s, hyp_sdt); +// } +// } +// +// if (suffixes.isEmpty()) { +// continue; +// } +// +// Collections.sort(suffixes, (sa, sb) -> sa.length() > sb.length() ? 1 : +// sa.length() < sb.length() ? -1 : 0); +// +// for (SymbolicSuffix s : suffixes) { +// SymbolicSuffix testSuffix; +// SDT hyp_sdt = hyp_sdts.get(s); +// +// if (suffixBuilder != null) { +// SDT dest_sdt = dest_sdts.get(s); +// DataValue[] regs = remappedRegisters(dest_sdt, hyp_sdt); +// testSuffix = suffixBuilder.extendSuffix(dest_id, dest_sdt, s, regs); +// } else { +// testSuffix = new SymbolicSuffix(src_id, dest_id.suffix(1), restrictionBuilder); +// testSuffix = testSuffix.concat(s); +// } +// +// SDT testSDT = sulOracle.treeQuery(src_id, testSuffix); +// Branching testBranching = sulOracle.updateBranching(src_id, dest_id.lastSymbol().getBaseSymbol(), hypBranching, testSDT); +// if (testBranching.getBranches().get(dest_id) != null) { +// suffix = testSuffix; +// break; +// } +// } +// } +// +// if (suffix != null) { +// dt.addSuffix(suffix, src_c); +// return false; +// } +// } +// } +// +// return true; +// } +// +// private SymbolicSuffix distinguishingSuffix(Word wa, DTLeaf ca, Word wb, DTLeaf cb) { +// Word sa = wa.suffix(1); +// Word sb = wb.suffix(1); +// +// assert sa.getSymbol(0).getBaseSymbol().equals(sb.getSymbol(0).getBaseSymbol()); +// +// SymbolicSuffix v = dt.findLCA(ca, cb).getSuffix(); +// +// Word prefixA = wa.prefix(wa.length() - 1); +// Word prefixB = wb.prefix(wb.length() - 1); +// +// SDT tqrA = ca.getTQR(wa, v); +// SDT tqrB = cb.getTQR(wb, v); +// +// assert tqrA != null && tqrB != null; +// +// SDT sdtA = tqrA; +// SDT sdtB = tqrB; +// +// if (suffixBuilder != null && solver != null) { +// //return suffixBuilder.extendDistinguishingSuffix(wa, sdtA, wb, sdtB, v); +// SymbolicSuffix suffix = suffixBuilder.distinguishingSuffixFromSDTs(wa, sdtA, wb, sdtB, v.getActions(), solver); +// return suffix; +// } +// +// SymbolicSuffix alpha_a = new SymbolicSuffix(prefixA, sa, restrictionBuilder); +// SymbolicSuffix alpha_b = new SymbolicSuffix(prefixB, sb, restrictionBuilder); +// return alpha_a.getFreeValues().size() > alpha_b.getFreeValues().size() +// ? alpha_a.concat(v) +// : alpha_b.concat(v); +// } +// +// private boolean noShortPrefixes() { +// for (DTLeaf l : dt.getLeaves()) { +// if (!l.getShortPrefixes().isEmpty()) { +// return false; +// } +// } +// return true; +// } +// +// public void setUseOldAnalyzer(boolean useOldAnalyzer) { +// this.useOldAnalyzer = useOldAnalyzer; +// } +// +// private Word branchWithSameGuard(MappedPrefix mp, Branching branching) { +// Word dw = mp.getPrefix(); +// +// return branching.transformPrefix(dw); +// } +// +// private DataValue[] remappedRegisters(SDT sdt1, SDT sdt2) { +// Bijection bijection = SDT.equivalentUnderBijection(sdt1, sdt2); +// assert bijection != null; +// List vals = new LinkedList<>(); +// for (Map.Entry e : bijection.entrySet()) { +// if (!e.getKey().equals(e.getValue())) { +// vals.add(e.getKey()); +// vals.add(e.getValue()); +// } +// } +// return vals.toArray(new DataValue[vals.size()]); +// } +// +// @Override +// public Hypothesis getHypothesis() { +// Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); +// components.putAll(dt.getComponents()); +// AutomatonBuilder ab; +// if (ioMode) { +// ab = new IOAutomatonBuilder(components, consts); +// } else { +// ab = new AutomatonBuilder(components, consts); +// } +// return ab.toRegisterAutomaton(); +// } +// +// public DT getDT() { +// return dt; +// } +// +// public DTHyp getDTHyp() { +// return hyp; +// } +// +// public Map, LocationComponent> getComponents() { +// return dt.getComponents(); +// } +// +// @Override +// public void setStatisticCounter(QueryStatistics queryStats) { +// this.queryStats = queryStats; +// } +// +// @Override +// public QueryStatistics getQueryStatistics() { +// return queryStats; +// } +// +// public void setSolver(ConstraintSolver solver) { +// this.solver = solver; +// } +// +// @Override +// public RaLearningAlgorithmName getName() { +// return RaLearningAlgorithmName.RALAMBDA; +// } +// +// @Override +// public String toString() { +// return dt.toString(); +// } +//} diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java index e1fdd18e..55ca0d2a 100644 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java @@ -106,7 +106,7 @@ private boolean checkClosedness() { } private void buildHypothesis() { - CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, ioMode); + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, ioMode, solver); hyp = ab.buildHypothesis(); } @@ -184,5 +184,8 @@ public QueryStatistics getQueryStatistics() { public RaLearningAlgorithmName getName() { return RaLearningAlgorithmName.RADT; } - + + public ClassificationTree getCT() { + return ct; + } } diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java b/src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java new file mode 100644 index 00000000..8d9c5b54 --- /dev/null +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java @@ -0,0 +1,213 @@ +package de.learnlib.ralib.learning.ralambda; + +import java.util.Deque; +import java.util.LinkedList; +import java.util.Map; + +import de.learnlib.query.DefaultQuery; +import de.learnlib.ralib.ceanalysis.PrefixFinder; +import de.learnlib.ralib.ceanalysis.PrefixFinder.Result; +import de.learnlib.ralib.ct.CTAutomatonBuilder; +import de.learnlib.ralib.ct.CTHypothesis; +import de.learnlib.ralib.ct.ClassificationTree; +import de.learnlib.ralib.data.Constants; +import de.learnlib.ralib.data.DataType; +import de.learnlib.ralib.learning.Hypothesis; +import de.learnlib.ralib.learning.QueryStatistics; +import de.learnlib.ralib.learning.RaLearningAlgorithm; +import de.learnlib.ralib.learning.RaLearningAlgorithmName; +import de.learnlib.ralib.oracles.SDTLogicOracle; +import de.learnlib.ralib.oracles.TreeOracle; +import de.learnlib.ralib.oracles.TreeOracleFactory; +import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; +import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; +import de.learnlib.ralib.smt.ConstraintSolver; +import de.learnlib.ralib.theory.Theory; +import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import net.automatalib.word.Word; + +public class SLLambda implements RaLearningAlgorithm { + + private final ClassificationTree ct; + + private final Constants consts; + + private final Deque> counterexamples; + + private CTHypothesis hyp; + + private final TreeOracle sulOracle; + + private final SDTLogicOracle sdtLogicOracle; + + private final TreeOracleFactory hypOracleFactory; + + private final OptimizedSymbolicSuffixBuilder suffixBuilder; + private final SymbolicSuffixRestrictionBuilder restrictionBuilder; + + private final Map teachers; + + private QueryStatistics queryStats; + + private final boolean ioMode; + + private final ConstraintSolver solver; + + public SLLambda(TreeOracle sulOracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, + Map teachers, Constants consts, boolean ioMode, ConstraintSolver solver, + ParameterizedSymbol ... inputs) { + this.sulOracle = sulOracle; + this.hypOracleFactory = hypOracleFactory; + this.sdtLogicOracle = sdtLogicOracle; + this.teachers = teachers; + this.consts = consts; + this.ioMode = ioMode; + this.solver = solver; + restrictionBuilder = sulOracle.getRestrictionBuilder(); + suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrictionBuilder); + counterexamples = new LinkedList<>(); + hyp = null; + ct = new ClassificationTree(sulOracle, solver, restrictionBuilder, suffixBuilder, consts, ioMode, inputs); + ct.initialize(); + } + + @Override + public void learn() { + if (hyp == null) { + while(!checkClosedness()); + buildHypothesis(); + } + + while(analyzeCounterExample()); + + if (queryStats != null) { + queryStats.hypothesisConstructed(); + } + } + + private boolean checkClosedness() { + if (!ct.checkOutputClosed()) { + return false; + } + if (!ct.checkLocationClosedness()) { + return false; + } + if (!ct.checkTransitionClosedness()) { + return false; + } + if (!ct.checkRegisterClosedness()) { + return false; + } + return true; + } + + private boolean checkConsistency() { + if (!ct.checkLocationConsistency()) { + return false; + } + if (!ct.checkTransitionConsistency()) { + return false; + } + if (!ct.checkRegisterConsistency()) { + return false; + } + return true; + } + + private void buildHypothesis() { + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, ioMode, solver); + hyp = ab.buildHypothesis(); + } + + private boolean analyzeCounterExample() { + if (counterexamples.isEmpty()) { + return false; + } + + // check whether ce is still a ce + DefaultQuery ce = counterexamples.peek(); + Word ceWord = ce.getInput(); + boolean accHyp = hyp.accepts(ceWord); + boolean accSul = ce.getOutput(); + if (accHyp == accSul) { + // not a ce, dequeue it + counterexamples.poll(); + return true; + } + + // analyze counterexample + + if (queryStats != null) { + queryStats.analyzingCounterExample(); + queryStats.analyzeCE(ceWord); + } + + PrefixFinder prefixFinder = new PrefixFinder(sulOracle, + hyp, + ct, + teachers, + restrictionBuilder, + solver, + consts); + + Result res = prefixFinder.analyzeCounterExample(ceWord); + + // process counterexample + + if (queryStats != null) + queryStats.processingCounterExample(); + + switch(res.result()) { + case TRANSITION: + assert !ct.getPrefixes().contains(res.prefix()) : "Duplicate prefix: " + res.prefix(); + ct.sift(res.prefix()); + break; + case LOCATION: + assert !ct.getShortPrefixes().contains(res.prefix()) : "Prefix already short: " + res.prefix(); + ct.expand(res.prefix()); + break; + } + + boolean closedAndConsistent = false; + while(!closedAndConsistent) { + if (checkClosedness()) { + if (checkConsistency()) { + closedAndConsistent = true; + } + } + } + + buildHypothesis(); + return true; + } + + @Override + public void addCounterexample(DefaultQuery ce) { + counterexamples.add(ce); + } + + @Override + public Hypothesis getHypothesis() { + return hyp; + } + + @Override + public void setStatisticCounter(QueryStatistics queryStats) { + this.queryStats = queryStats; + } + + @Override + public QueryStatistics getQueryStatistics() { + return queryStats; + } + + @Override + public RaLearningAlgorithmName getName() { + return RaLearningAlgorithmName.RALAMBDA; + } + + public ClassificationTree getCT() { + return ct; + } +} diff --git a/src/main/java/de/learnlib/ralib/oracles/Branching.java b/src/main/java/de/learnlib/ralib/oracles/Branching.java index 1347f2e5..ba5ac5a8 100644 --- a/src/main/java/de/learnlib/ralib/oracles/Branching.java +++ b/src/main/java/de/learnlib/ralib/oracles/Branching.java @@ -16,8 +16,10 @@ */ package de.learnlib.ralib.oracles; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Optional; +import java.util.Set; import de.learnlib.ralib.data.DataValue; import de.learnlib.ralib.data.Mapping; @@ -62,4 +64,11 @@ default Optional> getPrefix(Expression guard, Con return Optional.empty(); } + + default Set> guardSet() { + Set> guards = new LinkedHashSet<>(); + guards.addAll(getBranches().values()); + return guards; + } + } diff --git a/src/main/java/de/learnlib/ralib/smt/ConstraintSolver.java b/src/main/java/de/learnlib/ralib/smt/ConstraintSolver.java index 5de5e884..bb1f5827 100644 --- a/src/main/java/de/learnlib/ralib/smt/ConstraintSolver.java +++ b/src/main/java/de/learnlib/ralib/smt/ConstraintSolver.java @@ -17,6 +17,7 @@ package de.learnlib.ralib.smt; import java.util.HashMap; +import java.util.Optional; import java.util.Properties; import de.learnlib.ralib.data.DataValue; @@ -24,6 +25,7 @@ import de.learnlib.ralib.data.SymbolicDataValue; import gov.nasa.jpf.constraints.api.Expression; import gov.nasa.jpf.constraints.api.SolverContext; +import gov.nasa.jpf.constraints.api.Valuation; import gov.nasa.jpf.constraints.solvers.nativez3.NativeZ3SolverProvider; /** @@ -48,4 +50,14 @@ public boolean isSatisfiable(Expression expr, Mapping solve(Expression expr) { + Valuation res = new Valuation(); + gov.nasa.jpf.constraints.api.ConstraintSolver.Result r = solver.solve(expr, res); + if (r == gov.nasa.jpf.constraints.api.ConstraintSolver.Result.SAT) { + return Optional.of(res); + } + return Optional.empty(); + } + } diff --git a/src/main/java/de/learnlib/ralib/theory/Theory.java b/src/main/java/de/learnlib/ralib/theory/Theory.java index f668a152..dfc70ce7 100644 --- a/src/main/java/de/learnlib/ralib/theory/Theory.java +++ b/src/main/java/de/learnlib/ralib/theory/Theory.java @@ -29,8 +29,10 @@ import de.learnlib.ralib.data.WordValuation; import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; +import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; +import gov.nasa.jpf.constraints.api.Expression; import net.automatalib.word.Word; /** @@ -98,6 +100,12 @@ DataValue instantiate(Word prefix, Constants constants, SDTGuard guard, SuffixValue param, Set oldDvs); + public DataValue instantiate(Word prefix, + ParameterizedSymbol ps, Set pval, + Constants constants, + Expression guard, int param, + ConstraintSolver solver); + SuffixValueRestriction restrictSuffixValue(SuffixValue suffixValue, Word prefix, Word suffix, Constants consts); SuffixValueRestriction restrictSuffixValue(SDTGuard guard, Map prior); diff --git a/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java b/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java index 8c55ef5d..6429d916 100644 --- a/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java +++ b/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,6 +40,7 @@ import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.oracles.io.IOOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; +import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.*; import de.learnlib.ralib.theory.SDT; import de.learnlib.ralib.theory.SDTLeaf; @@ -46,6 +48,7 @@ import de.learnlib.ralib.words.OutputSymbol; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; +import gov.nasa.jpf.constraints.api.Expression; import net.automatalib.word.Word; /** @@ -408,6 +411,42 @@ private SDT makeRejectingBranch(int nextSufIndex, int maxIndex, DataType type) { } } + @Override + public DataValue instantiate(Word prefix, + ParameterizedSymbol ps, Set pval, + Constants constants, + Expression guard, int param, + ConstraintSolver solver) { + Parameter p = new Parameter(ps.getPtypes()[param-1], param); +// SuffixValue sv = new SuffixValue(ps.getPtypes()[param-1], param); + Set vals = DataWords.valSet(prefix, p.getDataType()); + vals.addAll(vals.stream() + .filter(v -> v.getDataType().equals(p.getDataType())) + .collect(Collectors.toSet())); + vals.addAll(constants.values()); + DataValue fresh = getFreshValue(new LinkedList<>(vals)); + + if (tryEquality(guard, p, fresh, solver, constants)) { + return fresh; + } + + for (DataValue val : vals) { + if (tryEquality(guard, p, val, solver, constants)) { + return val; + } + } + + throw new IllegalArgumentException("Guard is not equality/disequality: " + guard); + } + + private boolean tryEquality(Expression guard, Parameter p, DataValue val, ConstraintSolver solver, Constants consts) { +// SuffixValuation valuation = new SuffixValuation(); + Mapping valuation = new Mapping<>(); + valuation.put(p, val); + valuation.putAll(consts); + return solver.isSatisfiable(guard, valuation); + } + @Override public SuffixValueRestriction restrictSuffixValue(SuffixValue suffixValue, Word prefix, Word suffix, Constants consts) { // for now, use generic restrictions with equality theory diff --git a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java index 6997f19b..6e7a2c8c 100644 --- a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java +++ b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java @@ -23,16 +23,20 @@ import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import de.learnlib.ralib.data.*; import de.learnlib.ralib.data.SymbolicDataValue.Constant; +import de.learnlib.ralib.data.SymbolicDataValue.Parameter; import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; +import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.EquivalenceClassFilter; import de.learnlib.ralib.theory.FreshSuffixValue; import de.learnlib.ralib.theory.SDT; @@ -46,7 +50,10 @@ import gov.nasa.jpf.constraints.api.Expression; import gov.nasa.jpf.constraints.api.Valuation; import gov.nasa.jpf.constraints.api.Variable; +import gov.nasa.jpf.constraints.expressions.NumericBooleanExpression; +import gov.nasa.jpf.constraints.expressions.NumericComparator; import gov.nasa.jpf.constraints.solvers.nativez3.NativeZ3Solver; +import gov.nasa.jpf.constraints.util.ExpressionUtil; import net.automatalib.word.Word; /** @@ -603,6 +610,55 @@ public DataValue instantiate( return returnThis; } + public DataValue instantiate(Word prefix, + ParameterizedSymbol ps, Set pval, + Constants constants, + Expression guard, int param, + ConstraintSolver solver) { + Parameter p = new Parameter(ps.getPtypes()[param-1], param); +// SuffixValue sv = new SuffixValue(ps.getPtypes()[param-1], param); + Set vals = DataWords.valSet(prefix, p.getDataType()); + vals.addAll(vals.stream() + .filter(w -> w.getDataType().equals(p.getDataType())) + .collect(Collectors.toSet())); + DataValue fresh = getFreshValue(new LinkedList<>(vals)); + + if (tryEquality(guard, p, fresh, solver)) { + return fresh; + } + + List> diseqList = new LinkedList<>(); + vals.stream().forEach(d -> diseqList.add(new NumericBooleanExpression(p, NumericComparator.NE, d))); + Expression diseqs = ExpressionUtil.and(diseqList.toArray(new Expression[diseqList.size()])); + + Optional valuation = solver.solve(ExpressionUtil.and(guard, diseqs)); + if (valuation.isPresent()) { + BigDecimal dv = valuation.get().getValue(p); + assert dv != null : "No valuation for " + p + " in " + valuation; + return new DataValue(p.getDataType(), dv); + } + + for (DataValue val : vals) { + if (tryEquality(guard, p, val, solver)) { + return val; + } + } + + throw new IllegalArgumentException("Not a valid guard: " + guard); + } + + private boolean tryEquality(Expression guard, Parameter p, DataValue val, ConstraintSolver solver) { + ParameterValuation valuation = new ParameterValuation(); + valuation.put(p, val); + return solver.isSatisfiable(guard, valuation); + } +// private boolean tryEquality(Expression guard, SuffixValue sv, DataValue val, ConstraintSolver solver) { +// SuffixValuation valuation = new SuffixValuation(); +// valuation.put(sv, val); +// return solver.isSatisfiable(guard, valuation); +// } + + public void useSuffixOptimization(boolean useSuffixOpt) { this.useSuffixOpt = useSuffixOpt; } diff --git a/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java b/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java index 080d7bdb..6b4cae71 100644 --- a/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java +++ b/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java @@ -37,8 +37,8 @@ import de.learnlib.ralib.equivalence.IORandomWalk; import de.learnlib.ralib.learning.Hypothesis; import de.learnlib.ralib.learning.RaLearningAlgorithm; -import de.learnlib.ralib.learning.ralambda.RaDT; -import de.learnlib.ralib.learning.ralambda.RaLambda; +import de.learnlib.ralib.learning.ralambda.SLCT; +import de.learnlib.ralib.learning.ralambda.SLLambda; import de.learnlib.ralib.learning.rastar.RaStar; import de.learnlib.ralib.oracles.DataWordOracle; import de.learnlib.ralib.oracles.SimulatorOracle; @@ -249,11 +249,13 @@ public TreeOracle createTreeOracle(RegisterAutomaton hyp) { this.rastar = new RaStar(mto, hypFactory, mlo, consts, true, actions); break; case AbstractToolWithRandomWalk.LEARNER_SLLAMBDA: - this.rastar = new RaLambda(mto, hypFactory, mlo, consts, true, actions); - ((RaLambda)this.rastar).setSolver(solver); +// this.rastar = new RaLambda(mto, hypFactory, mlo, consts, true, actions); +// ((RaLambda)this.rastar).setSolver(solver); + this.rastar = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); break; case AbstractToolWithRandomWalk.LEARNER_RADT: - this.rastar = new RaDT(mto, hypFactory, mlo, consts, true, actions); +// this.rastar = new RaDT(mto, hypFactory, mlo, consts, true, actions); + this.rastar = new SLCT(mto, hypFactory, mlo, consts, true, solver, actions); break; default: throw new ConfigurationException("Unknown Learning algorithm: " + this.learner); diff --git a/src/main/java/de/learnlib/ralib/tools/IOSimulator.java b/src/main/java/de/learnlib/ralib/tools/IOSimulator.java index 35ebd306..8f95ba0b 100644 --- a/src/main/java/de/learnlib/ralib/tools/IOSimulator.java +++ b/src/main/java/de/learnlib/ralib/tools/IOSimulator.java @@ -37,8 +37,8 @@ import de.learnlib.ralib.learning.MeasuringOracle; import de.learnlib.ralib.learning.QueryStatistics; import de.learnlib.ralib.learning.RaLearningAlgorithm; -import de.learnlib.ralib.learning.ralambda.RaDT; -import de.learnlib.ralib.learning.ralambda.RaLambda; +import de.learnlib.ralib.learning.ralambda.SLCT; +import de.learnlib.ralib.learning.ralambda.SLLambda; import de.learnlib.ralib.learning.rastar.RaStar; import de.learnlib.ralib.oracles.DataWordOracle; import de.learnlib.ralib.oracles.SimulatorOracle; @@ -218,11 +218,13 @@ public TreeOracle createTreeOracle(RegisterAutomaton hyp) { this.rastar = new RaStar(mto, hypFactory, mlo, consts, true, actions); break; case AbstractToolWithRandomWalk.LEARNER_SLLAMBDA: - this.rastar = new RaLambda(mto, hypFactory, mlo, consts, true, actions); - ((RaLambda)this.rastar).setSolver(solver); +// this.rastar = new RaLambda(mto, hypFactory, mlo, consts, true, actions); +// ((RaLambda)this.rastar).setSolver(solver); + this.rastar = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); break; case AbstractToolWithRandomWalk.LEARNER_RADT: - this.rastar = new RaDT(mto, hypFactory, mlo, consts, true, actions); +// this.rastar = new RaDT(mto, hypFactory, mlo, consts, true, actions); + this.rastar = new SLCT(mto, hypFactory, mlo, consts, true, solver, actions); break; default: throw new ConfigurationException("Unknown Learning algorithm: " + this.learner); diff --git a/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java b/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java index 033a7798..452c7ef5 100644 --- a/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java +++ b/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java @@ -5,6 +5,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; @@ -12,12 +13,15 @@ import de.learnlib.ralib.data.SymbolicDataValue; import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; import de.learnlib.ralib.oracles.io.IOOracle; +import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.SDTGuard; import de.learnlib.ralib.theory.SuffixValueRestriction; import de.learnlib.ralib.theory.UnrestrictedSuffixValue; import de.learnlib.ralib.theory.equality.UniqueEqualityTheory; import de.learnlib.ralib.tools.classanalyzer.TypedTheory; import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import gov.nasa.jpf.constraints.api.Expression; import net.automatalib.word.Word; public class UniqueIntegerEqualityTheory extends UniqueEqualityTheory implements TypedTheory { @@ -63,6 +67,12 @@ public Collection getAllNextValues(List vals) { return ret; } + @Override + public DataValue instantiate(Word prefix, ParameterizedSymbol ps, Set pval, + Constants constants, Expression guard, int param, ConstraintSolver solver) { + throw new RuntimeException("Not implemented"); + } + @Override public SuffixValueRestriction restrictSuffixValue(SuffixValue suffixValue, Word prefix, Word suffix, Constants consts) { diff --git a/src/test/java/de/learnlib/ralib/RaLibLearningExperimentRunner.java b/src/test/java/de/learnlib/ralib/RaLibLearningExperimentRunner.java index be676121..7458225a 100644 --- a/src/test/java/de/learnlib/ralib/RaLibLearningExperimentRunner.java +++ b/src/test/java/de/learnlib/ralib/RaLibLearningExperimentRunner.java @@ -18,8 +18,8 @@ import de.learnlib.ralib.learning.MeasuringOracle; import de.learnlib.ralib.learning.RaLearningAlgorithm; import de.learnlib.ralib.learning.RaLearningAlgorithmName; -import de.learnlib.ralib.learning.ralambda.RaDT; -import de.learnlib.ralib.learning.ralambda.RaLambda; +import de.learnlib.ralib.learning.ralambda.SLCT; +import de.learnlib.ralib.learning.ralambda.SLLambda; import de.learnlib.ralib.learning.rastar.RaStar; import de.learnlib.ralib.oracles.DataWordOracle; import de.learnlib.ralib.oracles.TreeOracleFactory; @@ -125,11 +125,13 @@ public Hypothesis run(RaLearningAlgorithmName algorithmName, DataWordOracle data learner = new RaStar(mto, hypFactory, mlo, consts, ioMode, actionSymbols); break; case RALAMBDA: - learner = new RaLambda(mto, hypFactory, mlo, consts, ioMode, useOldAnalyzer, actionSymbols); - ((RaLambda)learner).setSolver(solver); +// learner = new RaLambda(mto, hypFactory, mlo, consts, ioMode, useOldAnalyzer, actionSymbols); +// ((RaLambda)learner).setSolver(solver); + learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, ioMode, solver, actionSymbols); break; case RADT: - learner = new RaDT(mto, hypFactory, mlo, consts, ioMode, actionSymbols); +// learner = new RaDT(mto, hypFactory, mlo, consts, ioMode, actionSymbols); + learner = new SLCT(mto, hypFactory, mlo, consts, ioMode, solver, actionSymbols); break; default: throw new UnsupportedOperationException(String.format("Algorithm %s not supported", algorithmName)); diff --git a/src/test/java/de/learnlib/ralib/automata/RaRunTest.java b/src/test/java/de/learnlib/ralib/automata/RaRunTest.java new file mode 100644 index 00000000..e5dc7b87 --- /dev/null +++ b/src/test/java/de/learnlib/ralib/automata/RaRunTest.java @@ -0,0 +1,80 @@ +package de.learnlib.ralib.automata; + +import java.math.BigDecimal; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import de.learnlib.ralib.RaLibTestSuite; +import de.learnlib.ralib.data.DataType; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.SymbolicDataValue; +import de.learnlib.ralib.data.SymbolicDataValue.Parameter; +import de.learnlib.ralib.data.SymbolicDataValue.Register; +import de.learnlib.ralib.data.VarMapping; +import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; +import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.RegisterGenerator; +import de.learnlib.ralib.words.InputSymbol; +import de.learnlib.ralib.words.PSymbolInstance; +import gov.nasa.jpf.constraints.api.Expression; +import gov.nasa.jpf.constraints.expressions.NumericBooleanExpression; +import gov.nasa.jpf.constraints.expressions.NumericComparator; +import gov.nasa.jpf.constraints.util.ExpressionUtil; +import net.automatalib.word.Word; + +public class RaRunTest extends RaLibTestSuite { + + final DataType DT = new DataType("int"); + final InputSymbol A = new InputSymbol("a", new DataType[] {DT}); + + @Test + public void testMutableRARun() { + MutableRegisterAutomaton ra = new MutableRegisterAutomaton(); + + RALocation l0 = ra.addInitialState(); + RALocation l1 = ra.addState(); + RALocation l2 = ra.addState(); + + ParameterGenerator pgen = new ParameterGenerator(); + RegisterGenerator rgen = new RegisterGenerator(); + Parameter p1 = pgen.next(DT); + Register r1 = rgen.next(DT); + + Expression gT = ExpressionUtil.TRUE; + Expression gEq = new NumericBooleanExpression(r1, NumericComparator.EQ, p1); + Expression gNe = new NumericBooleanExpression(r1, NumericComparator.NE, p1); + + VarMapping storeP1 = new VarMapping<>(); + storeP1.put(r1, p1); + + Assignment assP1 = new Assignment(storeP1); + Assignment assNo = new Assignment(new VarMapping<>()); + + ra.addTransition(l0, A, new InputTransition(gT, A, l0, l1, assP1)); + ra.addTransition(l1, A, new InputTransition(gEq, A, l1, l0, assNo)); + ra.addTransition(l1, A, new InputTransition(gNe, A, l1, l2, assP1)); + ra.addTransition(l2, A, new InputTransition(gEq, A, l2, l1, assP1)); + ra.addTransition(l2, A, new InputTransition(gNe, A, l2, l0, assNo)); + + DataValue dv1 = new DataValue(DT, BigDecimal.ONE); + DataValue dv2 = new DataValue(DT, BigDecimal.valueOf(2)); + PSymbolInstance psi1 = new PSymbolInstance(A, dv1); + PSymbolInstance psi2 = new PSymbolInstance(A, dv2); + Word word1 = Word.fromSymbols(psi1, psi1, psi2); + + RARun run = ra.getRun(word1); + + Assert.assertEquals(run.getLocation(0), l0); + Assert.assertEquals(run.getLocation(1), l1); + Assert.assertEquals(run.getLocation(2), l0); + Assert.assertEquals(run.getLocation(3), l1); + + Assert.assertTrue(run.getValuation(0).isEmpty()); + Assert.assertEquals(run.getValuation(1).get(r1), dv1); + Assert.assertEquals(run.getValuation(3).get(r1), dv2); + + Assert.assertEquals(run.getTransition(1), psi1); + Assert.assertEquals(run.getTransition(2), psi1); + Assert.assertEquals(run.getTransition(3), psi2); + } +} diff --git a/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java b/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java index caf2b993..8ba9706b 100644 --- a/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java +++ b/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java @@ -29,14 +29,25 @@ import org.testng.annotations.Test; import de.learnlib.ralib.RaLibTestSuite; +import de.learnlib.ralib.automata.Assignment; +import de.learnlib.ralib.automata.InputTransition; +import de.learnlib.ralib.automata.MutableRegisterAutomaton; +import de.learnlib.ralib.automata.RALocation; import de.learnlib.ralib.automata.RegisterAutomaton; +import de.learnlib.ralib.ceanalysis.PrefixFinder.Result; +import de.learnlib.ralib.ct.CTAutomatonBuilder; +import de.learnlib.ralib.ct.CTHypothesis; +import de.learnlib.ralib.ct.ClassificationTree; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.SymbolicDataValue; +import de.learnlib.ralib.data.SymbolicDataValue.Parameter; +import de.learnlib.ralib.data.SymbolicDataValue.Register; +import de.learnlib.ralib.data.VarMapping; import de.learnlib.ralib.dt.DTHyp; import de.learnlib.ralib.dt.DTLeaf; import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.learning.ralambda.RaLambda; import de.learnlib.ralib.learning.rastar.RaStar; import de.learnlib.ralib.oracles.DataWordOracle; import de.learnlib.ralib.oracles.SDTLogicOracle; @@ -44,10 +55,18 @@ import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; +import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; +import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.Theory; +import de.learnlib.ralib.tools.theories.DoubleInequalityTheory; import de.learnlib.ralib.tools.theories.IntegerEqualityTheory; +import de.learnlib.ralib.words.InputSymbol; import de.learnlib.ralib.words.PSymbolInstance; +import gov.nasa.jpf.constraints.api.Expression; +import gov.nasa.jpf.constraints.expressions.NumericBooleanExpression; +import gov.nasa.jpf.constraints.expressions.NumericComparator; +import gov.nasa.jpf.constraints.util.ExpressionUtil; import net.automatalib.word.Word; /** @@ -70,17 +89,32 @@ public void testPrefixFinder() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, new Constants(), solver); - SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); +// SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); +// +// TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> +// new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, +// new Constants(), solver); - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, - new Constants(), solver); +// RaStar rastar = new RaStar(mto, hypFactory, slo, +// consts, I_LOGIN, I_LOGOUT, I_REGISTER); + + SymbolicSuffixRestrictionBuilder rb = new SymbolicSuffixRestrictionBuilder(consts, teachers); + OptimizedSymbolicSuffixBuilder sb = new OptimizedSymbolicSuffixBuilder(consts, rb); + ClassificationTree ct = new ClassificationTree(mto, solver, rb, sb, consts, false, + I_LOGIN, I_LOGOUT, I_REGISTER); + + ct.initialize(); + boolean closed = false; + while(!closed) { + closed = ct.checkLocationClosedness() && + ct.checkTransitionClosedness() && + ct.checkRegisterClosedness(); + } + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, false, solver); + final CTHypothesis hyp = ab.buildHypothesis(); - RaStar rastar = new RaStar(mto, hypFactory, slo, - consts, I_LOGIN, I_LOGOUT, I_REGISTER); - - rastar.learn(); - final Hypothesis hyp = rastar.getHypothesis(); +// rastar.learn(); +// final Hypothesis hyp = rastar.getHypothesis(); // System.out.println(hyp); Word ce = Word.fromSymbols( @@ -89,63 +123,190 @@ public void testPrefixFinder() { new PSymbolInstance(I_LOGIN, new DataValue(T_UID, BigDecimal.ONE), new DataValue(T_PWD, BigDecimal.ONE))); - PrefixFinder pf = new PrefixFinder( - mto, - hypFactory.createTreeOracle(hyp), hyp, - slo, - // rastar.getComponents(), - consts - ); + PrefixFinder pf = new PrefixFinder(mto, hyp, ct, teachers, rb, solver, consts); + +// PrefixFinder pf = new PrefixFinder( +// MTO, +// HYPFACTORY.CREATETREEORACLE(HYP), HYP, +// SLO, +// // RASTAR.GETCOMPONENTS(), +// CONSTS +// ); - Word prefix = pf.analyzeCounterexample(ce).getPrefix(); - Assert.assertEquals(prefix.toString(), "register[0[T_uid], 0[T_pwd]]"); +// Word prefix = pf.analyzeCounterexample(ce).getPrefix(); + Result res = pf.analyzeCounterExample(ce); + Word prefix = res.prefix(); + Assert.assertEquals(res.result(), PrefixFinder.ResultType.LOCATION); + Assert.assertEquals(prefix.toString(), "register[0[T_uid], 0[T_pwd]]"); } @Test public void testPrefixFinderMultipleAccessSequences() { - Constants consts = new Constants(); - RegisterAutomaton sul = de.learnlib.ralib.example.stack.StackAutomatonExample.AUTOMATON; - DataWordOracle dwOracle = new SimulatorOracle(sul); + Constants consts = new Constants(); + RegisterAutomaton sul = de.learnlib.ralib.example.stack.StackAutomatonExample.AUTOMATON; + DataWordOracle dwOracle = new SimulatorOracle(sul); - final Map teachers = new LinkedHashMap<>(); - teachers.put(T_INT, new IntegerEqualityTheory(T_INT)); + final Map teachers = new LinkedHashMap<>(); + teachers.put(T_INT, new IntegerEqualityTheory(T_INT)); ConstraintSolver solver = new ConstraintSolver(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, new Constants(), solver); - SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, - new Constants(), solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, slo, - consts, I_PUSH, I_POP); - - ralambda.learn(); - final DTHyp hyp = ralambda.getDTHyp(); +// SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); +// +// TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> +// new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, +// new Constants(), solver); +// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, +// consts, I_PUSH, I_POP); +// +// ralambda.learn(); +// final DTHyp hyp = ralambda.getDTHyp(); // System.out.println(hyp); + SymbolicSuffixRestrictionBuilder rb = new SymbolicSuffixRestrictionBuilder(consts, teachers); + OptimizedSymbolicSuffixBuilder sb = new OptimizedSymbolicSuffixBuilder(consts, rb); + ClassificationTree ct = new ClassificationTree(mto, solver, rb, sb, consts, false, + I_PUSH, I_POP); + + ct.initialize(); + boolean closed = false; + while(!closed) { + closed = ct.checkLocationClosedness() && + ct.checkTransitionClosedness() && + ct.checkRegisterClosedness(); + } + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, false, solver); + final CTHypothesis hyp = ab.buildHypothesis(); + Word shortPrefix = Word.fromSymbols( new PSymbolInstance(I_PUSH, new DataValue(T_INT, BigDecimal.ZERO))); - DTLeaf leaf = ralambda.getDT().getLeaf(shortPrefix); - leaf.elevatePrefix(ralambda.getDT(), shortPrefix, hyp, slo); +// DTLeaf leaf = ralambda.getDT().getLeaf(shortPrefix); +// leaf.elevatePrefix(ralambda.getDT(), shortPrefix, hyp, slo); + ct.expand(shortPrefix); Word ce = Word.fromSymbols( new PSymbolInstance(I_PUSH, new DataValue(T_INT, BigDecimal.ZERO)), new PSymbolInstance(I_POP, new DataValue(T_INT, BigDecimal.ZERO)), new PSymbolInstance(I_PUSH, new DataValue(T_INT, BigDecimal.ONE))); - PrefixFinder pf = new PrefixFinder( - mto, - hypFactory.createTreeOracle(hyp), hyp, - slo, - // ralambda.getComponents(), - consts - ); +// PrefixFinder pf = new PrefixFinder( +// mto, +// hypFactory.createTreeOracle(hyp), hyp, +// slo, +// // ralambda.getComponents(), +// consts +// ); + + PrefixFinder pf = new PrefixFinder(mto, hyp, ct, teachers, rb, solver, consts); + +// Word prefix = pf.analyzeCounterexample(ce).getPrefix(); + Result res = pf.analyzeCounterExample(ce); + Assert.assertEquals(res.result(), PrefixFinder.ResultType.TRANSITION); + Assert.assertEquals(res.prefix().toString(), "push[0[T_int]] pop[0[T_int]]"); + } + + private final DataType DT = new DataType("double"); + private final InputSymbol A = new InputSymbol("α", DT); + private final InputSymbol B = new InputSymbol("β"); + + private RegisterAutomaton buildTestAutomaton() { + MutableRegisterAutomaton ra = new MutableRegisterAutomaton(); + + Register x1 = new Register(DT, 1); + Parameter p1 = new Parameter(DT, 1); + + RALocation l0 = ra.addInitialState(true); + RALocation l1 = ra.addState(false); + RALocation l2 = ra.addState(false); + RALocation l3 = ra.addState(false); + + Expression gTrue = ExpressionUtil.TRUE; + Expression gGT = new NumericBooleanExpression(x1, NumericComparator.GE, p1); + Expression gLT = new NumericBooleanExpression(x1, NumericComparator.LT, p1); + + VarMapping mapX1P1 = new VarMapping<>(); + mapX1P1.put(x1, p1); + VarMapping mapNo = new VarMapping<>(); + + Assignment assX1P1 = new Assignment(mapX1P1); + Assignment assNo = new Assignment(mapNo); + + ra.addTransition(l0, A, new InputTransition(gTrue, A, l0, l1, assX1P1)); + ra.addTransition(l0, B, new InputTransition(gTrue, B, l0, l0, assNo)); + ra.addTransition(l1, A, new InputTransition(gGT, A, l1, l2, assNo)); + ra.addTransition(l1, A, new InputTransition(gLT, A, l1, l3, assNo)); + ra.addTransition(l1, B, new InputTransition(gTrue, B, l1, l0, assNo)); + ra.addTransition(l2, A, new InputTransition(gTrue, A, l2, l0, assNo)); + ra.addTransition(l2, B, new InputTransition(gTrue, B, l2, l2, assNo)); + ra.addTransition(l3, A, new InputTransition(gTrue, A, l3, l0, assNo)); + ra.addTransition(l3, B, new InputTransition(gTrue, B, l3, l0, assNo)); + + return ra; + } + + @Test + public void testAnalyzeCELocation() { + RegisterAutomaton ra = buildTestAutomaton(); + DataWordOracle dwOracle = new SimulatorOracle(ra); + + final Map teachers = new LinkedHashMap<>(); + DoubleInequalityTheory dit = new DoubleInequalityTheory(DT); + dit.useSuffixOptimization(false); + teachers.put(DT, dit); + + ConstraintSolver solver = new ConstraintSolver(); + Constants consts = new Constants(); + + MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(dwOracle, teachers, consts, solver); + + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); + OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); + + DataValue dv0 = new DataValue(DT, BigDecimal.ZERO); + DataValue dv1 = new DataValue(DT, BigDecimal.ONE); + DataValue dv2 = new DataValue(DT, BigDecimal.valueOf(2)); + DataValue dv3 = new DataValue(DT, BigDecimal.valueOf(3)); + + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, false, A, B); + + ct.initialize(); + ct.checkLocationClosedness(); + ct.checkLocationClosedness(); - Word prefix = pf.analyzeCounterexample(ce).getPrefix(); - Assert.assertEquals(prefix.toString(), "push[0[T_int]] pop[0[T_int]]"); + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), false, solver); + CTHypothesis hyp = ab.buildHypothesis(); + + Word ce1 = Word.fromSymbols( + new PSymbolInstance(A, dv1), + new PSymbolInstance(A, dv2), + new PSymbolInstance(A, dv3)); + + PrefixFinder pf = new PrefixFinder(mto, hyp, ct, teachers, restrBuilder, solver, consts); + + Result res = pf.analyzeCounterExample(ce1); + Assert.assertEquals(res.result(), PrefixFinder.ResultType.LOCATION); + Assert.assertEquals(res.prefix().toString(), "α[1[double]] α[2[double]]"); + + ct.expand(res.prefix()); + boolean consistent = ct.checkLocationConsistency(); + Assert.assertFalse(consistent); + + ab = new CTAutomatonBuilder(ct, consts, false, solver); + hyp = ab.buildHypothesis(); + pf = new PrefixFinder(mto, hyp, ct, teachers, restrBuilder, solver, consts); + + Word ce2 = Word.fromSymbols( + new PSymbolInstance(A, dv1), + new PSymbolInstance(A, dv0), + new PSymbolInstance(B)); + + Assert.assertFalse(hyp.accepts(ce2) == ra.accepts(ce2)); + + res = pf.analyzeCounterExample(ce2); + Assert.assertEquals(res.result(), PrefixFinder.ResultType.TRANSITION); + Assert.assertEquals(res.prefix().toString(), "α[1[double]] α[0[double]]"); } } diff --git a/src/test/java/de/learnlib/ralib/ct/CTTest.java b/src/test/java/de/learnlib/ralib/ct/CTTest.java index 21de0c49..c5298f71 100644 --- a/src/test/java/de/learnlib/ralib/ct/CTTest.java +++ b/src/test/java/de/learnlib/ralib/ct/CTTest.java @@ -145,7 +145,7 @@ public void testStackCT() { Assert.assertTrue(ct.getLeaf(w3).getRepresentativePrefix().getRegisters().contains(dv0)); Assert.assertTrue(ct.getLeaf(w3).getRepresentativePrefix().getRegisters().contains(dv1)); - CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, false); + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, false, solver); Hypothesis hyp = ab.buildHypothesis(); Assert.assertEquals(hyp.getStates().size(), 4); @@ -239,7 +239,7 @@ public void testPQCT() { - CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), false); + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), false, solver); Hypothesis hyp = ab.buildHypothesis(); Assert.assertEquals(hyp.getStates().size(), ct.getLeaves().size()); @@ -322,7 +322,7 @@ public void testCTAutomatonBuilder() { System.out.println(ct); - CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), true); + CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), true, solver); Hypothesis hyp = ab.buildHypothesis(); System.out.println(hyp); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/GeneratedHypothesesTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/GeneratedHypothesesTest.java index 678267cf..4f19abbf 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/GeneratedHypothesesTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/GeneratedHypothesesTest.java @@ -1,69 +1,72 @@ -package de.learnlib.ralib.learning.ralambda; - -import static de.learnlib.ralib.example.stack.StackAutomatonExample.AUTOMATON; -import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_POP; -import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_PUSH; -import static de.learnlib.ralib.example.stack.StackAutomatonExample.T_INT; - -import java.util.LinkedHashMap; -import java.util.Map; - -import org.testng.Assert; -import org.testng.annotations.Test; - -import de.learnlib.ralib.RaLibTestSuite; -import de.learnlib.ralib.automata.RegisterAutomaton; -import de.learnlib.ralib.data.Constants; -import de.learnlib.ralib.data.DataType; -import de.learnlib.ralib.dt.DTHyp; -import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.learning.Measurements; -import de.learnlib.ralib.learning.MeasuringOracle; -import de.learnlib.ralib.oracles.DataWordOracle; -import de.learnlib.ralib.oracles.SDTLogicOracle; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; -import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; -import de.learnlib.ralib.smt.ConstraintSolver; -import de.learnlib.ralib.theory.Theory; -import de.learnlib.ralib.tools.theories.IntegerEqualityTheory; - -public class GeneratedHypothesesTest extends RaLibTestSuite { - - /** - * Tests that {@link RaLambda#getHypothesis()} returns a generic {@link Hypothesis} - * (and not a specialized Hypothesis, such as a {@link DTHyp}, which is a lot slower) - */ - @Test - public void testGetHypothesis() { - Constants consts = new Constants(); - RegisterAutomaton sul = AUTOMATON; - DataWordOracle dwOracle = new SimulatorOracle(sul); - ConstraintSolver solver = new ConstraintSolver(); - - final Map teachers = new LinkedHashMap<>(); - IntegerEqualityTheory theory = new IntegerEqualityTheory(T_INT); - theory.setUseSuffixOpt(false); - teachers.put(T_INT, theory); - - Measurements mes = new Measurements(); - - MeasuringOracle mto = new MeasuringOracle(new MultiTheoryTreeOracle( - dwOracle, teachers, new Constants(), solver), mes); - - SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, - new Constants(), solver); - - RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); - ralambda.setSolver(solver); - - ralambda.learn(); - RegisterAutomaton hyp = ralambda.getHypothesis(); - - Assert.assertEquals(hyp.getClass(), Hypothesis.class); - } -} +//package de.learnlib.ralib.learning.ralambda; +// +//import static de.learnlib.ralib.example.stack.StackAutomatonExample.AUTOMATON; +//import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_POP; +//import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_PUSH; +//import static de.learnlib.ralib.example.stack.StackAutomatonExample.T_INT; +// +//import java.util.LinkedHashMap; +//import java.util.Map; +// +//import org.testng.Assert; +//import org.testng.annotations.Ignore; +//import org.testng.annotations.Test; +// +//import de.learnlib.ralib.RaLibTestSuite; +//import de.learnlib.ralib.automata.RegisterAutomaton; +//import de.learnlib.ralib.data.Constants; +//import de.learnlib.ralib.data.DataType; +//import de.learnlib.ralib.dt.DTHyp; +//import de.learnlib.ralib.learning.Hypothesis; +//import de.learnlib.ralib.learning.Measurements; +//import de.learnlib.ralib.learning.MeasuringOracle; +//import de.learnlib.ralib.oracles.DataWordOracle; +//import de.learnlib.ralib.oracles.SDTLogicOracle; +//import de.learnlib.ralib.oracles.SimulatorOracle; +//import de.learnlib.ralib.oracles.TreeOracleFactory; +//import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; +//import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; +//import de.learnlib.ralib.smt.ConstraintSolver; +//import de.learnlib.ralib.theory.Theory; +//import de.learnlib.ralib.tools.theories.IntegerEqualityTheory; +// +//@Ignore +//public class GeneratedHypothesesTest extends RaLibTestSuite { +// +// /** +// * Tests that {@link RaLambda#getHypothesis()} returns a generic {@link Hypothesis} +// * (and not a specialized Hypothesis, such as a {@link DTHyp}, which is a lot slower) +// * +// */ +// @Test +// public void testGetHypothesis() { +// Constants consts = new Constants(); +// RegisterAutomaton sul = AUTOMATON; +// DataWordOracle dwOracle = new SimulatorOracle(sul); +// ConstraintSolver solver = new ConstraintSolver(); +// +// final Map teachers = new LinkedHashMap<>(); +// IntegerEqualityTheory theory = new IntegerEqualityTheory(T_INT); +// theory.setUseSuffixOpt(false); +// teachers.put(T_INT, theory); +// +// Measurements mes = new Measurements(); +// +// MeasuringOracle mto = new MeasuringOracle(new MultiTheoryTreeOracle( +// dwOracle, teachers, new Constants(), solver), mes); +// +// SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); +// +// TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> +// new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, +// new Constants(), solver); +// +// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); +// ralambda.setSolver(solver); +// +// ralambda.learn(); +// RegisterAutomaton hyp = ralambda.getHypothesis(); +// +// Assert.assertEquals(hyp.getClass(), Hypothesis.class); +// } +//} diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java index c72f2008..c8d95af8 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java @@ -219,20 +219,21 @@ public void testLearnIORAWithNoOutputParams() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, IN, OK, NOK); +// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, IN, OK, NOK); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, IN, OK, NOK); - ralambda.learn(); + sllambda.learn(); - RegisterAutomaton hyp = ralambda.getHypothesis(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP1: {0}", hyp); Word ce = Word.fromSymbols(new PSymbolInstance(IN, new DataValue(ID, BigDecimal.ZERO)), new PSymbolInstance(OK), new PSymbolInstance(IN, new DataValue(ID, BigDecimal.ONE)), new PSymbolInstance(NOK)); - ralambda.addCounterexample(new DefaultQuery<>(ce, model.accepts(ce))); + sllambda.addCounterexample(new DefaultQuery<>(ce, model.accepts(ce))); - ralambda.learn(); - hyp = ralambda.getHypothesis(); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP2: {0}", hyp); Assert.assertTrue(hyp.accepts(ce)); IOEquivalenceTest test = new IOEquivalenceTest(model, teachers, consts, true, IN, OK, NOK); @@ -266,11 +267,12 @@ public void testLearnIORAWithEqualOutputParam() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, IN, NOK, OUT); +// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, IN, NOK, OUT); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, IN, NOK, OUT); - ralambda.learn(); + sllambda.learn(); - RegisterAutomaton hyp = ralambda.getHypothesis(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP1: {0}", hyp); // Word ce = Word.fromSymbols(new PSymbolInstance(IN, new DataValue(ID, 0)), @@ -280,10 +282,10 @@ public void testLearnIORAWithEqualOutputParam() { new PSymbolInstance(OUT, new DataValue(ID, BigDecimal.ZERO)), new PSymbolInstance(IN, new DataValue(ID, BigDecimal.ONE)), new PSymbolInstance(NOK)); - ralambda.addCounterexample(new DefaultQuery<>(ce, model.accepts(ce))); + sllambda.addCounterexample(new DefaultQuery<>(ce, model.accepts(ce))); - ralambda.learn(); - hyp = ralambda.getHypothesis(); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP2: {0}", hyp); Assert.assertTrue(hyp.accepts(ce)); IOEquivalenceTest test = new IOEquivalenceTest(model, teachers, consts, true, IN, NOK, OUT); @@ -317,21 +319,22 @@ public void testLearnIORAWithFreshOutputParam() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, IN, NOK, OUT); +// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, IN, NOK, OUT); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, IN, NOK, OUT); - ralambda.learn(); + sllambda.learn(); - RegisterAutomaton hyp = ralambda.getHypothesis(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP1: {0}", hyp); Word ce = Word.fromSymbols(new PSymbolInstance(IN, new DataValue(ID, BigDecimal.ZERO)), new PSymbolInstance(OUT, new DataValue(ID, BigDecimal.ONE)), new PSymbolInstance(IN, new DataValue(ID, BigDecimal.ONE)), new PSymbolInstance(NOK)); - ralambda.addCounterexample(new DefaultQuery<>(ce, model.accepts(ce))); + sllambda.addCounterexample(new DefaultQuery<>(ce, model.accepts(ce))); - ralambda.learn(); - hyp = ralambda.getHypothesis(); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP2: {0}", hyp); Assert.assertTrue(hyp.accepts(ce)); IOEquivalenceTest test = new IOEquivalenceTest(model, teachers, consts, true, IN, NOK, OUT); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java index 85489467..67e11ba1 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java @@ -86,8 +86,9 @@ public void testLearnABPOutput() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); - ralambda.setSolver(solver); +// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); +// ralambda.setSolver(solver); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); IOEquivalenceTest ioEquiv = new IOEquivalenceTest( model, teachers, consts, true, actions); @@ -112,8 +113,8 @@ public void testLearnABPOutput() { inputs); for (int check = 0; check < 100; ++check) { - ralambda.learn(); - Hypothesis hyp = ralambda.getHypothesis(); + sllambda.learn(); + Hypothesis hyp = sllambda.getHypothesis(); ce = null; @@ -143,10 +144,10 @@ public void testLearnABPOutput() { Assert.assertTrue(model.accepts(ce.getInput())); Assert.assertFalse(hyp.accepts(ce.getInput())); - ralambda.addCounterexample(ce); + sllambda.addCounterexample(ce); } - RegisterAutomaton hyp = ralambda.getHypothesis(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "FINAL HYP: {0}", hyp); ce = ioEquiv.findCounterExample(hyp, null); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java index 506c2c30..98d37594 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java @@ -59,7 +59,8 @@ public void testLearnEcho() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda learner = new RaLambda(mto, hypFactory, mlo, consts, true, sul.getActionSymbols()); +// RaLambda learner = new RaLambda(mto, hypFactory, mlo, consts, true, sul.getActionSymbols()); + SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, sul.getActionSymbols()); learner.learn(); Word ce = Word.fromSymbols( diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java index f80a04f7..b16f11c0 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java @@ -61,12 +61,14 @@ public void testLearnLogin() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, slo, - consts, I_LOGIN, I_LOGOUT, I_REGISTER); - ralambda.setSolver(solver); - - ralambda.learn(); - RegisterAutomaton hyp = ralambda.getHypothesis(); +// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, +// consts, I_LOGIN, I_LOGOUT, I_REGISTER); + SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, + consts, false, solver, I_LOGIN, I_LOGOUT, I_REGISTER); +// sllambda.setSolver(solver); + + sllambda.learn(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP1: {0}", hyp); Word ce = Word.fromSymbols( @@ -75,10 +77,10 @@ public void testLearnLogin() { new PSymbolInstance(I_LOGIN, new DataValue(T_UID, BigDecimal.ZERO), new DataValue(T_PWD, BigDecimal.ZERO))); - ralambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); + sllambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); - ralambda.learn(); - hyp = ralambda.getHypothesis(); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP2: {0}", hyp); Assert.assertEquals(hyp.getStates().size(), 3); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java index 6fdfdf10..2dfce1a5 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java @@ -106,8 +106,9 @@ public void testLearnMixedIO() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda rastar = new RaLambda(mto, hypFactory, mlo, consts, true, actions); - rastar.setSolver(solver); +// RaLambda rastar = new RaLambda(mto, hypFactory, mlo, consts, true, actions); +// rastar.setSolver(solver); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); IORandomWalk iowalk = new IORandomWalk(random, sul, @@ -127,8 +128,8 @@ public void testLearnMixedIO() { IOCounterExamplePrefixFinder pref = new IOCounterExamplePrefixFinder(ioOracle); for (int check = 0; check < 100; ++check) { - rastar.learn(); - Hypothesis hyp = rastar.getHypothesis(); + sllambda.learn(); + Hypothesis hyp = sllambda.getHypothesis(); DefaultQuery ce = iowalk.findCounterExample(hyp, null); if (ce == null) { @@ -142,10 +143,10 @@ public void testLearnMixedIO() { Assert.assertTrue(model.accepts(ce.getInput())); Assert.assertFalse(hyp.accepts(ce.getInput())); - rastar.addCounterexample(ce); + sllambda.addCounterexample(ce); } - RegisterAutomaton hyp = rastar.getHypothesis(); + RegisterAutomaton hyp = sllambda.getHypothesis(); IOEquivalenceTest checker = new IOEquivalenceTest( model, teachers, consts, true, actions); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java index 457fc638..32acf928 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java @@ -114,8 +114,10 @@ private Hypothesis learnPQ(long seed, Map teachers, Constants TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda rastar = new RaLambda(mto, hypFactory, mlo, - consts, true, sul.getActionSymbols()); +// RaLambda rastar = new RaLambda(mto, hypFactory, mlo, +// consts, true, sul.getActionSymbols()); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, + consts, true, solver, sul.getActionSymbols()); IORandomWalk iowalk = new IORandomWalk(random, sul, @@ -135,8 +137,8 @@ private Hypothesis learnPQ(long seed, Map teachers, Constants IOCounterExamplePrefixFinder pref = new IOCounterExamplePrefixFinder(ioOracle); for (int check = 0; check < 100; ++check) { - rastar.learn(); - Hypothesis hyp = rastar.getHypothesis(); + sllambda.learn(); + Hypothesis hyp = sllambda.getHypothesis(); DefaultQuery ce = iowalk.findCounterExample(hyp, null); //System.out.println("CE: " + ce); @@ -147,9 +149,9 @@ private Hypothesis learnPQ(long seed, Map teachers, Constants ce = loops.optimizeCE(ce.getInput(), hyp); ce = asrep.optimizeCE(ce.getInput(), hyp); ce = pref.optimizeCE(ce.getInput(), hyp); - rastar.addCounterexample(ce); + sllambda.addCounterexample(ce); } - return rastar.getHypothesis(); + return sllambda.getHypothesis(); } } diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java index 4498795d..41aafd9e 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java @@ -79,9 +79,10 @@ public void testLearnPQ() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - RaLambda rastar = new RaLambda(mto, hypFactory, mlo, consts, OFFER, POLL); - rastar.learn(); - RegisterAutomaton hyp = rastar.getHypothesis(); +// RaLambda rastar = new RaLambda(mto, hypFactory, mlo, consts, OFFER, POLL); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, false, solver, OFFER, POLL); + sllambda.learn(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP1: {0}", hyp); Word ce = Word.fromSymbols( @@ -96,10 +97,10 @@ public void testLearnPQ() { DefaultQuery ceQuery = new DefaultQuery<>(ce, true); - rastar.addCounterexample(ceQuery); + sllambda.addCounterexample(ceQuery); - rastar.learn(); - hyp = rastar.getHypothesis(); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP2: {0}", hyp); Assert.assertTrue(hyp.accepts(ceQuery.getInput())); @@ -114,9 +115,9 @@ public void testLearnPQ() { new PSymbolInstance(POLL, new DataValue(doubleType, BigDecimal.valueOf(2.0)))); DefaultQuery ce2Query = new DefaultQuery<>(ce2, true); - rastar.addCounterexample(ce2Query); - rastar.learn(); - hyp = rastar.getHypothesis(); + sllambda.addCounterexample(ce2Query); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP3: {0}", hyp); Assert.assertTrue(hyp.accepts(ce2Query.getInput())); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java index 0f3ef3a5..3245b1d0 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java @@ -117,11 +117,12 @@ public void testLearnPadlock() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, true, IN); - ralambda.setSolver(solver); +// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, true, IN); +// ralambda.setSolver(solver); + SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, IN); - ralambda.learn(); - RegisterAutomaton hyp = ralambda.getHypothesis(); + sllambda.learn(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP0: {0}", hyp); Word ce = Word.fromSymbols( @@ -130,10 +131,10 @@ public void testLearnPadlock() { new PSymbolInstance(IN, new DataValue(DIGIT, BigDecimal.ZERO)), new PSymbolInstance(IN, new DataValue(DIGIT, BigDecimal.ZERO))); - ralambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); + sllambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); - ralambda.learn(); - hyp = ralambda.getHypothesis(); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP1: {0}", hyp); } } diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java index c54d593f..b67148f3 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java @@ -72,15 +72,16 @@ public void testLearnPalindromeIO() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); - ralambda.setSolver(solver); - +// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); +// ralambda.setSolver(solver); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + IOEquivalenceTest ioEquiv = new IOEquivalenceTest( model, teachers, consts, true, actions); for (int check = 0; check < 10; ++check) { - ralambda.learn(); - Hypothesis hyp = ralambda.getHypothesis(); + sllambda.learn(); + Hypothesis hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP: {0}", hyp); DefaultQuery ce = ioEquiv.findCounterExample(hyp, null); @@ -92,10 +93,10 @@ public void testLearnPalindromeIO() { Assert.assertTrue(model.accepts(ce.getInput())); Assert.assertFalse(hyp.accepts(ce.getInput())); - ralambda.addCounterexample(ce); + sllambda.addCounterexample(ce); } - RegisterAutomaton hyp = ralambda.getHypothesis(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "FINAL HYP: {0}", hyp); DefaultQuery ce = ioEquiv.findCounterExample(hyp, null); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java index b38840c5..2559eb4d 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java @@ -63,9 +63,9 @@ public void testLearnRepeater() { Measurements measurements = new Measurements(); QueryStatistics stats = new QueryStatistics(measurements, ioOracle); - RaLambda learner = new RaLambda(mto, hypFactory, mlo, consts, true, sul.getActionSymbols()); + SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, sul.getActionSymbols()); learner.setStatisticCounter(stats); - learner.setSolver(solver); +// learner.setSolver(solver); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java index 7fab29c3..d598057b 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java @@ -96,8 +96,9 @@ public void testLearnSipIO() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); - ralambda.setSolver(solver); +// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); +// sllambda.setSolver(solver); IOEquivalenceTest ioEquiv = new IOEquivalenceTest( model, teachers, consts, true, actions); @@ -107,8 +108,8 @@ public void testLearnSipIO() { IOCounterExamplePrefixFinder pref = new IOCounterExamplePrefixFinder(ioOracle); for (int check = 0; check < 100; ++check) { - ralambda.learn(); - Hypothesis hyp = ralambda.getHypothesis(); + sllambda.learn(); + Hypothesis hyp = sllambda.getHypothesis(); DefaultQuery ce = ioEquiv.findCounterExample(hyp, null); if (ce == null) { @@ -122,10 +123,10 @@ public void testLearnSipIO() { Assert.assertTrue(model.accepts(ce.getInput())); Assert.assertFalse(hyp.accepts(ce.getInput())); - ralambda.addCounterexample(ce); + sllambda.addCounterexample(ce); } - RegisterAutomaton hyp = ralambda.getHypothesis(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "FINAL HYP: {0}", hyp); DefaultQuery ce = ioEquiv.findCounterExample(hyp, null); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java index 300c98ce..90ba02d4 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java @@ -49,7 +49,7 @@ public class LearnStackTest extends RaLibTestSuite { @Test public void testLearnStack() { - Constants consts = new Constants(); + Constants consts = new Constants(); RegisterAutomaton sul = AUTOMATON; DataWordOracle dwOracle = new SimulatorOracle(sul); @@ -69,21 +69,24 @@ public void testLearnStack() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); - ralambda.setSolver(solver); +// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); +// ralambda.setSolver(solver); + SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, I_PUSH, I_POP); - ralambda.learn(); - RegisterAutomaton hyp = ralambda.getHypothesis(); +// ralambda.learn(); +// RegisterAutomaton hyp = ralambda.getHypothesis(); + sllambda.learn(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP0: {0}", hyp); Word ce = Word.fromSymbols( new PSymbolInstance(I_PUSH, new DataValue(T_INT, BigDecimal.ZERO)), new PSymbolInstance(I_POP, new DataValue(T_INT, BigDecimal.ZERO))); - ralambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); + sllambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); - ralambda.learn(); - hyp = ralambda.getHypothesis(); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP1: {0}", hyp); ce = Word.fromSymbols( @@ -91,10 +94,10 @@ public void testLearnStack() { new PSymbolInstance(I_PUSH, new DataValue(T_INT, BigDecimal.ONE)), new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(2)))); - ralambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); + sllambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); - ralambda.learn(); - hyp = ralambda.getHypothesis(); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP2: {0}", hyp); Assert.assertEquals(hyp.getStates().size(), 4); @@ -121,13 +124,14 @@ public void testLearnStackSwitchedCE() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); - ralambda.setSolver(solver); +// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); +// ralambda.setSolver(solver); + SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, I_PUSH, I_POP); - ralambda.learn(); - RegisterAutomaton hyp = ralambda.getHypothesis(); + sllambda.learn(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP0: {0}", hyp); - hyp = ralambda.getHypothesis(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP1: {0}", hyp); Word ce = Word.fromSymbols( @@ -135,20 +139,20 @@ public void testLearnStackSwitchedCE() { new PSymbolInstance(I_PUSH, new DataValue(T_INT, BigDecimal.ONE)), new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(2)))); - ralambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); + sllambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); - ralambda.learn(); - hyp = ralambda.getHypothesis(); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP2: {0}", hyp); ce = Word.fromSymbols( new PSymbolInstance(I_PUSH, new DataValue(T_INT, BigDecimal.ZERO)), new PSymbolInstance(I_POP, new DataValue(T_INT, BigDecimal.ZERO))); - ralambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); + sllambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); - ralambda.learn(); - hyp = ralambda.getHypothesis(); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP2: {0}", hyp); ce = Word.fromSymbols( @@ -156,22 +160,22 @@ public void testLearnStackSwitchedCE() { new PSymbolInstance(I_PUSH, new DataValue(T_INT, BigDecimal.ONE)), new PSymbolInstance(I_POP, new DataValue(T_INT, BigDecimal.ONE))); - ralambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); - ralambda.learn(); - hyp = ralambda.getHypothesis(); + sllambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); + sllambda.learn(); + hyp = sllambda.getHypothesis(); - Collection suffixes = ralambda.getDT().getSuffixes(); - Set> suffixActions = suffixes.stream().map(s -> s.getActions()).collect(Collectors.toSet()); - Set> expectedSuffixActions = ImmutableSet.of( - Word.fromSymbols(), - Word.fromSymbols(I_PUSH), - Word.fromSymbols(I_PUSH, I_PUSH), - Word.fromSymbols(I_POP), - Word.fromSymbols(I_POP, I_POP)); +// Collection suffixes = ralambda.getDT().getSuffixes(); +// Set> suffixActions = suffixes.stream().map(s -> s.getActions()).collect(Collectors.toSet()); +// Set> expectedSuffixActions = ImmutableSet.of( +// Word.fromSymbols(), +// Word.fromSymbols(I_PUSH), +// Word.fromSymbols(I_PUSH, I_PUSH), +// Word.fromSymbols(I_POP), +// Word.fromSymbols(I_POP, I_POP)); Assert.assertEquals(hyp.getStates().size(), 4); Assert.assertEquals(hyp.getTransitions().size(), 10); - Assert.assertEquals(suffixActions, expectedSuffixActions); +// Assert.assertEquals(suffixActions, expectedSuffixActions); } @Test @@ -194,13 +198,14 @@ public void testLearnStackLongCE() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); - ralambda.setSolver(solver); +// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); +// ralambda.setSolver(solver); + SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, I_PUSH, I_POP); - ralambda.learn(); - RegisterAutomaton hyp = ralambda.getHypothesis(); + sllambda.learn(); + RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP0: {0}", hyp); - hyp = ralambda.getHypothesis(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP1: {0}", hyp); Word ce = Word.fromSymbols( @@ -209,10 +214,10 @@ public void testLearnStackLongCE() { new PSymbolInstance(I_POP, new DataValue(T_INT, BigDecimal.ZERO)), new PSymbolInstance(I_POP, new DataValue(T_INT, BigDecimal.ZERO))); - ralambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); + sllambda.addCounterexample(new DefaultQuery<>(ce, sul.accepts(ce))); - ralambda.learn(); - hyp = ralambda.getHypothesis(); + sllambda.learn(); + hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP2: {0}", hyp); Assert.assertTrue(hyp.accepts(ce)); @@ -249,6 +254,8 @@ public void testLearnStackRandom() { measuresStar[seed] = runner.getMeasurements(); runner.resetMeasurements(); } + + System.out.println(Arrays.toString(measuresLambda)); Assert.assertEquals(Arrays.toString(measuresLambda), "[{TQ: 60, Resets: 1199, Inputs: 0}," + diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java index 75aa90a9..7b48aa38 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java @@ -5,6 +5,7 @@ import java.util.Set; import org.testng.Assert; +import org.testng.annotations.Ignore; import org.testng.annotations.Test; import de.learnlib.query.DefaultQuery; @@ -33,6 +34,7 @@ import gov.nasa.jpf.constraints.util.ExpressionUtil; import net.automatalib.word.Word; +@Ignore public class TestDistinguishingSuffixOptimization { private static final InputSymbol A = new InputSymbol("a"); @@ -89,8 +91,9 @@ public void testDistinguishingSuffixOptimization() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - RaLambda learner = new RaLambda(mto, hypFactory, slo, consts, false, false, A, B); - learner.setSolver(solver); +// RaLambda learner = new RaLambda(mto, hypFactory, slo, consts, false, false, A, B); +// learner.setSolver(solver); + SLLambda learner = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, A, B); learner.learn(); @@ -122,7 +125,7 @@ public void testDistinguishingSuffixOptimization() { new PSymbolInstance(A))); Word b = Word.fromSymbols(new PSymbolInstance(B)); - Set suffixes = learner.getDT().getLeaf(b).getPrefix(b).getTQRs().keySet(); + Set suffixes = learner.getCT().getLeaf(b).getPrefix(b).getPath().getSDTs().keySet(); //.getTQRs().keySet(); Assert.assertFalse(suffixes.contains(suffixUnoptimized)); Assert.assertTrue(suffixes.contains(suffixOptimized)); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestOutputSuffixes.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestOutputSuffixes.java index cc2e937d..48a8e886 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestOutputSuffixes.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestOutputSuffixes.java @@ -77,8 +77,9 @@ public void testSIPOutputSuffixesPresent() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaDT radt = new RaDT(mto, hypFactory, mlo, consts, true, actions); - radt.learn(); +// RaDT radt = new RaDT(mto, hypFactory, mlo, consts, true, actions); + SLCT slct = new SLCT(mto, hypFactory, mlo, consts, true, solver, actions); + slct.learn(); String[] ces = {"IINVITE[1[int]] O100[1[int]] / true", "IINVITE[0[int]] O100[0[int]] IPRACK[0[int]] O200[0[int]] / true"}; @@ -86,8 +87,8 @@ public void testSIPOutputSuffixesPresent() { Deque> ceQueue = TestUnknownMemorable.buildSIPCEs(ces, actions); while (!ceQueue.isEmpty()) { - radt.addCounterexample(ceQueue.pop()); - radt.learn(); + slct.addCounterexample(ceQueue.pop()); + slct.learn(); } Set outputs = Sets.difference(Set.of(actions), Set.of(inputs)); @@ -96,7 +97,7 @@ public void testSIPOutputSuffixesPresent() { ceQueue = TestUnknownMemorable.buildSIPCEs(wordStr, actions); Word word = ceQueue.getFirst().getInput(); - Set suffixes = radt.getDT().getLeaf(word).getPrefix(word).getTQRs().keySet(); + Set suffixes = slct.getCT().getLeaf(word).getPrefix(word).getPath().getSDTs().keySet(); Set suffixActions = suffixes.stream() .filter(s -> s.length() == 1) .map(s -> s.getActions().firstSymbol()) diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java index d6a79093..3331ca7e 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java @@ -20,6 +20,8 @@ import de.learnlib.ralib.learning.QueryStatistics; import de.learnlib.ralib.oracles.SimulatorOracle; import de.learnlib.ralib.oracles.TreeOracleFactory; +import de.learnlib.ralib.oracles.io.IOCache; +import de.learnlib.ralib.oracles.io.IOFilter; import de.learnlib.ralib.oracles.io.IOOracle; import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; @@ -57,8 +59,10 @@ public void testQueryCount() { -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); QueryStatistics queryStats = new QueryStatistics(measurements, ioOracle); - RaLambda learner = new RaLambda(mto, hypFactory, mlo, - consts, true, sul.getActionSymbols()); +// RaLambda learner = new RaLambda(mto, hypFactory, mlo, +// consts, true, sul.getActionSymbols()); + SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, + consts, true, solver, sul.getActionSymbols()); learner.setStatisticCounter(queryStats); learner.learn(); @@ -77,7 +81,7 @@ public void testQueryCount() { learner.learn(); long memQueries1 = learner.getQueryStatistics().getMemQueries(); - Assert.assertEquals(memQueries1, 2); + Assert.assertEquals(memQueries1, 22); Word ce2 = Word.fromSymbols( new PSymbolInstance(PriorityQueueSUL.OFFER, new DataValue(PriorityQueueSUL.DOUBLE_TYPE, BigDecimal.ONE)), @@ -95,7 +99,7 @@ public void testQueryCount() { learner.learn(); long memQueries2 = learner.getQueryStatistics().getMemQueries(); - Assert.assertEquals(memQueries2, 27); + Assert.assertEquals(memQueries2, 35); Word ce3 = Word.fromSymbols( new PSymbolInstance(PriorityQueueSUL.OFFER, new DataValue(PriorityQueueSUL.DOUBLE_TYPE, BigDecimal.ONE)), @@ -111,8 +115,8 @@ public void testQueryCount() { learner.addCounterexample(ceQuery); learner.learn(); - + long memQueries3 = learner.getQueryStatistics().getMemQueries(); - Assert.assertEquals(memQueries3, 36); + Assert.assertEquals(memQueries3, 48); } } diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java index fcf7c90d..ea0a083d 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java @@ -74,9 +74,10 @@ public void testLearnRepeaterSuffixOpt() { Measurements measurements = new Measurements(); QueryStatistics stats = new QueryStatistics(measurements, sul); - RaLambda learner = new RaLambda(mto, hypFactory, mlo, consts, true, sul.getActionSymbols()); +// RaLambda learner = new RaLambda(mto, hypFactory, mlo, consts, true, sul.getActionSymbols()); + SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, sul.getActionSymbols()); learner.setStatisticCounter(stats); - learner.setSolver(solver); +// learner.setSolver(solver); learner.learn(); @@ -125,8 +126,9 @@ public void testLearnPQSuffixOpt() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - RaLambda learner = new RaLambda(mto, hypFactory, mlo, consts, OFFER, POLL); - learner.setSolver(solver); +// RaLambda learner = new RaLambda(mto, hypFactory, mlo, consts, OFFER, POLL); +// learner.setSolver(solver); + SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, false, solver, OFFER, POLL); learner.setStatisticCounter(stats); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java index ba0adc81..acd558c8 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java @@ -67,8 +67,9 @@ public void testLearnSymmetryExampleCT2() { // System.out.println(sul); // System.out.println("---------------------------------"); - RaLambda learner = new RaLambda(mto, hypFactory, slo, consts, false, false, A, B); - learner.setSolver(solver); +// RaLambda learner = new RaLambda(mto, hypFactory, slo, consts, false, false, A, B); +// learner.setSolver(solver); + SLLambda learner = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, A, B); learner.learn(); // System.out.println(learner.getHypothesis().toString()); @@ -101,7 +102,7 @@ public void testLearnSymmetryExampleCT2() { // System.out.println(learner.getHypothesis().toString()); // System.out.println(learner.getDT()); - Assert.assertTrue(learner.getDTHyp().accepts(ce)); + Assert.assertTrue(learner.getHypothesis().accepts(ce)); } private RegisterAutomaton buildCT2() { @@ -202,8 +203,9 @@ public void testLearnSymmetryExampleCT1() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - RaLambda learner = new RaLambda(mto, hypFactory, slo, consts, false, false, A, B); - learner.setSolver(solver); +// RaLambda learner = new RaLambda(mto, hypFactory, slo, consts, false, false, A, B); +// learner.setSolver(solver); + SLLambda learner = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, A, B); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java index 064998e9..e0fe8b3d 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java @@ -193,10 +193,11 @@ public void testUnknownMemorable() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); - ralambda.setSolver(solver); +// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); +// ralambda.setSolver(solver); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); - ralambda.learn(); + sllambda.learn(); Word ce = Word.fromSymbols( new PSymbolInstance(IPUT, new DataValue(T_INT, BigDecimal.ZERO)), @@ -205,9 +206,9 @@ public void testUnknownMemorable() { new PSymbolInstance(OECHO, new DataValue(T_INT, BigDecimal.ONE)), new PSymbolInstance(IQUERY), new PSymbolInstance(OYES, new DataValue(T_INT, BigDecimal.ONE))); - ralambda.addCounterexample(new DefaultQuery(ce, true)); + sllambda.addCounterexample(new DefaultQuery(ce, true)); - ralambda.learn(); + sllambda.learn(); ce = Word.fromSymbols( new PSymbolInstance(IPUT, new DataValue(T_INT, BigDecimal.ZERO)), @@ -218,10 +219,10 @@ public void testUnknownMemorable() { new PSymbolInstance(OECHO, new DataValue(T_INT, BigDecimal.ZERO)), new PSymbolInstance(IQUERY), new PSymbolInstance(ONO, new DataValue(T_INT, BigDecimal.ZERO))); - boolean acc = ralambda.getHypothesis().accepts(ce); + boolean acc = sllambda.getHypothesis().accepts(ce); if (!acc) { - ralambda.addCounterexample(new DefaultQuery(ce, true)); - ralambda.learn(); + sllambda.addCounterexample(new DefaultQuery(ce, true)); + sllambda.learn(); } // if learning reaches this point without assertion violations, the test is passed @@ -266,9 +267,10 @@ public void testSkippingMemorable() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); - ralambda.setSolver(solver); - ralambda.learn(); +// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); +// ralambda.setSolver(solver); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + sllambda.learn(); String[] ces = {"IPRACK[0[int]] Otimeout[] IINVITE[1[int]] Otimeout[] / true", "Inil[] Otimeout[] IINVITE[0[int]] O100[0[int]] / true", @@ -280,8 +282,8 @@ public void testSkippingMemorable() { Deque> ceQueue = buildSIPCEs(ces, actions); while (!ceQueue.isEmpty()) { - ralambda.addCounterexample(ceQueue.pop()); - ralambda.learn(); + sllambda.addCounterexample(ceQueue.pop()); + sllambda.learn(); } Assert.assertTrue(true); @@ -325,9 +327,10 @@ public void testSkippingMemorable2() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); - ralambda.setSolver(solver); - ralambda.learn(); +// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); +// ralambda.setSolver(solver); + SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + sllambda.learn(); String[] ces = {"IINVITE[0[int]] O100[0[int]] / true", "IACK[0[int]] Otimeout[] IINVITE[0[int]] Otimeout[] / true", @@ -343,8 +346,8 @@ public void testSkippingMemorable2() { Deque> ceQueue = buildSIPCEs(ces, actions); while (!ceQueue.isEmpty()) { - ralambda.addCounterexample(ceQueue.pop()); - ralambda.learn(); + sllambda.addCounterexample(ceQueue.pop()); + sllambda.learn(); } Assert.assertTrue(true); From c3fc70a970a54e949d7b80dad4bf85e5a1399805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Wed, 5 Nov 2025 16:52:35 +0100 Subject: [PATCH 04/31] bugfixing --- .../learnlib/ralib/automata/Assignment.java | 28 ++++++ .../learnlib/ralib/automata/Transition.java | 8 ++ .../java/de/learnlib/ralib/ct/CTBranch.java | 7 +- .../de/learnlib/ralib/ct/CTHypothesis.java | 90 ++++++++++++++++--- .../de/learnlib/ralib/ct/CTInnerNode.java | 12 ++- .../java/de/learnlib/ralib/ct/CTPath.java | 35 +++++--- .../de/learnlib/ralib/data/DataValue.java | 3 +- .../ralib/data/util/RemappingIterator.java | 4 + .../oracles/mto/MultiTheoryTreeOracle.java | 57 ++++++++++++ 9 files changed, 217 insertions(+), 27 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/automata/Assignment.java b/src/main/java/de/learnlib/ralib/automata/Assignment.java index 55840509..a709df38 100644 --- a/src/main/java/de/learnlib/ralib/automata/Assignment.java +++ b/src/main/java/de/learnlib/ralib/automata/Assignment.java @@ -17,6 +17,7 @@ package de.learnlib.ralib.automata; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import de.learnlib.ralib.data.Constants; @@ -41,7 +42,28 @@ public class Assignment { public Assignment(VarMapping assignment) { this.assignment = assignment; } + + public RegisterValuation valuation(RegisterValuation registers, ParameterValuation parameters, Constants consts) { + RegisterValuation val = new RegisterValuation(); + for (Map.Entry e : assignment.entrySet()) { + Register x = e.getKey(); + SymbolicDataValue sdv = e.getValue(); + DataValue d = sdv.isParameter() ? parameters.get((Parameter) sdv) : + sdv.isRegister() ? registers.get((Register) sdv) : + sdv.isConstant() ? consts.get((Constant) sdv) : + null; + if (d == null) { + throw new IllegalStateException("Illegal assignment: " + x + " := " + sdv); + } + val.put(x, d); + } + return val; + } + /* + * @deprecated method is unsafe, use {@link #valuation()} instead + */ + @Deprecated public RegisterValuation compute(RegisterValuation registers, ParameterValuation parameters, Constants consts) { RegisterValuation val = new RegisterValuation(); List rNames = assignment.keySet().stream().map(k -> k.getName()).toList(); @@ -56,6 +78,12 @@ public RegisterValuation compute(RegisterValuation registers, ParameterValuation val.put(e.getKey(), registers.get((Register) valp)); } else if (valp.isParameter()) { + DataValue dv = parameters.get((Parameter) valp); + for (Map.Entry ep : parameters.entrySet()) { + if (ep.getKey().equals(valp)) { + dv = ep.getValue(); + } + } val.put(e.getKey(), parameters.get((Parameter) valp)); } //TODO: check if we want to copy constant values into vars diff --git a/src/main/java/de/learnlib/ralib/automata/Transition.java b/src/main/java/de/learnlib/ralib/automata/Transition.java index ef7d6f72..daf98e1d 100644 --- a/src/main/java/de/learnlib/ralib/automata/Transition.java +++ b/src/main/java/de/learnlib/ralib/automata/Transition.java @@ -52,7 +52,15 @@ public Transition(ParameterizedSymbol label, Expression guard, public boolean isEnabled(RegisterValuation registers, ParameterValuation parameters, Constants consts) { return guard.evaluateSMT(SMTUtil.compose(registers, parameters, consts)); } + + public RegisterValuation valuation(RegisterValuation registers, ParameterValuation parameters, Constants consts) { + return this.getAssignment().valuation(registers, parameters, consts); + } + /* + * @deprecated method is unsafe, use {@link #valuation()} instead + */ + @Deprecated public RegisterValuation execute(RegisterValuation registers, ParameterValuation parameters, Constants consts) { return this.getAssignment().compute(registers, parameters, consts); } diff --git a/src/main/java/de/learnlib/ralib/ct/CTBranch.java b/src/main/java/de/learnlib/ralib/ct/CTBranch.java index 4d06290a..bd042363 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTBranch.java +++ b/src/main/java/de/learnlib/ralib/ct/CTBranch.java @@ -4,7 +4,6 @@ import de.learnlib.ralib.data.Bijection; import de.learnlib.ralib.data.DataValue; -import de.learnlib.ralib.data.SymbolicDataValue.Register; import de.learnlib.ralib.data.util.RemappingIterator; import de.learnlib.ralib.smt.ConstraintSolver; @@ -30,7 +29,7 @@ public Bijection matches(CTPath other, ConstraintSolver solver) { if (!reprPath.typeSizesMatch(other)) { return null; } - + Set regs = reprPath.getMemorable(); Set otherRegs = other.getMemorable(); @@ -38,6 +37,8 @@ public Bijection matches(CTPath other, ConstraintSolver solver) { for (Bijection vars : it) { if (reprPath.isEquivalent(other, vars, solver)) { +// if (reprPath.isEquivalent(other, vars, solver) && +// other.isEquivalent(getPath(), vars, solver)) { return vars; } } @@ -48,7 +49,7 @@ public Bijection matches(CTPath other, ConstraintSolver solver) { public CTPath getRepresentativePath() { return reprPath; } - + @Override public String toString() { return child.toString(); diff --git a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java index 3bb60f3f..f61f518a 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java +++ b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java @@ -1,46 +1,116 @@ package de.learnlib.ralib.ct; +import java.util.Collection; import java.util.Map; -import org.checkerframework.checker.nullness.qual.Nullable; - import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; +import org.checkerframework.checker.nullness.qual.Nullable; + import de.learnlib.ralib.automata.RALocation; +import de.learnlib.ralib.automata.RARun; +import de.learnlib.ralib.automata.Transition; +import de.learnlib.ralib.automata.output.OutputTransition; import de.learnlib.ralib.data.Constants; +import de.learnlib.ralib.data.ParameterValuation; +import de.learnlib.ralib.data.RegisterValuation; import de.learnlib.ralib.learning.Hypothesis; +import de.learnlib.ralib.words.OutputSymbol; +import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; +import net.automatalib.word.Word; public class CTHypothesis extends Hypothesis { - + private final BiMap leaves; - - public CTHypothesis(Constants consts, int leaves) { + private RALocation sink = null; + private final boolean ioMode; + + public CTHypothesis(Constants consts, int leaves, boolean ioMode) { super(consts); + this.ioMode = ioMode; this.leaves = HashBiMap.create(leaves); } - - public CTHypothesis(Constants consts, Map leaves) { + + public CTHypothesis(Constants consts, Map leaves, boolean ioMode) { super(consts); + this.ioMode = ioMode; this.leaves = HashBiMap.create(leaves.size()); this.leaves.putAll(leaves); } - + public void putLeaves(Map leaves) { this.leaves.putAll(leaves); } + public void setSink(RALocation sink) { + this.sink = sink; + } + + public RALocation getSink() { + return sink; + } + @Override public @Nullable RALocation getSuccessor(RALocation state, ParameterizedSymbol input) { return super.getSuccessor(state, input); } - + public RALocation getLocation(CTLeaf leaf) { return leaves.get(leaf); } - + public CTLeaf getLeaf(RALocation location) { return leaves.inverse().get(location); } + + @Override + public RARun getRun(Word word) { + int n = word.length(); + RALocation[] locs = new RALocation[n+1]; + RegisterValuation[] vals = new RegisterValuation[n+1]; + PSymbolInstance[] symbols = new PSymbolInstance[n]; + + locs[0] = getInitialState(); + vals[0] = new RegisterValuation(); + + for (int i = 0; i < n; i++) { + symbols[i] = word.getSymbol(i); + ParameterValuation pars = ParameterValuation.fromPSymbolInstance(symbols[i]); + + Collection candidates = locs[i].getOut(symbols[i].getBaseSymbol()); + if (candidates == null) { + return null; + } + + boolean found = false; + boolean output = candidates.isEmpty() ? false : + candidates.iterator().next() instanceof OutputTransition; + + for (Transition t : candidates) { + if (t.isEnabled(vals[i], pars, constants)) { +// vals[i+1] = t.execute(vals[i], pars, constants); + vals[i+1] = t.valuation(vals[i], pars, constants); + locs[i+1] = t.getDestination(); + found = true; + break; + } + } + + if (!found) { + if (ioMode) { + if ((symbols[i].getBaseSymbol() instanceof OutputSymbol && (output || candidates.isEmpty())) + || locs[i].equals(sink)) { + vals[i+1] = new RegisterValuation(); + locs[i+1] = getSink(); + } + } else { + return null; + } + } + } + + return new RARun(locs, vals, symbols); + } } diff --git a/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java index 863a6b72..0fd3b807 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java +++ b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java @@ -11,8 +11,8 @@ import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.oracles.TreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; -import de.learnlib.ralib.theory.SDT; import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; import net.automatalib.word.Word; public class CTInnerNode extends CTNode { @@ -65,9 +65,12 @@ protected CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, return leaf; } - protected Map, CTLeaf> refine(CTLeaf leaf, SymbolicSuffix suffix, TreeOracle oracle, ConstraintSolver solver, boolean ioMode) { + protected Map, CTLeaf> refine(CTLeaf leaf, SymbolicSuffix suffix, TreeOracle oracle, ConstraintSolver solver, boolean ioMode, ParameterizedSymbol[] inputs) { CTBranch b = getBranch(leaf); assert b != null : "Node is not the parent of leaf " + leaf; + assert !getSuffixes().contains(suffix) : "Duplicate suffix: " + suffix; + + Set shorts = leaf.getShortPrefixes(); CTInnerNode newNode = new CTInnerNode(this, suffix); CTBranch newBranch = new CTBranch(b.getPath(), newNode); @@ -85,6 +88,11 @@ protected Map, CTLeaf> refine(CTLeaf leaf, SymbolicSuffix l = sift(u, oracle, solver, ioMode); leaves.put(u, l); } + for (ShortPrefix u : shorts) { + if (!(u instanceof ShortPrefix)) { + leaves.get(u).elevatePrefix(u, oracle, inputs); + } + } return leaves; } diff --git a/src/main/java/de/learnlib/ralib/ct/CTPath.java b/src/main/java/de/learnlib/ralib/ct/CTPath.java index 512195dd..8b0f153d 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTPath.java +++ b/src/main/java/de/learnlib/ralib/ct/CTPath.java @@ -13,7 +13,9 @@ import de.learnlib.ralib.oracles.TreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.SDT; +import de.learnlib.ralib.words.InputSymbol; import de.learnlib.ralib.words.OutputSymbol; +import de.learnlib.ralib.words.ParameterizedSymbol; public class CTPath { private final Map sdts; @@ -106,17 +108,28 @@ public static CTPath computePath(TreeOracle oracle, Prefix prefix, List 0) { - // error path - if (prefix.length() > 0 && !r.isAccepting()) { - continue; - } - - // umatched suffix - if ((prefix.length() < 1 && (s.getActions().firstSymbol() instanceof OutputSymbol))) { - continue; - } - } +// if (ioMode && s.getActions().length() > 0) { +// // error path +// if (prefix.length() > 0 && !r.isAccepting()) { +// continue; +// } +// +// // umatched suffix +// ParameterizedSymbol first = s.getActions().firstSymbol(); +// if (first instanceof OutputSymbol && +// (prefix.length() < 1 || prefix.lastSymbol().getBaseSymbol() instanceof OutputSymbol)) { +// continue; +// } +// +// if (first instanceof InputSymbol && +// prefix.length() > 0 && +// prefix.lastSymbol().getBaseSymbol() instanceof InputSymbol) { +// continue; +// } +//// if ((prefix.length() < 1 && (s.getActions().firstSymbol() instanceof OutputSymbol))) { +//// continue; +//// } +// } sdt = prefix.getSDT(s); if (sdt == null) { diff --git a/src/main/java/de/learnlib/ralib/data/DataValue.java b/src/main/java/de/learnlib/ralib/data/DataValue.java index 8ec2ac93..6c69158c 100644 --- a/src/main/java/de/learnlib/ralib/data/DataValue.java +++ b/src/main/java/de/learnlib/ralib/data/DataValue.java @@ -63,7 +63,8 @@ public boolean equals(Object obj) { if (!Objects.equals(this.type, other.type)) { return false; } - return this.getValue().equals(other.getValue()); +// return this.getValue().equals(other.getValue()); + return this.getValue().compareTo(other.getValue()) == 0; } @Override diff --git a/src/main/java/de/learnlib/ralib/data/util/RemappingIterator.java b/src/main/java/de/learnlib/ralib/data/util/RemappingIterator.java index 2fb90f3d..5089715d 100644 --- a/src/main/java/de/learnlib/ralib/data/util/RemappingIterator.java +++ b/src/main/java/de/learnlib/ralib/data/util/RemappingIterator.java @@ -33,6 +33,10 @@ public boolean hasNext() { // public VarMapping next() { public Bijection next() { assert next != null : "No more permutations"; + if (replace.length == 0) { + next = null; + return new Bijection<>(); + } Mapping vars = new Mapping<>(); for (int i = 0; i < replace.length; i++) { int index = next[i]; diff --git a/src/main/java/de/learnlib/ralib/oracles/mto/MultiTheoryTreeOracle.java b/src/main/java/de/learnlib/ralib/oracles/mto/MultiTheoryTreeOracle.java index 200f1b23..dfe98391 100644 --- a/src/main/java/de/learnlib/ralib/oracles/mto/MultiTheoryTreeOracle.java +++ b/src/main/java/de/learnlib/ralib/oracles/mto/MultiTheoryTreeOracle.java @@ -18,11 +18,14 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.Deque; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Queue; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -54,6 +57,8 @@ import de.learnlib.ralib.theory.SDTLeaf; import de.learnlib.ralib.theory.Theory; import de.learnlib.ralib.words.DataWords; +import de.learnlib.ralib.words.InputSymbol; +import de.learnlib.ralib.words.OutputSymbol; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; import net.automatalib.common.util.Pair; @@ -88,6 +93,9 @@ public MultiTheoryTreeOracle(DataWordOracle oracle, Map teache @Override public SDT treeQuery(Word prefix, SymbolicSuffix suffix) { + if (!isValid(prefix)) { + return makeRejectingSDT(suffix); + } SDT sdt = treeQuery(prefix, suffix, new WordValuation(), constants, new SuffixValuation()); //System.out.println(sdt); return sdt; @@ -472,4 +480,53 @@ public Map getTeachers() { public SymbolicSuffixRestrictionBuilder getRestrictionBuilder() { return restrictionBuilder; } + + private boolean isValid(Word word) { + if (word.length() < 1) { + return true; + } + + Word actions = DataWords.actsOf(word); + if (actions.stream() + .filter(a -> a instanceof OutputSymbol) + .findAny() + .isEmpty()) { + return true; + } + + boolean inExpected = true; + for (ParameterizedSymbol action : actions) { + if (inExpected ^ (action instanceof InputSymbol)) { + return false; + } + inExpected = !inExpected; + } + + return true; + } + + private SDT makeRejectingSDT(SymbolicSuffix suffix) { + Queue types = new LinkedList<>(); + for (ParameterizedSymbol ps : suffix.getActions()) { + for (DataType type : ps.getPtypes()) { + types.offer(type); + } + } + return makeRejectingSDT(1, types); + } + + private SDT makeRejectingSDT(int param, Queue types) { + if (types.isEmpty()) { + return SDTLeaf.REJECTING; + } + + DataType type = types.poll(); + SuffixValue sv = new SuffixValue(type, param); + SDTGuard g = new SDTGuard.SDTTrueGuard(sv); + + Map child = new LinkedHashMap<>(); + child.put(g, makeRejectingSDT(param+1, types)); + + return new SDT(child); + } } From 510acdba227a41499905a5ba77f35c86c4c51846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Thu, 6 Nov 2025 13:51:31 +0100 Subject: [PATCH 05/31] remove method call introduced in java 21 --- src/main/java/de/learnlib/ralib/ct/ClassificationTree.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java index 4d4ee7cd..17cf614c 100644 --- a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java +++ b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java @@ -581,7 +581,7 @@ public Optional getSink() { if (children.isEmpty()) { return Optional.empty(); } - node = children.getFirst().getChild(); + node = children.stream().findFirst().get().getChild(); } return Optional.of((CTLeaf) node); } From 37a794b4a73454b1625e6fdfe2e8ea194a2a523b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Thu, 6 Nov 2025 14:23:10 +0100 Subject: [PATCH 06/31] fix query counting in caching oracle and update query numbers --- .../learning/ralambda/LearnLoginTest.java | 41 +++++++++--------- .../ralib/learning/ralambda/LearnPQTest.java | 4 +- .../learning/ralambda/LearnStackTest.java | 42 +++++++++---------- .../ralambda/TestSuffixOptimization.java | 8 ++-- 4 files changed, 47 insertions(+), 48 deletions(-) diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java index b16f11c0..4a65255d 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java @@ -119,28 +119,29 @@ public void testLearnLoginRandom() { measuresStar[seed] = runner.getMeasurements(); runner.resetMeasurements(); } + Assert.assertEquals(Arrays.toString(measuresLambda), - "[{TQ: 64, Resets: 2511, Inputs: 0}," + - " {TQ: 64, Resets: 2485, Inputs: 0}," + - " {TQ: 64, Resets: 1958, Inputs: 0}," + - " {TQ: 64, Resets: 1959, Inputs: 0}," + - " {TQ: 64, Resets: 1886, Inputs: 0}," + - " {TQ: 64, Resets: 2750, Inputs: 0}," + - " {TQ: 64, Resets: 2487, Inputs: 0}," + - " {TQ: 64, Resets: 1737, Inputs: 0}," + - " {TQ: 68, Resets: 1758, Inputs: 0}," + - " {TQ: 64, Resets: 1604, Inputs: 0}]"); + "[{TQ: 88, Resets: 1997, Inputs: 0}," + + " {TQ: 88, Resets: 1984, Inputs: 0}," + + " {TQ: 88, Resets: 1417, Inputs: 0}," + + " {TQ: 88, Resets: 1449, Inputs: 0}," + + " {TQ: 88, Resets: 1403, Inputs: 0}," + + " {TQ: 88, Resets: 2120, Inputs: 0}," + + " {TQ: 88, Resets: 1984, Inputs: 0}," + + " {TQ: 88, Resets: 1263, Inputs: 0}," + + " {TQ: 93, Resets: 1243, Inputs: 0}," + + " {TQ: 88, Resets: 1220, Inputs: 0}]"); Assert.assertEquals(Arrays.toString(measuresStar), - "[{TQ: 65, Resets: 2339, Inputs: 0}," + - " {TQ: 65, Resets: 2313, Inputs: 0}," + - " {TQ: 65, Resets: 2208, Inputs: 0}," + - " {TQ: 64, Resets: 2205, Inputs: 0}," + - " {TQ: 65, Resets: 2136, Inputs: 0}," + - " {TQ: 65, Resets: 2578, Inputs: 0}," + - " {TQ: 65, Resets: 2315, Inputs: 0}," + - " {TQ: 65, Resets: 2192, Inputs: 0}," + - " {TQ: 65, Resets: 3623, Inputs: 0}," + - " {TQ: 65, Resets: 2059, Inputs: 0}]"); + "[{TQ: 65, Resets: 1807, Inputs: 0}," + + " {TQ: 65, Resets: 1788, Inputs: 0}," + + " {TQ: 65, Resets: 1693, Inputs: 0}," + + " {TQ: 64, Resets: 1727, Inputs: 0}," + + " {TQ: 65, Resets: 1680, Inputs: 0}," + + " {TQ: 65, Resets: 1929, Inputs: 0}," + + " {TQ: 65, Resets: 1793, Inputs: 0}," + + " {TQ: 65, Resets: 1720, Inputs: 0}," + + " {TQ: 65, Resets: 3103, Inputs: 0}," + + " {TQ: 65, Resets: 1682, Inputs: 0}]"); } } diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java index 41aafd9e..77a979df 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java @@ -150,7 +150,7 @@ public void testLearnPQRandom() { } // hard-coded results from first seed - Assert.assertEquals(Arrays.toString(ralambdaCount), "[{TQ: 71, Resets: 1946, Inputs: 0}]"); - Assert.assertEquals(Arrays.toString(rastarCount), "[{TQ: 55, Resets: 7033, Inputs: 0}]"); + Assert.assertEquals(Arrays.toString(ralambdaCount), "[{TQ: 88, Resets: 876, Inputs: 0}]"); + Assert.assertEquals(Arrays.toString(rastarCount), "[{TQ: 55, Resets: 5721, Inputs: 0}]"); } } diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java index 90ba02d4..ba0a7c00 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java @@ -254,30 +254,28 @@ public void testLearnStackRandom() { measuresStar[seed] = runner.getMeasurements(); runner.resetMeasurements(); } - - System.out.println(Arrays.toString(measuresLambda)); Assert.assertEquals(Arrays.toString(measuresLambda), - "[{TQ: 60, Resets: 1199, Inputs: 0}," + - " {TQ: 65, Resets: 1859, Inputs: 0}," + - " {TQ: 60, Resets: 1178, Inputs: 0}," + - " {TQ: 62, Resets: 1516, Inputs: 0}," + - " {TQ: 70, Resets: 2717, Inputs: 0}," + - " {TQ: 62, Resets: 1443, Inputs: 0}," + - " {TQ: 56, Resets: 1148, Inputs: 0}," + - " {TQ: 41, Resets: 1089, Inputs: 0}," + - " {TQ: 78, Resets: 2478, Inputs: 0}," + - " {TQ: 44, Resets: 1139, Inputs: 0}]"); + "[{TQ: 93, Resets: 435, Inputs: 0}," + + " {TQ: 103, Resets: 737, Inputs: 0}," + + " {TQ: 88, Resets: 441, Inputs: 0}," + + " {TQ: 98, Resets: 574, Inputs: 0}," + + " {TQ: 113, Resets: 936, Inputs: 0}," + + " {TQ: 92, Resets: 597, Inputs: 0}," + + " {TQ: 82, Resets: 446, Inputs: 0}," + + " {TQ: 58, Resets: 418, Inputs: 0}," + + " {TQ: 133, Resets: 694, Inputs: 0}," + + " {TQ: 63, Resets: 470, Inputs: 0}]"); Assert.assertEquals(Arrays.toString(measuresStar), - "[{TQ: 51, Resets: 1589, Inputs: 0}," + - " {TQ: 50, Resets: 12577, Inputs: 0}," + - " {TQ: 63, Resets: 1317, Inputs: 0}," + - " {TQ: 50, Resets: 10669, Inputs: 0}," + - " {TQ: 39, Resets: 11088, Inputs: 0}," + - " {TQ: 62, Resets: 1310, Inputs: 0}," + - " {TQ: 60, Resets: 1298, Inputs: 0}," + - " {TQ: 49, Resets: 1207, Inputs: 0}," + - " {TQ: 53, Resets: 11461, Inputs: 0}," + - " {TQ: 49, Resets: 1301, Inputs: 0}]"); + "[{TQ: 51, Resets: 838, Inputs: 0}," + + " {TQ: 50, Resets: 10681, Inputs: 0}," + + " {TQ: 63, Resets: 599, Inputs: 0}," + + " {TQ: 50, Resets: 9021, Inputs: 0}," + + " {TQ: 39, Resets: 9971, Inputs: 0}," + + " {TQ: 62, Resets: 606, Inputs: 0}," + + " {TQ: 60, Resets: 603, Inputs: 0}," + + " {TQ: 49, Resets: 520, Inputs: 0}," + + " {TQ: 53, Resets: 9344, Inputs: 0}," + + " {TQ: 49, Resets: 620, Inputs: 0}]"); } } diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java index ea0a083d..500bdae9 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java @@ -148,9 +148,9 @@ public void testLearnPQSuffixOpt() { String str = stats.toString(); Assert.assertTrue(str.contains("Counterexamples: 1")); Assert.assertTrue(str.contains("CE max length: 4")); - Assert.assertTrue(str.contains("CE Analysis: {TQ: 33, Resets: 339, Inputs: 0}")); - Assert.assertTrue(str.contains("Processing / Refinement: {TQ: 27, Resets: 815, Inputs: 0}")); - Assert.assertTrue(str.contains("Other: {TQ: 7, Resets: 7, Inputs: 0}")); - Assert.assertTrue(str.contains("Total: {TQ: 67, Resets: 1161, Inputs: 0}")); + Assert.assertTrue(str.contains("CE Analysis: {TQ: 81, Resets: 92, Inputs: 0}")); + Assert.assertTrue(str.contains("Processing / Refinement: {TQ: 32, Resets: 510, Inputs: 0}")); + Assert.assertTrue(str.contains("Other: {TQ: 10, Resets: 5, Inputs: 0}")); + Assert.assertTrue(str.contains("Total: {TQ: 123, Resets: 607, Inputs: 0}")); } } From a70057231729543d50c525a56f9ac2a7f052b5b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Thu, 6 Nov 2025 14:34:58 +0100 Subject: [PATCH 07/31] fix to caching oracle query counting --- src/test/java/de/learnlib/ralib/CacheDataWordOracle.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/learnlib/ralib/CacheDataWordOracle.java b/src/test/java/de/learnlib/ralib/CacheDataWordOracle.java index c03ac7f8..9ee97a58 100644 --- a/src/test/java/de/learnlib/ralib/CacheDataWordOracle.java +++ b/src/test/java/de/learnlib/ralib/CacheDataWordOracle.java @@ -40,7 +40,7 @@ public void processQueries(Collection> boolean answer = traceBoolean(query.getInput()); query.answer(answer); } - countQueries(queries.size()); +// countQueries(queries.size()); } private boolean traceBoolean(Word query) { @@ -49,6 +49,7 @@ private boolean traceBoolean(Word query) { return ret; } ret = oracle.answerQuery(query); + countQueries(1); addToCache(query, ret); return ret; } From 5398c1d22b097090197b5d00db82bfd467e3d3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Fri, 7 Nov 2025 10:23:16 +0100 Subject: [PATCH 08/31] remove unused files --- src/main/java/de/learnlib/ralib/dt/DT.java | 571 ----------------- .../java/de/learnlib/ralib/dt/DTBranch.java | 61 -- src/main/java/de/learnlib/ralib/dt/DTHyp.java | 155 ----- .../de/learnlib/ralib/dt/DTInnerNode.java | 93 --- .../java/de/learnlib/ralib/dt/DTLeaf.java | 605 ------------------ .../java/de/learnlib/ralib/dt/DTNode.java | 31 - .../de/learnlib/ralib/dt/MappedPrefix.java | 112 ---- .../java/de/learnlib/ralib/dt/PathResult.java | 185 ------ .../java/de/learnlib/ralib/dt/PrefixSet.java | 88 --- .../de/learnlib/ralib/dt/ShortPrefix.java | 35 - .../ralib/learning/AutomatonBuilder.java | 16 +- .../ralib/learning/IOAutomatonBuilder.java | 19 +- .../learning/ralambda/DiscriminationTree.java | 37 -- .../learning/ralambda/LeafComponent.java | 89 --- .../ralib/learning/ralambda/RaDT.java | 176 ----- .../ralib/learning/ralambda/SLCT.java | 2 +- .../de/learnlib/ralib/dt/DTInnerNodeTest.java | 78 --- .../java/de/learnlib/ralib/dt/DTTest.java | 221 ------- .../ralib/dt/RegisterConsistencyTest.java | 158 ----- .../learning/ralambda/LearnSipIOTest.java | 15 +- 20 files changed, 24 insertions(+), 2723 deletions(-) delete mode 100644 src/main/java/de/learnlib/ralib/dt/DT.java delete mode 100644 src/main/java/de/learnlib/ralib/dt/DTBranch.java delete mode 100644 src/main/java/de/learnlib/ralib/dt/DTHyp.java delete mode 100644 src/main/java/de/learnlib/ralib/dt/DTInnerNode.java delete mode 100644 src/main/java/de/learnlib/ralib/dt/DTLeaf.java delete mode 100644 src/main/java/de/learnlib/ralib/dt/DTNode.java delete mode 100644 src/main/java/de/learnlib/ralib/dt/MappedPrefix.java delete mode 100644 src/main/java/de/learnlib/ralib/dt/PathResult.java delete mode 100644 src/main/java/de/learnlib/ralib/dt/PrefixSet.java delete mode 100644 src/main/java/de/learnlib/ralib/dt/ShortPrefix.java delete mode 100644 src/main/java/de/learnlib/ralib/learning/ralambda/DiscriminationTree.java delete mode 100644 src/main/java/de/learnlib/ralib/learning/ralambda/LeafComponent.java delete mode 100644 src/main/java/de/learnlib/ralib/learning/ralambda/RaDT.java delete mode 100644 src/test/java/de/learnlib/ralib/dt/DTInnerNodeTest.java delete mode 100644 src/test/java/de/learnlib/ralib/dt/DTTest.java delete mode 100644 src/test/java/de/learnlib/ralib/dt/RegisterConsistencyTest.java diff --git a/src/main/java/de/learnlib/ralib/dt/DT.java b/src/main/java/de/learnlib/ralib/dt/DT.java deleted file mode 100644 index b62d70f4..00000000 --- a/src/main/java/de/learnlib/ralib/dt/DT.java +++ /dev/null @@ -1,571 +0,0 @@ -package de.learnlib.ralib.dt; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Deque; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.tuple.Pair; - -import de.learnlib.ralib.data.Bijection; -import de.learnlib.ralib.data.Constants; -import de.learnlib.ralib.data.DataType; -import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; -import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.SuffixValueGenerator; -import de.learnlib.ralib.learning.LocationComponent; -import de.learnlib.ralib.learning.SymbolicSuffix; -import de.learnlib.ralib.learning.ralambda.DiscriminationTree; -import de.learnlib.ralib.learning.rastar.RaStar; -import de.learnlib.ralib.oracles.TreeOracle; -import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; -import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; -import de.learnlib.ralib.theory.SDT; -import de.learnlib.ralib.theory.SDTGuard; -import de.learnlib.ralib.theory.SDTLeaf; -import de.learnlib.ralib.words.OutputSymbol; -import de.learnlib.ralib.words.PSymbolInstance; -import de.learnlib.ralib.words.ParameterizedSymbol; -import net.automatalib.word.Word; - -/** - * Implementation of discrimination tree. - * - * @author fredrik - */ -public class DT implements DiscriminationTree { - private final DTInnerNode root; - - private final ParameterizedSymbol[] inputs; - private final TreeOracle oracle; - private final boolean ioMode; - private final Constants consts; - private DTLeaf sink = null; - private final SymbolicSuffixRestrictionBuilder restrictionBuilder; - - public DT(TreeOracle oracle, boolean ioMode, Constants consts, ParameterizedSymbol... inputs) { - this.oracle = oracle; - this.ioMode = ioMode; - this.inputs = inputs; - this.consts = consts; - this.restrictionBuilder = oracle.getRestrictionBuilder(); - - Word epsilon = Word.epsilon(); - SymbolicSuffix suffEps = new SymbolicSuffix(epsilon, epsilon); - - root = new DTInnerNode(suffEps); - } - - public DT(DTInnerNode root, TreeOracle oracle, boolean ioMode, Constants consts, ParameterizedSymbol... inputs) { - this.root = root; - this.oracle = oracle; - this.ioMode = ioMode; - this.inputs = inputs; - this.consts = consts; - this.restrictionBuilder = oracle.getRestrictionBuilder(); - } - - public DT(DT dt) { - this.inputs = dt.inputs; - this.oracle = dt.oracle; - this.ioMode = dt.ioMode; - this.consts = dt.consts; - this.restrictionBuilder = dt.restrictionBuilder; - - root = new DTInnerNode(dt.root); - } - - @Override - public DTLeaf sift(Word prefix, boolean add) { - //System.out.println("SIFT: " + prefix + ", add: " + add); - DTLeaf leaf = getLeaf(prefix); - if (leaf != null) { - return leaf; - } - MappedPrefix mp = new MappedPrefix(prefix, new Bijection<>()); - DTLeaf result = sift(mp, root, add); - return result; - } - - public void initialize() { - if (ioMode) { - DTInnerNode parent = root; - MappedPrefix epsilon = new MappedPrefix(RaStar.EMPTY_PREFIX, new Bijection<>()); - for (ParameterizedSymbol symbol : inputs) { - if (symbol instanceof OutputSymbol) { - DTInnerNode outputNode = new DTInnerNode(new SymbolicSuffix(symbol)); - PathResult r = PathResult.computePathResult(oracle, epsilon, parent.getSuffixes(), ioMode); - DTBranch branch = new DTBranch(outputNode, r); - outputNode.setParent(parent); - parent.addBranch(branch); - parent = outputNode; - } - } - sift(epsilon, root, true); - - for (DTBranch branch : root.getBranches()) { - if (!branch.getUrap().isAccepting()) - sink = (DTLeaf) branch.getChild(); - } - } else { - sift(RaStar.EMPTY_PREFIX, true); - } - } - - private SDT makeRejectingSDT(OutputSymbol symbol, SuffixValueGenerator sgen, int paramIndex) { - if (paramIndex == symbol.getArity()) { - return SDTLeaf.REJECTING; - } else { - DataType param = symbol.getPtypes()[paramIndex]; - SuffixValue s = sgen.next(param); - LinkedHashMap map = new LinkedHashMap(); - map.put(new SDTGuard.SDTTrueGuard(s), makeRejectingSDT(symbol, sgen, paramIndex + 1)); - return new SDT(map); - } - } - - private DTLeaf sift(MappedPrefix mp, DTInnerNode from, boolean add) { - DTLeaf leaf = null; - DTInnerNode inner = from; - - // traverse tree from root to leaf - do { - SymbolicSuffix suffix = inner.getSuffix(); - Pair siftRes = inner.sift(mp, oracle, ioMode); - - if (siftRes == null) { - // discovered new location - leaf = new DTLeaf(oracle); - //tqr = mp.computeTQR(suffix, oracle); - PathResult r = PathResult.computePathResult(oracle, mp, inner.getSuffixes(), ioMode); - assert !mp.getTQRs().containsKey(suffix); - mp.addTQR(suffix, r.getSDTforSuffix(suffix)); - mp.updateRemapping(Bijection.identity(mp.memorableValues())); - leaf.setAccessSequence(mp); - DTBranch branch = new DTBranch(leaf, r); - inner.addBranch(branch); - leaf.setParent(inner); - leaf.start(this, ioMode, inputs); - leaf.updateBranching(this); - return leaf; - } - SDT tqr = siftRes.getValue().getSDTforSuffix(suffix); - mp.addTQR(suffix, tqr); - mp.updateRemapping(siftRes.getValue().getRemapping()); - if (!siftRes.getKey().isLeaf()) { - inner = (DTInnerNode) siftRes.getKey(); - } else { - leaf = (DTLeaf) siftRes.getKey(); - } - } while (leaf == null); - - if (add && !leaf.getAccessSequence().equals(mp.getPrefix())) { - if (mp instanceof ShortPrefix) { - leaf.addShortPrefix((ShortPrefix) mp); - } else { - leaf.addPrefix(mp); - } - } - return leaf; - } - - @Override - public void split(Word prefix, SymbolicSuffix suffix, DTLeaf leaf) { - //System.out.println("SPLIT: " + prefix + ", " + suffix + ", " + leaf); - // add new inner node - DTBranch branch = leaf.getParentBranch(); - DTInnerNode node = new DTInnerNode(suffix); - node.setParent(leaf.getParent()); - branch.setChild(node); // point branch to the new inner node - - // add the new leaf - MappedPrefix mp = leaf.getMappedPrefix(prefix); - //SDT tqr = mp.computeTQR(suffix, oracle); - DTLeaf newLeaf = new DTLeaf(mp, oracle); - newLeaf.setParent(node); - PathResult r = PathResult.computePathResult(oracle, mp, node.getSuffixes(), ioMode); - SDT tqr = r.getSDTforSuffix(suffix); - assert !mp.getTQRs().containsKey(suffix); - mp.addTQR(suffix, tqr); - mp.updateRemapping(Bijection.identity(mp.memorableValues())); - - DTBranch newBranch = new DTBranch(newLeaf, r); - node.addBranch(newBranch); - ShortPrefix sp = (ShortPrefix) leaf.getShortPrefixes().get(prefix); - - // update old leaf - boolean removed = leaf.removeShortPrefix(prefix); - assert (removed); // must not split a prefix that isn't there - - //SDT tqr2 = leaf.getPrimePrefix().computeTQR(suffix, oracle); - PathResult r2 = PathResult.computePathResult(oracle, leaf.getPrimePrefix(), node.getSuffixes(), ioMode); - SDT tqr2 = r2.getSDTforSuffix(suffix); - leaf.getPrimePrefix().addTQR(suffix, tqr2); - leaf.getPrimePrefix().updateRemapping(Bijection.identity(leaf.getPrimePrefix().memorableValues())); - // assert !tqr.getSdt().isEquivalent(tqr2.getSdt(), new VarMapping<>()); - DTBranch b = new DTBranch(leaf, r2); - leaf.setParent(node); - node.addBranch(b); - - // resift all transitions targeting this location - resift(leaf); - - newLeaf.start(this, sp.getBranching()); - newLeaf.updateBranching(this); - - if (removed) { - leaf.updateBranching(this); - } - } - - public void addSuffix(SymbolicSuffix suffix, DTLeaf leaf) { - - DTBranch branch = leaf.getParentBranch(); - DTInnerNode node = new DTInnerNode(suffix); - node.setParent(leaf.getParent()); - branch.setChild(node); - leaf.setParent(node); - - //SDT tqr = leaf.getPrimePrefix().computeTQR(suffix, oracle); - PathResult r = PathResult.computePathResult(oracle, leaf.getPrimePrefix(), node.getSuffixes(), ioMode); - SDT tqr = r.getSDTforSuffix(suffix); - assert !leaf.getPrimePrefix().getTQRs().containsKey(suffix); - leaf.getPrimePrefix().addTQR(suffix, tqr); - leaf.getPrimePrefix().updateRemapping(Bijection.identity(leaf.getPrimePrefix().memorableValues())); - - DTBranch newBranch = new DTBranch(leaf, r); - node.addBranch(newBranch); - - Set prefixes = new LinkedHashSet(); - leaf.getMappedExtendedPrefixes(prefixes); - for (MappedPrefix prefix : prefixes) { - leaf.removePrefix(prefix.getPrefix()); - DTLeaf l = sift(prefix, node, true); - //System.out.println("SIFTED: " + prefix + " to " + l); - } - - leaf.updateBranching(this); - } - - public boolean addLocation(Word target, DTLeaf src_c, DTLeaf dest_c, DTLeaf target_c) { - - Word prefix = target.prefix(target.length() - 1); - SymbolicSuffix suff1 = new SymbolicSuffix(prefix, target.suffix(1), restrictionBuilder); - SymbolicSuffix suff2 = findLCA(dest_c, target_c).getSuffix(); - SymbolicSuffix suffix = suff1.concat(suff2); - - DTInnerNode parent = src_c.getParent(); - while (parent != null) { - if (parent.getSuffix().equals(suffix)) - return false; - parent = parent.getParent(); - } - - split(prefix, suffix, src_c); - return true; - } - - /** - * resift all prefixes of a leaf, in order to add them to the correct leaf - * - * @param leaf - */ - private void resift(DTLeaf leaf) { - // Potential optimization: - // can keep TQRs up to the parent, as they should still be the same - - Set prefixes = new LinkedHashSet(); - leaf.getMappedExtendedPrefixes(prefixes); - DTInnerNode parent = leaf.getParent(); - for (MappedPrefix prefix : prefixes) { - leaf.removePrefix(prefix.getPrefix()); - sift(prefix, parent, true); - } - } - - public boolean checkIOSuffixes() { - if (ioMode) { - for (DTBranch b : root.getBranches()) { - if (b.getUrap().getSDTforSuffix(root.getSuffix()).isAccepting()) - return checkIOSuffixes(b.getChild()); - } - throw new java.lang.RuntimeException("No accepting child of root"); - } - else - return true; - } - - private boolean checkIOSuffixes(DTNode node) { - if (node.isLeaf()) { - boolean missingSuffix = false; - DTLeaf leaf = (DTLeaf) node; - MappedPrefix accessMP = leaf.getPrimePrefix(); - if (accessMP.getPrefix().length() == 0 - || accessMP.getPrefix().lastSymbol().getBaseSymbol() instanceof OutputSymbol) { - return true; - } - Set ioSuffixes = accessMP.getTQRs() - .keySet() - .stream() - .filter(s -> s.length() == 1) - .map(s -> s.getActions().firstSymbol()) - .filter(ps -> ps instanceof OutputSymbol) - .collect(Collectors.toSet()); - for (ParameterizedSymbol ps : inputs) { - if (ps instanceof OutputSymbol - && !ioSuffixes.contains(ps)) { - SymbolicSuffix suffix = new SymbolicSuffix(ps); - addSuffix(suffix, leaf); - missingSuffix = true; - } - } - return !missingSuffix; - } - boolean ret = true; - DTInnerNode inner = (DTInnerNode) node; - for (DTBranch b : Collections.unmodifiableCollection(new LinkedHashSet(inner.getBranches()))) { - ret = ret && checkIOSuffixes(b.getChild()); - } - return ret; - } - - public boolean checkVariableConsistency(OptimizedSymbolicSuffixBuilder suffixBuilder) { - return checkConsistency(this.root, suffixBuilder); - } - - private boolean checkConsistency(DTNode node, OptimizedSymbolicSuffixBuilder suffixBuilder) { - if (node.isLeaf()) { - DTLeaf leaf = (DTLeaf) node; - return leaf.checkVariableConsistency(this, this.consts, suffixBuilder); - } - boolean ret = true; - DTInnerNode inner = (DTInnerNode) node; - for (DTBranch b : Collections.unmodifiableCollection(new LinkedHashSet(inner.getBranches()))) { - ret = ret && checkConsistency(b.getChild(), suffixBuilder); - } - return ret; - } - - public boolean checkRegisterConsistency(OptimizedSymbolicSuffixBuilder suffixBuilder) { - return checkRegisterConsistency(root, suffixBuilder); - } - - private boolean checkRegisterConsistency(DTNode node, OptimizedSymbolicSuffixBuilder suffixBuilder) { - if (node.isLeaf()) { - DTLeaf leaf = (DTLeaf) node; - return leaf.checkRegisterConsistency(this, this.consts, suffixBuilder); - } - boolean ret = true; - DTInnerNode inner = (DTInnerNode) node; - for (DTBranch b : Collections.unmodifiableCollection(new LinkedHashSet(inner.getBranches()))) { - ret = ret && checkRegisterConsistency(b.getChild(), suffixBuilder); - } - return ret; - } - - /** - * check whether sifting a word into the dt leads to a refinement of the dt, i.e - * whether the location corresponding to word is already in the branching of the - * source location of word - * - * @param word - * @return true if sifting word into dt leads to refinement - */ - public boolean isRefinement(Word word) { - Word prefix = word.prefix(word.length() - 1); - DTLeaf prefixLeaf = getLeaf(prefix); - assert prefixLeaf != null; - - return prefixLeaf.isRefinemement(this, word); - } - - /** - * get leaf containing prefix as - * - * @param as - * @return leaf containing as, or null - */ - public DTLeaf getLeaf(Word as) { - return getLeaf(as, root); - } - - DTLeaf getLeaf(Word as, DTNode node) { - if (node.isLeaf()) { - DTLeaf leaf = (DTLeaf) node; - if (leaf.getPrimePrefix().getPrefix().equals(as) || leaf.getShortPrefixes().contains(as) - || leaf.getPrefixes().contains(as)) - return leaf; - } else { - DTInnerNode in = (DTInnerNode) node; - for (DTBranch b : in.getBranches()) { - DTLeaf l = getLeaf(as, b.getChild()); - if (l != null) - return l; - } - } - return null; - } - - public ParameterizedSymbol[] getInputs() { - return inputs; - } - - boolean getIoMode() { - return ioMode; - } - - TreeOracle getOracle() { - return oracle; - } - - public Collection getLeaves() { - Collection leaves = new ArrayList(); - getLeaves(root, leaves); - return leaves; - } - - private void getLeaves(DTNode node, Collection leaves) { - if (node.isLeaf()) - leaves.add((DTLeaf) node); - else { - DTInnerNode inner = (DTInnerNode) node; - for (DTBranch b : inner.getBranches()) - getLeaves(b.getChild(), leaves); - } - } - - private void getSuffixes(DTNode node, Collection suffixes) { - if (!node.isLeaf()) { - DTInnerNode inner = (DTInnerNode) node; - suffixes.add(inner.getSuffix()); - for (DTBranch b : inner.getBranches()) - getSuffixes(b.getChild(), suffixes); - } - } - - public Collection getSuffixes() { - Collection suffixes = new LinkedHashSet<>(); - getSuffixes(root, suffixes); - return suffixes; - } - - private void getAllPrefixes(Collection> prefs, DTNode node) { - if (node.isLeaf()) { - DTLeaf leaf = (DTLeaf) node; - prefs.addAll(leaf.getAllPrefixes()); - } else { - DTInnerNode inner = (DTInnerNode) node; - for (DTBranch b : inner.getBranches()) - getAllPrefixes(prefs, b.getChild()); - } - } - - public boolean isMissingParameter() { - return isMissingParameter(root); - } - - private boolean isMissingParameter(DTNode node) { - if (node.isLeaf()) - return ((DTLeaf)node).isMissingVariable(); - else { - for (DTBranch b : ((DTInnerNode)node).getBranches()) { - if (isMissingParameter(b.getChild())) - return true; - } - } - return false; - } - - @Override - public Map, LocationComponent> getComponents() { - Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); - collectComponents(components, root); - return components; - } - - private void collectComponents(Map, LocationComponent> comp, DTNode node) { - if (node.isLeaf()) { - DTLeaf leaf = (DTLeaf) node; - comp.put(leaf.getAccessSequence(), leaf); - } else { - DTInnerNode inner = (DTInnerNode) node; - for (DTBranch b : inner.getBranches()) { - collectComponents(comp, b.getChild()); - } - } - } - - /** - * find the lowest common ancestor of two leaves - * - * @param l1 - * @param l2 - * @return the lowest common ancestor of l1 and l2 - */ - public DTInnerNode findLCA(DTLeaf l1, DTLeaf l2) { - Deque path1 = new ArrayDeque(); - Deque path2 = new ArrayDeque(); - - if (l1.getParent() == l2.getParent()) - return l1.getParent(); - - DTInnerNode parent = l1.getParent(); - while (parent != null) { - path1.add(parent); - parent = parent.getParent(); - } - parent = l2.getParent(); - while (parent != null) { - path2.add(parent); - parent = parent.getParent(); - } - - while (!path1.isEmpty()) { - DTInnerNode node = path1.poll(); - if (path2.contains(node)) - return node; - } - return null; - } - - public DTLeaf getSink() { - return sink; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("DT: {"); - buildTreeString(builder, root, "", " ", " -- "); - builder.append("}"); - return builder.toString(); - } - - private void buildTreeString(StringBuilder builder, DTNode node, String currentIndentation, String indentation, - String sep) { - if (node.isLeaf()) { - builder.append("\n").append(currentIndentation).append("Leaf: ").append(node); - } else { - DTInnerNode inner = (DTInnerNode) node; - builder.append("\n").append(currentIndentation).append("Inner: ").append(inner.getSuffix()); - if (!inner.getBranches().isEmpty()) { - Iterator iter = inner.getBranches().iterator(); - while (iter.hasNext()) { - builder.append("\n").append(currentIndentation); - DTBranch branch = iter.next(); - builder.append("Branch: ").append(branch.getUrap()); - buildTreeString(builder, branch.getChild(), indentation + currentIndentation, indentation, sep); - } - } - //else { - // builder.append("(").append(inner.getSuffix()).append(",").append("∅").append(")"); - //} - } - } -} diff --git a/src/main/java/de/learnlib/ralib/dt/DTBranch.java b/src/main/java/de/learnlib/ralib/dt/DTBranch.java deleted file mode 100644 index ce5af3d7..00000000 --- a/src/main/java/de/learnlib/ralib/dt/DTBranch.java +++ /dev/null @@ -1,61 +0,0 @@ -package de.learnlib.ralib.dt; - -import de.learnlib.ralib.data.Bijection; -import de.learnlib.ralib.data.DataValue; -import de.learnlib.ralib.data.util.RemappingIterator; - -public class DTBranch { - - private final PathResult urap; - - private DTNode child; - - public DTBranch(DTNode child, PathResult row) { - //this.sdt = sdt; - this.child = child; - this.urap = row; - child.setParentBranch(this); - } - - public DTBranch(DTBranch b) { - child = b.child.copy(); - urap = b.urap.copy(); - child.setParentBranch(this); - } - - public void setChild(DTNode child) { - this.child = child; - child.setParentBranch(this); - } - - public DTNode getChild() { - return child; - } - - /** - * null if there is no match - * - * @param r - * @return - */ - public Bijection matches(PathResult r) { - if (!urap.couldBeEquivalentTo(r)) { - return null; - } - - RemappingIterator iterator = new RemappingIterator<>( - r.memorableValues(), urap.memorableValues()); - - for (Bijection m : iterator) { - //System.out.println("m: " + m); - if (r.isEquivalentTo(urap, m)) { - return m; - } - } - return null; - } - - PathResult getUrap() { - return urap; - } -} diff --git a/src/main/java/de/learnlib/ralib/dt/DTHyp.java b/src/main/java/de/learnlib/ralib/dt/DTHyp.java deleted file mode 100644 index 733c9503..00000000 --- a/src/main/java/de/learnlib/ralib/dt/DTHyp.java +++ /dev/null @@ -1,155 +0,0 @@ -package de.learnlib.ralib.dt; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import de.learnlib.ralib.data.Constants; -import de.learnlib.ralib.data.ParameterValuation; -import de.learnlib.ralib.data.RegisterAssignment; -import de.learnlib.ralib.data.RegisterValuation; -import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.oracles.Branching; -import de.learnlib.ralib.smt.SMTUtil; -import de.learnlib.ralib.words.PSymbolInstance; -import de.learnlib.ralib.words.ParameterizedSymbol; -import gov.nasa.jpf.constraints.api.Expression; -import net.automatalib.word.Word; - -public class DTHyp extends Hypothesis { - - private final DT dt; - - public DTHyp(Constants consts, DT dt) { - super(consts); - this.dt = dt; - } - - @Override - public boolean accepts(Word word) { - Word as = transformAccessSequence(word); - DTLeaf l = dt.getLeaf(as); - assert l != null; - return l.isAccepting(); - } - - @Override - public boolean isAccessSequence(Word word) { - if (super.isAccessSequence(word)) - return true; - DTLeaf leaf = dt.getLeaf(word); - if (leaf == null) - return false; - return leaf.getAccessSequence().equals(word) || - leaf.getShortPrefixes().contains(word); - } - - @Override - public Word transformAccessSequence(Word word) { - List> tseq = getDTTransitions(word); - if (tseq == null) { - return null; - } - if (tseq.isEmpty()) { - return Word.epsilon(); - } else { - return dt.getLeaf(tseq.get(tseq.size() - 1)).getAccessSequence(); - } - } - - @Override - public Set> possibleAccessSequences(Word word) { - Set> ret = new LinkedHashSet>(); - Word as = transformAccessSequence(word); - ret.add(as); - - DTLeaf leaf = dt.getLeaf(as); - assert leaf != null; - for (MappedPrefix mp : leaf.getShortPrefixes().get()) - ret.add(mp.getPrefix()); - return ret; - } - - protected List> getDTTransitions(Word dw) { - RegisterValuation vars = RegisterValuation.copyOf(getInitialRegisters()); - DTLeaf current = dt.getLeaf(Word.epsilon()); - List> tseq = new ArrayList<>(); - for (PSymbolInstance psi : dw) { - ParameterValuation pars = ParameterValuation.fromPSymbolInstance(psi); - - Map, Expression> candidates = - current.getBranching(psi.getBaseSymbol()).getBranches(); - - if (candidates == null) { - return null; - } - - RegisterAssignment ra = current.getPrimePrefix().getAssignment(); - - boolean found = false; - for (Map.Entry, Expression> e : candidates.entrySet()) { - Expression g = e.getValue(); - g = SMTUtil.valsToRegisters(g, ra); - if (g.evaluateSMT(SMTUtil.compose(vars, pars, this.constants))) { - Word w = e.getKey(); - vars = current.getAssignment(w, dt.getLeaf(w)).compute(vars, pars, this.constants); - current = dt.getLeaf(w); - tseq.add(w); - found = true; - break; - } - } - - if (!found) { - return null; - } - } - return tseq; - } - - @Override - public Word transformTransitionSequence(Word word) { - List> tseq = getDTTransitions(word); - if (tseq == null) - return dt.getLeaf(word).getAccessSequence(); - assert tseq.size() == word.size(); - return tseq.get(tseq.size() - 1); - } - - @Override - public Word transformTransitionSequence(Word word, - Word location) { - Word suffix = word.suffix(1); - - DTLeaf leaf = dt.getLeaf(location); - assert leaf != null; - assert leaf.getAccessSequence().equals(location) || leaf.getShortPrefixes().contains(location); - - if (leaf.getAccessSequence().equals(location)) { - Word tseq = transformTransitionSequence(word); - //System.out.println("TSEQ: " + tseq); - if (tseq == null) { - ParameterizedSymbol ps = suffix.firstSymbol().getBaseSymbol(); - for (Word p : leaf.getBranching(ps).getBranches().keySet()) { - DTLeaf l = dt.getLeaf(p); - if (l != null && l == dt.getSink()) - return p; - } - } - return tseq; - } - - ParameterizedSymbol ps = suffix.firstSymbol().getBaseSymbol(); - - ShortPrefix sp = (ShortPrefix)leaf.getShortPrefixes().get(location); - Word ret = branchWithSameGuard(word, sp.getBranching(ps)); - assert ret != null; - return ret; - } - - public Word branchWithSameGuard(Word word, MappedPrefix src_id, Branching branching) { - return branching.transformPrefix(word); - } -} diff --git a/src/main/java/de/learnlib/ralib/dt/DTInnerNode.java b/src/main/java/de/learnlib/ralib/dt/DTInnerNode.java deleted file mode 100644 index 038c5b07..00000000 --- a/src/main/java/de/learnlib/ralib/dt/DTInnerNode.java +++ /dev/null @@ -1,93 +0,0 @@ -package de.learnlib.ralib.dt; - -import java.util.*; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; - -import de.learnlib.ralib.data.Bijection; -import de.learnlib.ralib.data.DataValue; -import de.learnlib.ralib.learning.SymbolicSuffix; -import de.learnlib.ralib.oracles.TreeOracle; - -public class DTInnerNode extends DTNode { - - private final SymbolicSuffix suffix; - - private final Set branches; - - public DTInnerNode(SymbolicSuffix suffix) { - super(); - this.suffix = suffix; - branches = new LinkedHashSet(); - } - - public DTInnerNode(SymbolicSuffix suffix, Set branches) { - super(); - this.suffix = suffix; - this.branches = branches; - } - - public DTInnerNode(DTInnerNode n) { - suffix = n.suffix; - branches = new LinkedHashSet(); - for (DTBranch b : n.branches) { - DTBranch nb = new DTBranch(b); - b.getChild().setParent(this); - branches.add(nb); - } - } - - protected Pair sift(MappedPrefix prefix, TreeOracle oracle, boolean ioMode) { - PathResult r = PathResult.computePathResult(oracle, prefix, getSuffixes(), ioMode); - for (DTBranch b : branches) { - Bijection remapping = b.matches(r); - if (remapping != null) { - r.setRemapping(remapping); - return new ImmutablePair(b.getChild(), r); - } - } - r.setRemapping(Bijection.identity(r.memorableValues())); - return null; - } - - public void addBranch(DTBranch b) { - branches.add(b); - } - - public Set getBranches() { - return branches; - } - - public SymbolicSuffix getSuffix() { - return suffix; - } - - List getSuffixes() { - LinkedList suffixes = new LinkedList<>(); - getSuffixes(suffixes); - return suffixes; - } - - void getSuffixes(LinkedList suffixes) { - suffixes.addFirst(suffix); - if (parent != null) { - parent.getSuffixes(suffixes); - } - } - - @Override - public boolean isLeaf() { - return false; - } - - @Override - public DTInnerNode copy() { - return new DTInnerNode(this); - } - - @Override - public String toString() { - return "(" + suffix.toString() + ")"; - } -} diff --git a/src/main/java/de/learnlib/ralib/dt/DTLeaf.java b/src/main/java/de/learnlib/ralib/dt/DTLeaf.java deleted file mode 100644 index 54892cda..00000000 --- a/src/main/java/de/learnlib/ralib/dt/DTLeaf.java +++ /dev/null @@ -1,605 +0,0 @@ -package de.learnlib.ralib.dt; - -import java.util.*; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import com.google.common.collect.Iterators; -import com.google.common.collect.Sets; - -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; - -import de.learnlib.ralib.automata.Assignment; -import de.learnlib.ralib.data.*; -import de.learnlib.ralib.learning.AutomatonBuilder; -import de.learnlib.ralib.learning.LocationComponent; -import de.learnlib.ralib.learning.PrefixContainer; -import de.learnlib.ralib.learning.SymbolicSuffix; -import de.learnlib.ralib.learning.ralambda.DiscriminationTree; -import de.learnlib.ralib.learning.rastar.RaStar; -import de.learnlib.ralib.oracles.Branching; -import de.learnlib.ralib.oracles.SDTLogicOracle; -import de.learnlib.ralib.oracles.TreeOracle; -import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; -import de.learnlib.ralib.theory.SDT; -import de.learnlib.ralib.words.DataWords; -import de.learnlib.ralib.words.InputSymbol; -import de.learnlib.ralib.words.PSymbolInstance; -import de.learnlib.ralib.words.ParameterizedSymbol; -import gov.nasa.jpf.constraints.api.Expression; -import net.automatalib.word.Word; - -public class DTLeaf extends DTNode implements LocationComponent { - - private MappedPrefix access; - private PrefixSet shortPrefixes; - private PrefixSet otherPrefixes; - - private final Map branching = new LinkedHashMap(); - private final TreeOracle oracle; - - public DTLeaf(TreeOracle oracle) { - super(); - access = null; - shortPrefixes = new PrefixSet(); - otherPrefixes = new PrefixSet(); - this.oracle = oracle; - } - - public DTLeaf(MappedPrefix as, TreeOracle oracle) { - super(); - access = as; - shortPrefixes = new PrefixSet(); - otherPrefixes = new PrefixSet(); - this.oracle = oracle; - } - - public DTLeaf(DTLeaf l) { - access = new MappedPrefix(l.access, l.access.getRemapping()); - shortPrefixes = new PrefixSet(l.shortPrefixes); - otherPrefixes = new PrefixSet(l.otherPrefixes); - branching.putAll(l.branching); - oracle = l.oracle; - } - - public void addPrefix(Word p) { - otherPrefixes.add(new MappedPrefix(p, new Bijection<>())); - } - - public void addPrefix(MappedPrefix p) { - assert p.memorableValues().size() == access.memorableValues().size(); - otherPrefixes.add(p); - } - - void setAccessSequence(MappedPrefix mp) { - access = mp; - } - - public void addShortPrefix(ShortPrefix prefix) { - if (otherPrefixes.contains(prefix.getPrefix())) - otherPrefixes.remove(prefix.getPrefix()); - assert access != null; - shortPrefixes.add(prefix); - } - - public boolean removeShortPrefix(Word p) { - return shortPrefixes.remove(p); - } - - public boolean removePrefix(Word p) { - return shortPrefixes.removeIf((e) -> e.getPrefix().equals(p)) || otherPrefixes.removeIf((e) -> e.getPrefix().equals(p)); - } - - /** - * Clears the short and other prefix sets. - * The only prefix remaining will be the leaf's access sequence. - */ - public void clear() { - shortPrefixes = new PrefixSet(); - otherPrefixes = new PrefixSet(); - } - - public PrefixSet getShortPrefixes() { - return shortPrefixes; - } - - public PrefixSet getPrefixes() { - return otherPrefixes; - } - - @Override - public boolean isLeaf() { - return true; - } - - @Override - public boolean isAccepting() { - SDT tqr = access.getTQRs().get(RaStar.EMPTY_SUFFIX); - return tqr.isAccepting(); - } - - MappedPrefix getMappedPrefix(Word p) { - if (access.getPrefix().equals(p)) - return access; - MappedPrefix ret = shortPrefixes.get(p); - if (ret != null) - return ret; - ret = otherPrefixes.get(p); - return ret; - } - - @Override - public Word getAccessSequence() { - return access.getPrefix(); - } - - @Override - public Bijection getRemapping(PrefixContainer r) { - if (r.getPrefix().equals(this.getAccessSequence())) - return Bijection.identity(this.access.memorableValues()); - MappedPrefix mp = otherPrefixes.get(r.getPrefix()); - if (mp == null) - mp = shortPrefixes.get(r.getPrefix()); - - assert mp != null; - return mp.getRemapping(); - } - - @Override - public Branching getBranching(ParameterizedSymbol action) { - return branching.get(action); - } - - public Branching getBranching(ParameterizedSymbol action, Word src) { - Branching b = null; - ShortPrefix sp = (ShortPrefix)shortPrefixes.get(src); - if (sp != null) - b = sp.getBranching(action); - if (b == null) - return getBranching(action); - return b; - } - - @Override - public MappedPrefix getPrimePrefix() { - return access; - } - - Collection> getAllPrefixes() { - Collection> prefs = new ArrayList>(); - prefs.add(this.getAccessSequence()); - Iterator it = shortPrefixes.iterator(); - while (it.hasNext()) - prefs.add(it.next().getPrefix()); - it = otherPrefixes.iterator(); - while (it.hasNext()) - prefs.add(it.next().getPrefix()); - return prefs; - } - - void getMappedExtendedPrefixes(Collection mps) { - mps.addAll(shortPrefixes.get()); - mps.addAll(otherPrefixes.get()); - } - - @Override - public DTInnerNode getParent() { - return parent; - } - - public MappedPrefix getPrefix(Word prefix) { - if (getAccessSequence().equals(prefix)) - return getPrimePrefix(); - MappedPrefix mp = shortPrefixes.get(prefix); - if (mp == null) - mp = otherPrefixes.get(prefix); - return mp; - } - - public SDT getTQR(Word prefix, SymbolicSuffix suffix) { - MappedPrefix mp = getMappedPrefix(prefix); - return mp.getTQRs().get(suffix); - } - - void addTQRs(SymbolicSuffix suffix) { - Iterator it = Iterators.concat(shortPrefixes.iterator(), otherPrefixes.iterator()); - while (it.hasNext()) { - MappedPrefix mp = it.next(); - mp.computeTQR(suffix, oracle); - } - } - - void addTQRs(SymbolicSuffix s, boolean addToAccess) { - if (addToAccess) { - access.computeTQR(s, oracle); - } - addTQRs(s); - } - - @Override - public Collection getOtherPrefixes() { - return Stream.concat(otherPrefixes.get().stream(), shortPrefixes.get().stream()).collect(Collectors.toList()); - } - - /** - * Elevate a prefix from the set of other prefixes to the set of short prefix, - * and checks whether this leads to a refinement. The branches of prefix are - * sifted into the tree, and added to their respective leaves. If a branch of - * prefix leads to another location than the same branch of the access sequence, - * returns the diverging words as a Pair, otherwise returns null. - * - * @param dt - * @param prefix - * @param hyp - * @param logicOracle - * @return Pair of diverging words, if such a pair of words exists. Otherwise - * null. - */ - public Pair, Word> elevatePrefix(DT dt, Word prefix, - DTHyp hyp, SDTLogicOracle logicOracle) { - assert !shortPrefixes.contains(prefix) : prefix + " is already a short prefix"; - MappedPrefix mp = otherPrefixes.get(prefix); - assert mp != null : "Cannot elevate prefix that is not contained in leaf " + this + " === " + prefix; - ShortPrefix sp = new ShortPrefix(mp); - addShortPrefix(sp); - - return startPrefix(dt, sp, hyp, logicOracle); - } - - private Pair, Word> startPrefix(DT dt, ShortPrefix mp, DTHyp hyp, SDTLogicOracle logicOracle) { - - Pair, Word> divergance = null; - boolean input = DTLeaf.isInput(mp.getPrefix().lastSymbol().getBaseSymbol()); - for (ParameterizedSymbol ps : dt.getInputs()) { - - SDT[] sdtsP = this.getSDTsForInitialSymbol(mp, ps); - Branching prefixBranching = oracle.getInitialBranching(mp.getPrefix(), ps, sdtsP); - mp.putBranching(ps, prefixBranching); - - SDT[] sdtsAS = this.getSDTsForInitialSymbol(this.getPrimePrefix(), ps); - Branching accessBranching = oracle.getInitialBranching(getAccessSequence(), ps, sdtsAS); - - assert prefixBranching.getBranches().size() == accessBranching.getBranches().size(); - - for (Word p : prefixBranching.getBranches().keySet()) { - if (dt.getIoMode() && ((input ^ !isInput(ps)) || hyp.getLocation(p) == null)) { - dt.getSink().addPrefix(p); - continue; - } - - Word a = null; - if (hyp == null) { - // no hypothesis yet, assume all true guards - for (Word w : accessBranching.getBranches().keySet()) { - if (w.lastSymbol().getBaseSymbol().equals(p.lastSymbol().getBaseSymbol())) { - a = w; - break; - } - } - } else { - a = branchWithSameGuard(p, prefixBranching, this.getRemapping(mp), accessBranching, logicOracle); - } - assert a != null; - DTLeaf leaf = dt.sift(p, true); - - if (!dt.getLeaf(a).equals(leaf)) { - divergance = new ImmutablePair, Word>(p, a); - } - } - } - return divergance; - } - - static public Word branchWithSameGuard(Word word, Branching wordBranching, Bijection remapping, Branching accBranching, SDTLogicOracle oracle) { - Word a = null; - Expression g = null; - for (Entry, Expression> e : wordBranching.getBranches().entrySet()) { - if (e.getKey().equals(word)) { - g = e.getValue(); - break; - } - } - assert g != null; - //System.out.println("w:" + word); - //System.out.println("g: " + g); - //System.out.println("pi: " + remapping); - for (Entry, Expression> e : accBranching.getBranches().entrySet()) { - Expression ag = e.getValue(); - //System.out.println("ag: " + ag); - boolean eq = oracle.areEquivalent(ag, remapping, g, new Mapping()); - if (eq) { - a = e.getKey(); - break; - } - } - assert a != null; - return a; - } - - public boolean isRefinemement(DT dt, Word word) { - ParameterizedSymbol ps = word.lastSymbol().getBaseSymbol(); - DTLeaf target = dt.getLeaf(word); - - Branching b = getBranching(ps); - boolean refinement = true; - for (Word w : b.getBranches().keySet()) { - if (dt.getLeaf(w) == target) - refinement = false; - } - - return refinement; - } - - void start(DT dt, boolean ioMode, ParameterizedSymbol... inputs) { - boolean input = isInputComponent(); - for (ParameterizedSymbol ps : inputs) { - - SDT[] sdts = this.getSDTsForInitialSymbol(ps); - Branching b = oracle.getInitialBranching(getAccessSequence(), ps, sdts); - branching.put(ps, b); - for (Word prefix : b.getBranches().keySet()) { - if (ioMode && (dt.getSink() != null) && (input ^ isInput(ps))) - dt.getSink().addPrefix(prefix); - else - dt.sift(prefix, true); - } - } - } - - void start(DT dt, Map branching) { - this.branching.putAll(branching); - } - - boolean updateBranching(DT dt) { - boolean ret = true; - for (ParameterizedSymbol p : branching.keySet()) { - boolean ub = updateBranching(p, dt); - ret = ret && ub; - } - return ret; - } - - private boolean updateBranching(ParameterizedSymbol ps, DiscriminationTree dt) { - Branching b = branching.get(ps); - SDT[] sdts = getSDTsForInitialSymbol(ps); - Branching newB = oracle.updateBranching(access.getPrefix(), ps, b, sdts); - boolean ret = true; - - for (Word prefix : newB.getBranches().keySet()) { - if (!b.getBranches().containsKey(prefix)) { - dt.sift(prefix, true); - ret = false; - } - } - - for (MappedPrefix sp : shortPrefixes.get()) { - ret &= updateBranching(ps, (ShortPrefix) sp, dt); - } - - branching.put(ps, newB); - return ret; - } - - private boolean updateBranching(ParameterizedSymbol ps, ShortPrefix sp, DiscriminationTree dt) { - Branching b = sp.getBranching(ps); - SDT[] sdts = getSDTsForInitialSymbol(sp, ps); - Branching newB = oracle.updateBranching(sp.getPrefix(), ps, b, sdts); - boolean ret = true; - - for (Word prefix : newB.getBranches().keySet()) { - if (!b.getBranches().containsKey(prefix)) { - dt.sift(prefix, true); - ret = false; - } - } - sp.putBranching(ps, newB); - return ret; - } - - private SDT[] getSDTsForInitialSymbol(ParameterizedSymbol p) { - return getSDTsForInitialSymbol(this.getPrimePrefix(), p); - } - - private SDT[] getSDTsForInitialSymbol(MappedPrefix mp, ParameterizedSymbol p) { - List sdts = new ArrayList<>(); - for (Entry e : mp.getTQRs().entrySet()) { - Word acts = e.getKey().getActions(); - if (acts.length() > 0 && acts.firstSymbol().equals(p)) { - sdts.add(e.getValue()); - } - } - return sdts.toArray(new SDT[] {}); - } - - public boolean checkVariableConsistency(DT dt, Constants consts, OptimizedSymbolicSuffixBuilder suffixBuilder) { - if (!checkVariableConsistency(access, dt, consts, suffixBuilder)) { - return false; - } - - Iterator it = otherPrefixes.iterator(); - while (it.hasNext()) { - if (!checkVariableConsistency(it.next(), dt, consts, suffixBuilder)) - return false; - } - it = shortPrefixes.iterator(); - while (it.hasNext()) { - if (!checkVariableConsistency(it.next(), dt, consts, suffixBuilder)) - return false; - } - return true; - } - - private boolean checkVariableConsistency(MappedPrefix mp, DT dt, Constants consts, OptimizedSymbolicSuffixBuilder suffixBuilder) { - if (mp.getPrefix().length() < 2) - return true; - - Word prefix = mp.getPrefix().prefix(mp.getPrefix().length() - 1); - DTLeaf prefixLeaf = dt.getLeaf(prefix); - MappedPrefix prefixMapped = prefixLeaf.getMappedPrefix(prefix); - - Set memPrefix = prefixMapped.memorableValues(); - Set memMP = mp.memorableValues(); - - int max = DataWords.paramLength(DataWords.actsOf(prefix)); - List mpVals = Arrays.stream(DataWords.valsOf(mp.getPrefix())).toList(); - - for (DataValue d : memMP) { - boolean prefixMissingParam = !memPrefix.contains(d) || prefixMapped.missingParameter.contains(d); - if (prefixMissingParam && mpVals.indexOf(d) < max) { - List prefixSuffixes = prefixMapped.getAllSuffixesForMemorable(d); - List suffixes = mp.getAllSuffixesForMemorable(d); - assert !suffixes.isEmpty(); - for (SymbolicSuffix suffix : suffixes) { - SDT sdt = mp.getTQRs().get(suffix); - // suffixBuilder == null ==> suffix.isOptimizedGeneric() - assert suffixBuilder != null || suffix.isOptimizationGeneric() : "Optimized with restriction builder, but no restriction builder provided"; - SymbolicSuffix newSuffix = suffixBuilder != null ? - suffixBuilder.extendSuffix(mp.getPrefix(), sdt, suffix, d) : - new SymbolicSuffix(mp.getPrefix(), suffix, consts); - if (prefixSuffixes.contains(newSuffix)) - continue; - SDT tqr = oracle.treeQuery(prefix, newSuffix); - - if (tqr.getDataValues().contains(d)) { - dt.addSuffix(newSuffix, prefixLeaf); - mp.missingParameter.remove(d); - return false; - } - } - if (!prefixMapped.missingParameter.contains(d)) { - mp.missingParameter.add(d); - } - } else { - mp.missingParameter.remove(d); - } - } - - return true; - } - - public boolean checkRegisterConsistency(DT dt, Constants consts, OptimizedSymbolicSuffixBuilder suffixBuilder) { - if (access.memorableValues().isEmpty()) - return true; - - if (!checkRegisterConsistency(access, dt, consts, suffixBuilder)) - return false; - - Iterator it = otherPrefixes.iterator(); - while (it.hasNext()) { - if (!checkRegisterConsistency(it.next(), dt, consts, suffixBuilder)) - return false; - } - it = shortPrefixes.iterator(); - while (it.hasNext()) { - if (!checkRegisterConsistency(it.next(), dt, consts, suffixBuilder)) - return false; - } - return true; - } - - public boolean checkRegisterConsistency(MappedPrefix mp, DT dt, Constants consts, OptimizedSymbolicSuffixBuilder suffixBuilder) { - if (mp.getPrefix().length() < 2) - return true; - - Set memMP = Set.of(mp.memorableValues().toArray(new DataValue[0])); - if (memMP.isEmpty()) - return true; - - Word prefix = mp.getPrefix().prefix(mp.getPrefix().length() - 1); - DTLeaf prefixLeaf = dt.getLeaf(prefix); - MappedPrefix prefixMapped = prefixLeaf.getMappedPrefix(prefix); - Set memPrefix = Set.of(prefixMapped.memorableValues().toArray(new DataValue[0])); - - Set paramsIntersect = Sets.intersection(memPrefix, memMP); - if (prefixMapped.equivalentRenamings(memPrefix).size() < 2) - return true; -// if (renamingsPrefix.size() < 2) -// return true; // there are no equivalent renamings - - if (!paramsIntersect.isEmpty() && paramsIntersect.size() < memPrefix.size()) { - // word shares some data values with prefix, but not all - for (Map.Entry e : mp.getTQRs().entrySet()) { - Set pmap = Set.of(e.getValue().getDataValues().toArray(new DataValue[0])); - if (!Sets.intersection(pmap, paramsIntersect).isEmpty()) { - SDT sdt = e.getValue(); - SymbolicSuffix newSuffix = suffixBuilder != null ? - suffixBuilder.extendSuffix(mp.getPrefix(), sdt, e.getKey()) : - new SymbolicSuffix(mp.getPrefix(), e.getKey(), consts); - if (!prefixMapped.getTQRs().containsKey(newSuffix)) { - dt.addSuffix(newSuffix, prefixLeaf); - return false; - } - } - } - } - - Set> renamingsPrefix = prefixMapped.equivalentRenamings(paramsIntersect); - if (renamingsPrefix.size() < 2) - return true; // there are no equivalent renamings - Set> renamingsMP = mp.equivalentRenamings(paramsIntersect); - Set> difference = Sets.difference(renamingsPrefix, renamingsMP); - if (!difference.isEmpty()) { - // there are symmetric parameter mappings in the prefix which are not symmetric in mp - for (Map.Entry e : mp.getTQRs().entrySet()) { - SDT sdt = e.getValue(); - for (Bijection vm : difference) { - //VarMapping renaming = new VarMapping<>(); - /*for (Map.Entry paramRenaming : vm.entrySet()) { - Register oldRegister = memPrefix.get(paramRenaming.getKey()); - Register newRegister = memPrefix.get(paramRenaming.getValue()); - renaming.put(oldRegister, newRegister); - }*/ - if (!sdt.isEquivalent(sdt, vm)) { - SymbolicSuffix newSuffix = suffixBuilder != null ? - suffixBuilder.extendSuffix(mp.getPrefix(), sdt, e.getKey()) : - new SymbolicSuffix(mp.getPrefix(), e.getKey(), consts); - dt.addSuffix(newSuffix, prefixLeaf); - return false; - } - } - } - } - return true; - } - public boolean isMissingVariable() { - Collection prefixes = new ArrayList<>(); - getMappedExtendedPrefixes(prefixes); - for (MappedPrefix mp : prefixes) { - if (!mp.missingParameter.isEmpty()) - return true; - } - return !access.missingParameter.isEmpty(); - } - - public boolean isInputComponent() { - if (this.getAccessSequence().length() == 0) - return true; - - ParameterizedSymbol ps = this.getAccessSequence().lastSymbol().getBaseSymbol(); - return !isInput(ps); - } - - public static boolean isInput(ParameterizedSymbol ps) { - return (ps instanceof InputSymbol); - } - - public Assignment getAssignment(Word dest_id, DTLeaf dest_c) { - MappedPrefix r = dest_c.getPrefix(dest_id); - RegisterAssignment srcAssign = getPrimePrefix().getAssignment(); - RegisterAssignment dstAssign = dest_c.access.getAssignment(); - Bijection remap = dest_c.getRemapping(r); - return AutomatonBuilder.computeAssignment(r.getPrefix(), srcAssign, dstAssign, remap); - } - - @Override - public DTLeaf copy() { - return new DTLeaf(this); - } - - @Override - public String toString() { - return getAllPrefixes().toString(); - } -} diff --git a/src/main/java/de/learnlib/ralib/dt/DTNode.java b/src/main/java/de/learnlib/ralib/dt/DTNode.java deleted file mode 100644 index 3bdc1311..00000000 --- a/src/main/java/de/learnlib/ralib/dt/DTNode.java +++ /dev/null @@ -1,31 +0,0 @@ -package de.learnlib.ralib.dt; - -public abstract class DTNode { - protected DTInnerNode parent; - protected DTBranch parentBranch; - - public DTNode() { - parent = null; - parentBranch = null; - } - - public void setParent(DTInnerNode parent) { - this.parent = parent; - } - - public void setParentBranch(DTBranch b) { - parentBranch = b; - } - - public DTInnerNode getParent() { - return parent; - } - - public DTBranch getParentBranch() { - return parentBranch; - } - - public abstract boolean isLeaf(); - - public abstract DTNode copy(); -} diff --git a/src/main/java/de/learnlib/ralib/dt/MappedPrefix.java b/src/main/java/de/learnlib/ralib/dt/MappedPrefix.java deleted file mode 100644 index 957b6595..00000000 --- a/src/main/java/de/learnlib/ralib/dt/MappedPrefix.java +++ /dev/null @@ -1,112 +0,0 @@ -package de.learnlib.ralib.dt; - -import java.util.*; -import java.util.Map.Entry; - -import de.learnlib.ralib.data.*; -import de.learnlib.ralib.data.util.RemappingIterator; -import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.RegisterGenerator; -import de.learnlib.ralib.learning.PrefixContainer; -import de.learnlib.ralib.learning.SymbolicSuffix; -import de.learnlib.ralib.oracles.TreeOracle; -import de.learnlib.ralib.theory.Memorables; -import de.learnlib.ralib.theory.SDT; -import de.learnlib.ralib.words.PSymbolInstance; -import net.automatalib.word.Word; - -public class MappedPrefix implements PrefixContainer { - - private final Word prefix; - private final RegisterGenerator regGen = new RegisterGenerator(); - - private Bijection remapping; - private final Map tqrs = new LinkedHashMap(); - public final Set missingParameter = new LinkedHashSet<>(); - - public MappedPrefix(Word prefix, Bijection remapping) { - this.prefix = prefix; - this.remapping = remapping; - } - - MappedPrefix(MappedPrefix mp, Bijection remapping) { - this.prefix = mp.getPrefix(); - tqrs.putAll(mp.getTQRs()); - this.remapping = remapping; - } - - public Set> equivalentRenamings(Set params) { - assert new HashSet<>(memorableValues()).containsAll(params); - - Set> renamings = new LinkedHashSet<>(); - RemappingIterator iter = new RemappingIterator<>(params, params); - LOC: for (Bijection b : iter) { - for (SDT tqr : tqrs.values()) { - if (!tqr.isEquivalent(tqr, b)) - continue LOC; - } - renamings.add(b); - } - return renamings; - } - - /* - * Performs a tree query for the (new) suffix and stores it in its internal map. - * Returns the result. - */ - SDT computeTQR(SymbolicSuffix suffix, TreeOracle oracle) { - SDT tqr = oracle.treeQuery(prefix, suffix); - addTQR(suffix, tqr); - return tqr; - } - - void addTQR(SymbolicSuffix s, SDT tqr) { - if (tqrs.containsKey(s) || tqr == null) return; - tqrs.put(s, tqr); - } - - public Map getTQRs() { - return tqrs; - } - - @Override - public Word getPrefix() { - return this.prefix; - } - - public Bijection getRemapping() { - return remapping; - } - - public void updateRemapping(Bijection remapping) { - this.remapping = remapping; - } - - public Set memorableValues() { - return Memorables.memorableValues(tqrs.values()); - } - - @Override - public RegisterAssignment getAssignment() { - return Memorables.getAssignment(tqrs.values()); - } - - @Override - public String toString() { - return "{" + prefix.toString() + ", " + Arrays.toString(memorableValues().toArray()) + "}"; - } - - SymbolicSuffix getSuffixForMemorable(DataValue d) { - return tqrs.entrySet().stream() - .filter(e -> e.getValue().getDataValues().contains(d)) - .findFirst() - .orElseThrow(() -> new IllegalStateException("This line is not supposed to be reached.")) - .getKey(); - } - - List getAllSuffixesForMemorable(DataValue d) { - return tqrs.entrySet().stream() - .filter(e -> e.getValue().getDataValues().contains(d)) - .map(Entry::getKey) - .toList(); - } -} diff --git a/src/main/java/de/learnlib/ralib/dt/PathResult.java b/src/main/java/de/learnlib/ralib/dt/PathResult.java deleted file mode 100644 index 0d6905b3..00000000 --- a/src/main/java/de/learnlib/ralib/dt/PathResult.java +++ /dev/null @@ -1,185 +0,0 @@ -package de.learnlib.ralib.dt; - - -import java.util.*; -import java.util.stream.Collectors; - -import de.learnlib.ralib.data.*; -import de.learnlib.ralib.data.util.SymbolicDataValueGenerator; -import de.learnlib.ralib.learning.SymbolicSuffix; -import de.learnlib.ralib.learning.rastar.RaStar; -import de.learnlib.ralib.oracles.TreeOracle; -import de.learnlib.ralib.theory.Memorables; -import de.learnlib.ralib.theory.SDT; -import de.learnlib.ralib.words.InputSymbol; -import de.learnlib.ralib.words.OutputSymbol; - -/** - * this is a copy of the functionality of row - * with additions / modifications for use in the DT - * - * @author falk - */ -public class PathResult { - - private final Map results; - - private Bijection remapping; - - private final SymbolicDataValueGenerator.RegisterGenerator regGen = new SymbolicDataValueGenerator.RegisterGenerator(); - - private final boolean ioMode; - - private PathResult(boolean ioMode) { - this.results = new LinkedHashMap<>(); - this.ioMode = ioMode; - } - - private void addResult(SymbolicSuffix s, SDT tqr) { - this.results.put(s, tqr); - } - - public boolean isEquivalentTo(PathResult other, Bijection renaming) { - return isEquivalentTo(other, SDTRelabeling.fromBijection(renaming)); - } - - public boolean isEquivalentTo(PathResult other, SDTRelabeling renaming) { - if (!couldBeEquivalentTo(other)) { - return false; - } - - if (!Memorables.relabel(this.memorableValues(), renaming).equals(other.memorableValues())) { - return false; - } - - for (Map.Entry e : this.results.entrySet()) { - SDT c1 = e.getValue(); - SDT c2 = other.results.get(e.getKey()); - - if (ioMode) { - if (c1 == null && c2 == null) { - continue; - } - - if (c1 == null || c2 == null) { - return false; - } - } - - if (!isEquivalentTo(c1, c2, renaming)) { - return false; - } - } - return true; - } - - boolean isEquivalentTo(SDT c1, SDT c2, SDTRelabeling renaming) { - if (!couldBeEquivalentTo(c1, c2)) return false; - return Memorables.relabel(c1.getDataValues(), renaming).equals(c2.getDataValues()) && c2.isEquivalent(c1, renaming); - } - - boolean couldBeEquivalentTo(PathResult other) { - if (!Memorables.typedSize(this.memorableValues()).equals(Memorables.typedSize(other.memorableValues()))) { - return false; - } - - for (Map.Entry e : this.results.entrySet()) { - SDT c1 = e.getValue(); - SDT c2 = other.results.get(e.getKey()); - - if (ioMode) { - if (c1 == null && c2 == null) { - continue; - } - - if (c1 == null || c2 == null) { - return false; - } - } - - if (!couldBeEquivalentTo(c1, c2)) { - return false; - } - } - return true; - } - - public Set memorableValues() { - return results.values().stream() - .flatMap(sdt -> sdt.getDataValues().stream()) - .collect(Collectors.toSet()); - } - - - private boolean couldBeEquivalentTo(SDT c1, SDT c2) { - return Memorables.typedSize(c1.getDataValues()).equals(Memorables.typedSize(c2.getDataValues())); - } - - /** - * computes a new row object from a prefix and a set of symbolic suffixes. - * - * @param oracle - * @param prefix - * @param suffixes - * @return - */ - public static PathResult computePathResult(TreeOracle oracle, - MappedPrefix prefix, List suffixes, boolean ioMode) { - - PathResult r = new PathResult(ioMode); - for (SymbolicSuffix s : suffixes) { - //todo: potential for optimization - if (ioMode && !s.getActions().isEmpty()) { - // error row - if (!prefix.getPrefix().isEmpty() && !r.isAccepting()) { - //log.log(Level.INFO, "Not adding suffix " + s + " to error row " + r.getPrefix()); - continue; - } - // unmatching suffix - if ((prefix.getPrefix().isEmpty() && (s.getActions().firstSymbol() instanceof OutputSymbol)) - || (!prefix.getPrefix().isEmpty() && prefix.getPrefix().lastSymbol().getBaseSymbol() instanceof InputSymbol == s.getActions().firstSymbol() instanceof InputSymbol)) { - //log.log(Level.INFO, "Not adding suffix " + s + " to unmatching row " + r.getPrefix()); - continue; - } - } - SDT tqr = prefix.getTQRs().get(s); - if (tqr == null) { - tqr = oracle.treeQuery(prefix.getPrefix(), s); - } - //System.out.println("TQ: " + prefix + " : " + s + " : " + tqr); - r.addResult(s, tqr); - } - return r; - } - - public boolean isAccepting() { - SDT c = this.results.get(RaStar.EMPTY_SUFFIX); - return c.isAccepting(); - } - - public Bijection getRemapping() { - return remapping; - } - - public void setRemapping(Bijection remapping) { - this.remapping = remapping; - } - - public SDT getSDTforSuffix(SymbolicSuffix suffix) { - return results.get(suffix); - } - - public PathResult copy() { - PathResult r = new PathResult(ioMode); - r.results.putAll(this.results); - return r; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - this.results.forEach((key, value) -> sb.append("[").append(key).append("->") - .append(value.toString().replaceAll("\\s+", " ")).append("] ")); - return sb.toString(); - } -} diff --git a/src/main/java/de/learnlib/ralib/dt/PrefixSet.java b/src/main/java/de/learnlib/ralib/dt/PrefixSet.java deleted file mode 100644 index 2bc0f682..00000000 --- a/src/main/java/de/learnlib/ralib/dt/PrefixSet.java +++ /dev/null @@ -1,88 +0,0 @@ -package de.learnlib.ralib.dt; - -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.function.Predicate; - -import de.learnlib.ralib.data.Bijection; -import de.learnlib.ralib.data.DataValue; -import de.learnlib.ralib.words.PSymbolInstance; -import net.automatalib.word.Word; - -public class PrefixSet { - private final Set prefixes; - - public PrefixSet() { - prefixes = new LinkedHashSet(); - } - - public PrefixSet(PrefixSet ps) { - prefixes = new LinkedHashSet(ps.get()); - } - - public void add(MappedPrefix p) { - prefixes.add(p); - } - - public void add(Word p, Bijection pmap) { - prefixes.add(new MappedPrefix(p, pmap)); - } - - public boolean remove(MappedPrefix p) { - return prefixes.remove(p); - } - - public boolean removeIf(Predicate filter) { - return prefixes.removeIf(filter); - } - - public boolean remove(Word p) { - return prefixes.removeIf(mp -> mp.getPrefix().equals(p)); - } - - public Set get() { - return prefixes; - } - - public MappedPrefix get(Word p) { - for (MappedPrefix mp : prefixes) { - if (mp.getPrefix().equals(p)) - return mp; - } - return null; - } - - public Iterator iterator() { - return prefixes.iterator(); - } - - public boolean contains(MappedPrefix p) { - return prefixes.contains(p); - } - - public boolean contains(Word word) { - return prefixes.stream().anyMatch(mp -> mp.getPrefix().equals(word)); - } - - public Collection> getWords() { - Collection> words = new LinkedHashSet>(); - for (MappedPrefix p : prefixes) - words.add(p.getPrefix()); - return words; - } - - public int length() { - return prefixes.size(); - } - - public boolean isEmpty() { - return prefixes.isEmpty(); - } - - @Override - public String toString() { - return prefixes.toString(); - } -} diff --git a/src/main/java/de/learnlib/ralib/dt/ShortPrefix.java b/src/main/java/de/learnlib/ralib/dt/ShortPrefix.java deleted file mode 100644 index b1f8b72d..00000000 --- a/src/main/java/de/learnlib/ralib/dt/ShortPrefix.java +++ /dev/null @@ -1,35 +0,0 @@ -package de.learnlib.ralib.dt; - -import java.util.LinkedHashMap; -import java.util.Map; - -import de.learnlib.ralib.data.Bijection; -import de.learnlib.ralib.oracles.Branching; -import de.learnlib.ralib.words.PSymbolInstance; -import de.learnlib.ralib.words.ParameterizedSymbol; -import net.automatalib.word.Word; - -public class ShortPrefix extends MappedPrefix { - - private final Map branching = new LinkedHashMap(); - - public ShortPrefix(Word prefix) { - super(prefix, new Bijection<>()); - } - - public ShortPrefix(MappedPrefix mp) { - super(mp, mp.getRemapping()); - } - - public Map getBranching() { - return branching; - } - - public Branching getBranching(ParameterizedSymbol ps) { - return branching.get(ps); - } - - void putBranching(ParameterizedSymbol ps, Branching b) { - branching.put(ps, b); - } -} diff --git a/src/main/java/de/learnlib/ralib/learning/AutomatonBuilder.java b/src/main/java/de/learnlib/ralib/learning/AutomatonBuilder.java index e6404e33..6d6b79c4 100644 --- a/src/main/java/de/learnlib/ralib/learning/AutomatonBuilder.java +++ b/src/main/java/de/learnlib/ralib/learning/AutomatonBuilder.java @@ -30,8 +30,6 @@ import de.learnlib.ralib.data.*; import de.learnlib.ralib.data.SymbolicDataValue.Parameter; import de.learnlib.ralib.data.SymbolicDataValue.Register; -import de.learnlib.ralib.dt.DT; -import de.learnlib.ralib.dt.DTHyp; import de.learnlib.ralib.learning.rastar.RaStar; import de.learnlib.ralib.oracles.Branching; import de.learnlib.ralib.smt.ReplacingValuesVisitor; @@ -65,11 +63,11 @@ public AutomatonBuilder(Map, LocationComponent> components this.automaton = new Hypothesis(consts); } - public AutomatonBuilder(Map, LocationComponent> components, Constants consts, DT dt) { - this.consts = consts; - this.components = components; - this.automaton = new DTHyp(consts, dt); - } +// public AutomatonBuilder(Map, LocationComponent> components, Constants consts, DT dt) { +// this.consts = consts; +// this.components = components; +// this.automaton = new DTHyp(consts, dt); +// } public Hypothesis toRegisterAutomaton() { LOGGER.debug(Category.EVENT, "computing hypothesis"); @@ -152,8 +150,8 @@ private void computeTransition(LocationComponent dest_c, PrefixContainer r) { // TODO: better solution // guard is null because r is transition from a short prefix - if (automaton instanceof DTHyp && guard == null) - return; +// if (automaton instanceof DTHyp && guard == null) +// return; assert true; assert guard != null; diff --git a/src/main/java/de/learnlib/ralib/learning/IOAutomatonBuilder.java b/src/main/java/de/learnlib/ralib/learning/IOAutomatonBuilder.java index ab8cfd65..e102a21a 100644 --- a/src/main/java/de/learnlib/ralib/learning/IOAutomatonBuilder.java +++ b/src/main/java/de/learnlib/ralib/learning/IOAutomatonBuilder.java @@ -35,7 +35,6 @@ import de.learnlib.ralib.data.SymbolicDataValue.Parameter; import de.learnlib.ralib.data.VarMapping; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; -import de.learnlib.ralib.dt.DT; import de.learnlib.ralib.words.OutputSymbol; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; @@ -64,15 +63,15 @@ public IOAutomatonBuilder(Map, LocationComponent> componen } } - public IOAutomatonBuilder(Map, LocationComponent> components, - Constants consts, DT dt) { - super(components, consts, dt); - - this.reverseConsts = new LinkedHashMap<>(); - for (Entry c : consts) { - reverseConsts.put(c.getValue().getValue(), c.getKey()); - } - } +// public IOAutomatonBuilder(Map, LocationComponent> components, +// Constants consts, DT dt) { +// super(components, consts, dt); +// +// this.reverseConsts = new LinkedHashMap<>(); +// for (Entry c : consts) { +// reverseConsts.put(c.getValue().getValue(), c.getKey()); +// } +// } @Override protected Transition createTransition(ParameterizedSymbol action, diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/DiscriminationTree.java b/src/main/java/de/learnlib/ralib/learning/ralambda/DiscriminationTree.java deleted file mode 100644 index 0ebd7c36..00000000 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/DiscriminationTree.java +++ /dev/null @@ -1,37 +0,0 @@ -package de.learnlib.ralib.learning.ralambda; - -import java.util.Map; - -import de.learnlib.ralib.dt.DTLeaf; -import de.learnlib.ralib.learning.LocationComponent; -import de.learnlib.ralib.learning.SymbolicSuffix; -import de.learnlib.ralib.words.PSymbolInstance; -import net.automatalib.word.Word; - -/** - * This interface describes the methods needed in a discrimination tree during learning. - * - * @author fredrik - */ -public interface DiscriminationTree { - - /** - * Sift a prefix into the DT to find the corresponding leaf. If add is true, also adds the prefix to the set of non-short prefixes of the corresponding leaf. - * - * @param prefix - * @param add - * @return the leaf corresponding to prefix - */ - DTLeaf sift(Word prefix, boolean add); - - /** - * Split a prefix from a leaf node into a new leaf. Adds a new inner node using the suffix as a discriminator. - * - * @param prefix - * @param suffix - * @param leaf - */ - void split(Word prefix, SymbolicSuffix suffix, DTLeaf leaf); - - Map, LocationComponent> getComponents(); -} diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/LeafComponent.java b/src/main/java/de/learnlib/ralib/learning/ralambda/LeafComponent.java deleted file mode 100644 index c822ab71..00000000 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/LeafComponent.java +++ /dev/null @@ -1,89 +0,0 @@ -//package de.learnlib.ralib.learning.ralambda; -// -//import java.util.Collection; -//import java.util.LinkedHashSet; -//import java.util.LinkedList; -//import java.util.Set; -// -//import de.learnlib.ralib.ct.CTLeaf; -//import de.learnlib.ralib.ct.Prefix; -//import de.learnlib.ralib.ct.ShortPrefix; -//import de.learnlib.ralib.data.Bijection; -//import de.learnlib.ralib.data.PIV; -//import de.learnlib.ralib.data.VarMapping; -//import de.learnlib.ralib.learning.LocationComponent; -//import de.learnlib.ralib.learning.PrefixContainer; -//import de.learnlib.ralib.oracles.Branching; -//import de.learnlib.ralib.words.PSymbolInstance; -//import de.learnlib.ralib.words.ParameterizedSymbol; -//import net.automatalib.word.Word; -// -//public class LeafComponent implements LocationComponent { -// -// public class PC implements PrefixContainer { -// Word prefix; -// PIV piv; -// -// public PC(Word prefix, PIV piv) { -// this.prefix = prefix; -// this.piv = piv; -// } -// -// @Override -// public Word getPrefix() { -// return prefix; -// } -// -// @Override -// public PIV getParsInVars() { -// return piv; -// } -// } -// -// private final CTLeaf leaf; -// -// public LeafComponent(CTLeaf leaf) { -// this.leaf = leaf; -// } -// -// @Override -// public boolean isAccepting() { -// return leaf.isAccepting(); -// } -// -// @Override -// public Word getAccessSequence() { -// return leaf.getRepresentativePrefix(); -// } -// -// @Override -// public VarMapping getRemapping(PrefixContainer r) { -// Bijection remapping = leaf.getPrefix(r.getPrefix()).getRpBijection(); -// return remapping.toVarMapping(); -// } -// -// @Override -// public Branching getBranching(ParameterizedSymbol action) { -// Prefix rp = leaf.getRepresentativePrefix(); -// assert rp instanceof ShortPrefix : "Prefix is not a short prefix: " + rp; -// return ((ShortPrefix) rp).getBranching(action); -// } -// -// @Override -// public PrefixContainer getPrimePrefix() { -// Prefix rp = leaf.getRepresentativePrefix(); -// return new PC(rp, PIV.defaultPiv(rp.getRegisters())); -// } -// -// @Override -// public Collection getOtherPrefixes() { -// Set prefixes = new LinkedHashSet<>(leaf.getPrefixes()); -// prefixes.remove(leaf.getRepresentativePrefix()); -// Collection container = new LinkedList<>(); -// for (Prefix u : prefixes) { -// container.add(new PC(u, PIV.defaultPiv(u.getRegisters()))); -// } -// return container; -// } -// -//} diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/RaDT.java b/src/main/java/de/learnlib/ralib/learning/ralambda/RaDT.java deleted file mode 100644 index 7c430f0c..00000000 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/RaDT.java +++ /dev/null @@ -1,176 +0,0 @@ -package de.learnlib.ralib.learning.ralambda; - -import java.util.Deque; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import de.learnlib.logging.Category; -import de.learnlib.query.DefaultQuery; -import de.learnlib.ralib.data.Constants; -import de.learnlib.ralib.dt.DT; -import de.learnlib.ralib.dt.DTHyp; -import de.learnlib.ralib.dt.DTLeaf; -import de.learnlib.ralib.learning.AutomatonBuilder; -import de.learnlib.ralib.learning.CounterexampleAnalysis; -import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.learning.IOAutomatonBuilder; -import de.learnlib.ralib.learning.LocationComponent; -import de.learnlib.ralib.learning.QueryStatistics; -import de.learnlib.ralib.learning.RaLearningAlgorithm; -import de.learnlib.ralib.learning.RaLearningAlgorithmName; -import de.learnlib.ralib.learning.rastar.CEAnalysisResult; -import de.learnlib.ralib.oracles.SDTLogicOracle; -import de.learnlib.ralib.oracles.TreeOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; -import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; -import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; -import de.learnlib.ralib.words.PSymbolInstance; -import de.learnlib.ralib.words.ParameterizedSymbol; -import net.automatalib.word.Word; - -public class RaDT implements RaLearningAlgorithm { - - private final DT dt; - - private final Constants consts; - - private final Deque> counterexamples = new LinkedList<>(); - - private DTHyp hyp = null; - - private final TreeOracle sulOracle; - - private final SDTLogicOracle sdtLogicOracle; - - private final TreeOracleFactory hypOracleFactory; - - private final OptimizedSymbolicSuffixBuilder suffixBuilder; - private final SymbolicSuffixRestrictionBuilder restrictionBuilder; - - private QueryStatistics queryStats = null; - - private final boolean ioMode; - - private static final Logger LOGGER = LoggerFactory.getLogger(RaDT.class); - - public RaDT(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, - boolean ioMode, ParameterizedSymbol... inputs) { - this.sulOracle = oracle; - this.hypOracleFactory = hypOracleFactory; - this.sdtLogicOracle = sdtLogicOracle; - this.consts = consts; - this.ioMode = ioMode; - this.restrictionBuilder = oracle.getRestrictionBuilder(); - this.suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrictionBuilder); - this.dt = new DT(oracle, ioMode, consts, inputs); - this.dt.initialize(); - } - - private void buildHypothesis() { - Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); - components.putAll(dt.getComponents()); - - AutomatonBuilder ab = new AutomatonBuilder(components, consts, dt); - hyp = (DTHyp) ab.toRegisterAutomaton(); - } - - @Override - public void learn() { - if (hyp == null) { - buildHypothesis(); - } - - while (analyzeCounterExample()); - - if (queryStats != null) { - queryStats.hypothesisConstructed(); - } - } - - private boolean analyzeCounterExample() { - LOGGER.info(Category.PHASE, "Analyzing Counterexample"); - if (counterexamples.isEmpty()) { - return false; - } - - TreeOracle hypOracle = hypOracleFactory.createTreeOracle(hyp); - - Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); - components.putAll(dt.getComponents()); - CounterexampleAnalysis analysis = new CounterexampleAnalysis(sulOracle, hypOracle, hyp, sdtLogicOracle, - components, consts); - - DefaultQuery ce = counterexamples.peek(); - - // check if ce still is a counterexample ... - boolean hypce = hyp.accepts(ce.getInput()); - boolean sulce = ce.getOutput(); - if (hypce == sulce) { - LOGGER.info(Category.EVENT, "word is not a counterexample: " + ce + " - " + sulce); - counterexamples.poll(); - return false; - } - - if (queryStats != null) { - queryStats.analyzingCounterExample(); - } - - CEAnalysisResult res = analysis.analyzeCounterexample(ce.getInput()); - - if (queryStats != null) { - queryStats.processingCounterExample(); - queryStats.analyzeCE(ce.getInput()); - } - - Word accSeq = hyp.transformAccessSequence(res.getPrefix()); - DTLeaf leaf = dt.getLeaf(accSeq); - dt.addSuffix(res.getSuffix(), leaf); - while(!dt.checkIOSuffixes()); - while(!dt.checkVariableConsistency(suffixBuilder)); - buildHypothesis(); - return true; - } - - @Override - public void addCounterexample(DefaultQuery ce) { - LOGGER.info(Category.EVENT, "adding counterexample: " + ce); - counterexamples.add(ce); - } - - @Override - public Hypothesis getHypothesis() { - Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); - components.putAll(dt.getComponents()); - AutomatonBuilder ab; - if (ioMode) { - ab = new IOAutomatonBuilder(components, consts); - } else { - ab = new AutomatonBuilder(components, consts); - } - return ab.toRegisterAutomaton(); - } - - public DT getDT() { - return dt; - } - - @Override - public void setStatisticCounter(QueryStatistics queryStats) { - this.queryStats = queryStats; - } - - @Override - public QueryStatistics getQueryStatistics() { - return queryStats; - } - - @Override - public RaLearningAlgorithmName getName() { - return RaLearningAlgorithmName.RADT; - } - -} diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java index 55ca0d2a..d3f43f57 100644 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java @@ -57,7 +57,7 @@ public class SLCT implements RaLearningAlgorithm { private final ConstraintSolver solver; - private static final Logger LOGGER = LoggerFactory.getLogger(RaDT.class); + private static final Logger LOGGER = LoggerFactory.getLogger(SLCT.class); public SLCT(TreeOracle sulOracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, boolean ioMode, ConstraintSolver solver, ParameterizedSymbol ... inputs) { diff --git a/src/test/java/de/learnlib/ralib/dt/DTInnerNodeTest.java b/src/test/java/de/learnlib/ralib/dt/DTInnerNodeTest.java deleted file mode 100644 index 613d59cf..00000000 --- a/src/test/java/de/learnlib/ralib/dt/DTInnerNodeTest.java +++ /dev/null @@ -1,78 +0,0 @@ -package de.learnlib.ralib.dt; - -import static de.learnlib.ralib.example.stack.StackAutomatonExample.AUTOMATON; -import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_POP; -import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_PUSH; -import static de.learnlib.ralib.example.stack.StackAutomatonExample.T_INT; - -import java.math.BigDecimal; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.testng.Assert; -import org.testng.annotations.Test; - -import de.learnlib.ralib.automata.RegisterAutomaton; -import de.learnlib.ralib.data.Bijection; -import de.learnlib.ralib.data.Constants; -import de.learnlib.ralib.data.DataType; -import de.learnlib.ralib.data.DataValue; -import de.learnlib.ralib.learning.SymbolicSuffix; -import de.learnlib.ralib.oracles.DataWordOracle; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; -import de.learnlib.ralib.smt.ConstraintSolver; -import de.learnlib.ralib.theory.Theory; -import de.learnlib.ralib.tools.theories.IntegerEqualityTheory; -import de.learnlib.ralib.words.PSymbolInstance; -import net.automatalib.word.Word; - -public class DTInnerNodeTest { - - @Test - public void testSiftDTInnerNode() { - RegisterAutomaton sul = AUTOMATON; - DataWordOracle dwOracle = new SimulatorOracle(sul); - - final Map teachers = new LinkedHashMap<>(); - teachers.put(T_INT, new IntegerEqualityTheory(T_INT)); - - ConstraintSolver solver = new ConstraintSolver(); - - MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( - dwOracle, teachers, new Constants(), solver); - - Word p1 = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(1))), - new PSymbolInstance(I_POP, new DataValue(T_INT, new BigDecimal(1)))); - - Word p2 = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(1))), - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(2)))); - - Word epsilon = Word.epsilon(); - Word push = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(1)))); - - Word suffix = Word.fromSymbols( - new PSymbolInstance(I_POP, new DataValue(T_INT, new BigDecimal(1)))); - - SymbolicSuffix symbSuffix = new SymbolicSuffix(epsilon, suffix); - - DTInnerNode node = new DTInnerNode(symbSuffix); - DTLeaf child1 = new DTLeaf(new MappedPrefix(epsilon, new Bijection<>()), mto); - DTLeaf child2 = new DTLeaf(new MappedPrefix(push, new Bijection<>()), mto); - - PathResult r1 = PathResult.computePathResult(mto, new MappedPrefix(epsilon, new Bijection<>()), node.getSuffixes(), false); - PathResult r2 = PathResult.computePathResult(mto, new MappedPrefix(push, new Bijection<>()), node.getSuffixes(), false); - - node.addBranch(new DTBranch(child1, r1)); - node.addBranch(new DTBranch(child2, r2)); - - DTNode test1 = node.sift(new MappedPrefix(p1, new Bijection<>()), mto, false).getKey(); - DTNode test2 = node.sift(new MappedPrefix(p2, new Bijection<>()), mto, false).getKey(); - - Assert.assertEquals(test1, child1); - Assert.assertEquals(test2, child2); - } -} diff --git a/src/test/java/de/learnlib/ralib/dt/DTTest.java b/src/test/java/de/learnlib/ralib/dt/DTTest.java deleted file mode 100644 index 5e312a41..00000000 --- a/src/test/java/de/learnlib/ralib/dt/DTTest.java +++ /dev/null @@ -1,221 +0,0 @@ -package de.learnlib.ralib.dt; - -import static de.learnlib.ralib.example.stack.StackAutomatonExample.AUTOMATON; -import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_POP; -import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_PUSH; -import static de.learnlib.ralib.example.stack.StackAutomatonExample.T_INT; - -import java.math.BigDecimal; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.testng.Assert; -import org.testng.annotations.Test; - -import de.learnlib.ralib.automata.RegisterAutomaton; -import de.learnlib.ralib.data.*; -import de.learnlib.ralib.learning.SymbolicSuffix; -import de.learnlib.ralib.oracles.DataWordOracle; -import de.learnlib.ralib.oracles.SDTLogicOracle; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; -import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; -import de.learnlib.ralib.smt.ConstraintSolver; -import de.learnlib.ralib.theory.SDT; -import de.learnlib.ralib.theory.Theory; -import de.learnlib.ralib.tools.theories.IntegerEqualityTheory; -import de.learnlib.ralib.words.PSymbolInstance; -import net.automatalib.word.Word; - -public class DTTest { - - private DT buildFullTreePrimesOnly(TreeOracle oracle) { - Word prePop = Word.fromSymbols( - new PSymbolInstance(I_POP, new DataValue(T_INT, new BigDecimal(1)))); - Word prePush = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(1)))); - Word prePushPush = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(1))), - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(2)))); - Word epsilon = Word.epsilon(); - - SymbolicSuffix suffEps = new SymbolicSuffix(epsilon, epsilon); - SymbolicSuffix suffPop = new SymbolicSuffix(epsilon, prePop); - SymbolicSuffix suffPush = new SymbolicSuffix(epsilon, prePush); - - SDT tqrPop = oracle.treeQuery(prePop, suffEps); - SDT tqrEps = oracle.treeQuery(epsilon, suffPop); - SDT tqrPush = oracle.treeQuery(prePush, suffPush); - SDT tqrPushPush = oracle.treeQuery(prePushPush, suffPush); - - DTInnerNode nodeEps = new DTInnerNode(suffEps); - DTInnerNode nodePop = new DTInnerNode(suffPop); - DTInnerNode nodePush = new DTInnerNode(suffPush); - - PathResult rPop = PathResult.computePathResult(oracle, new MappedPrefix(prePop, new Bijection<>()), nodeEps.getSuffixes(), false); - PathResult rEps = PathResult.computePathResult(oracle, new MappedPrefix(epsilon, new Bijection<>()), nodePop.getSuffixes(), false); - PathResult rPush = PathResult.computePathResult(oracle, new MappedPrefix(prePush, new Bijection<>()), nodePush.getSuffixes(), false); - PathResult rPushPush = PathResult.computePathResult(oracle, new MappedPrefix(prePushPush, new Bijection<>()), nodePush.getSuffixes(), false); - PathResult rInnerPop = PathResult.computePathResult(oracle, new MappedPrefix(epsilon, new Bijection<>()), nodeEps.getSuffixes(), false); - PathResult rInnerPush = PathResult.computePathResult(oracle, new MappedPrefix(prePush, new Bijection<>()), nodePop.getSuffixes(), false); - - DTLeaf leafPop = new DTLeaf(new MappedPrefix(prePop, new Bijection<>()), oracle); - DTLeaf leafEps = new DTLeaf(new MappedPrefix(epsilon, new Bijection<>()), oracle); - DTLeaf leafPush = new DTLeaf(new MappedPrefix(prePush, new Bijection<>()), oracle); - DTLeaf leafPushPush = new DTLeaf(new MappedPrefix(prePushPush, new Bijection<>()), oracle); - leafPop.setParent(nodeEps); - leafEps.setParent(nodePop); - leafPush.setParent(nodePush); - leafPushPush.setParent(nodePush); - - DTBranch brPop = new DTBranch(leafPop, rPop); - DTBranch brEps = new DTBranch(leafEps, rEps); - DTBranch brPush = new DTBranch(leafPush, rPush); - DTBranch brPushPush = new DTBranch(leafPushPush, rPushPush); - DTBranch brInnerPush = new DTBranch(nodePush, rInnerPush); - DTBranch brInnerPop = new DTBranch(nodePop, rInnerPop); - - leafPush.getPrimePrefix().addTQR(suffPop, oracle.treeQuery(prePush, suffPop)); - leafPushPush.getPrimePrefix().addTQR(suffPop, oracle.treeQuery(prePushPush, suffPop)); - - nodeEps.addBranch(brPop); - nodeEps.addBranch(brInnerPop); - nodePop.addBranch(brEps); - nodePop.addBranch(brInnerPush); - nodePush.addBranch(brPush); - nodePush.addBranch(brPushPush); - - return new DT(nodeEps, oracle, false, new Constants(), I_PUSH, I_POP); - } - - private DT buildSimpleTree(TreeOracle oracle) { - Word prePop = Word.fromSymbols( - new PSymbolInstance(I_POP, new DataValue(T_INT, new BigDecimal(1)))); - Word epsilon = Word.epsilon(); - - SymbolicSuffix suffEps = new SymbolicSuffix(epsilon, epsilon); - SymbolicSuffix suffPop = new SymbolicSuffix(epsilon, prePop); - - SDT tqrPop = oracle.treeQuery(prePop, suffEps); - SDT tqrEps = oracle.treeQuery(epsilon, suffPop); - - DTInnerNode nodeEps = new DTInnerNode(suffEps); - DTInnerNode nodePop = new DTInnerNode(suffPop); - - PathResult rPop = PathResult.computePathResult(oracle, new MappedPrefix(prePop, new Bijection<>()), nodeEps.getSuffixes(), false); - PathResult rEps = PathResult.computePathResult(oracle, new MappedPrefix(epsilon, new Bijection<>()), nodePop.getSuffixes(), false); - PathResult rInnerPop= PathResult.computePathResult(oracle, new MappedPrefix(epsilon, new Bijection<>()), nodeEps.getSuffixes(), false); - - DTLeaf leafPop = new DTLeaf(new MappedPrefix(prePop, new Bijection<>()), oracle); - DTLeaf leafEps = new DTLeaf(new MappedPrefix(epsilon, new Bijection<>()), oracle); - leafPop.setParent(nodeEps); - leafEps.setParent(nodePop); - - DTBranch brPop = new DTBranch(leafPop, rPop); - DTBranch brEps = new DTBranch(leafEps, rEps); - DTBranch brInnerPop = new DTBranch(nodePop, rInnerPop); - - nodeEps.addBranch(brPop); - nodeEps.addBranch(brInnerPop); - nodePop.addBranch(brEps); - - return new DT(nodeEps, oracle, false, new Constants(), I_PUSH, I_POP); - } - - @Test - public void testSiftDT() { - RegisterAutomaton sul = AUTOMATON; - DataWordOracle dwOracle = new SimulatorOracle(sul); - - final Map teachers = new LinkedHashMap<>(); - teachers.put(T_INT, new IntegerEqualityTheory(T_INT)); - - ConstraintSolver solver = new ConstraintSolver(); - - MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(dwOracle, teachers, new Constants(), solver); - DT dt = buildFullTreePrimesOnly(mto); - - Word prePush1Pop1 = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(1))), - new PSymbolInstance(I_POP, new DataValue(T_INT, new BigDecimal(1)))); - - Word prePush1Pop2 = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(1))), - new PSymbolInstance(I_POP, new DataValue(T_INT, new BigDecimal(2)))); - - Word prePushPushPop = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(1))), - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(2))), - new PSymbolInstance(I_POP, new DataValue(T_INT, new BigDecimal(2)))); - - Word accessEps = Word.epsilon(); - Word accessPop = Word.fromSymbols( - new PSymbolInstance(I_POP, new DataValue(T_INT,new BigDecimal(1)))); - Word accessPush = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT,new BigDecimal(1)))); - - DTLeaf leafPush1Pop1 = dt.sift(prePush1Pop1, true); - DTLeaf leafPush1Pop2 = dt.sift(prePush1Pop2, true); - DTLeaf leafPushPushPop = dt.sift(prePushPushPop, true); - - Assert.assertEquals(accessEps, leafPush1Pop1.getAccessSequence()); - Assert.assertEquals(accessPop, leafPush1Pop2.getAccessSequence()); - Assert.assertEquals(accessPush, leafPushPushPop.getAccessSequence()); - - // test en passant discovery - dt = buildSimpleTree(mto); - int leavesBeforeDiscovery = dt.getLeaves().size(); - Word prePush = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(1)))); - Word prePushPush = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(1))), - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(2)))); - DTLeaf newLeaf = dt.sift(prePush, true); - - Assert.assertEquals(dt.getLeaves().size(), leavesBeforeDiscovery + 1); - Assert.assertTrue(newLeaf.getAllPrefixes().contains(prePushPush)); - Assert.assertTrue(dt.getLeaf(accessEps).getAllPrefixes().contains(prePush1Pop1)); - Assert.assertTrue(dt.getLeaf(accessPop).getAllPrefixes().contains(prePush1Pop2)); - } - - @Test - public void testSplitDT() { - Constants consts = new Constants(); - RegisterAutomaton sul = AUTOMATON; - DataWordOracle dwOracle = new SimulatorOracle(sul); - - final Map teachers = new LinkedHashMap<>(); - teachers.put(T_INT, new IntegerEqualityTheory(T_INT)); - - ConstraintSolver solver = new ConstraintSolver(); - - MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(dwOracle, teachers, new Constants(), solver); - SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); - - DT dt = new DT(mto, false, consts, I_PUSH, I_POP); - dt.initialize(); - - DTHyp hyp = new DTHyp(consts, dt); - - Word prePush = Word.fromSymbols( - new PSymbolInstance(I_PUSH, new DataValue(T_INT, new BigDecimal(0)))); - Word prePop = Word.fromSymbols( - new PSymbolInstance(I_POP, new DataValue(T_INT, new BigDecimal(0)))); - Word eps = Word.epsilon(); - SymbolicSuffix suffPop = new SymbolicSuffix(eps, prePop); - - DTLeaf leafEps = dt.getLeaf(eps); - leafEps.elevatePrefix(dt, prePush, hyp, slo); - - dt.split(prePush, suffPop, leafEps); - - // assert new leaf added for PUSH(0) - DTLeaf leafPush = dt.getLeaf(prePush); - Assert.assertEquals(prePush, leafPush.getAccessSequence()); - - // assert epsilon and push(0) are both children of inner node pop - Assert.assertEquals(suffPop, leafEps.getParent().getSuffix()); - Assert.assertEquals(suffPop, leafPush.getParent().getSuffix()); - } -} diff --git a/src/test/java/de/learnlib/ralib/dt/RegisterConsistencyTest.java b/src/test/java/de/learnlib/ralib/dt/RegisterConsistencyTest.java deleted file mode 100644 index 5df076f0..00000000 --- a/src/test/java/de/learnlib/ralib/dt/RegisterConsistencyTest.java +++ /dev/null @@ -1,158 +0,0 @@ -package de.learnlib.ralib.dt; - -import java.math.BigDecimal; -import java.util.List; -import java.util.Map; - -import org.testng.Assert; -import org.testng.annotations.Test; - -import de.learnlib.ralib.RaLibTestSuite; -import de.learnlib.ralib.data.*; -import de.learnlib.ralib.data.SymbolicDataValue.Parameter; -import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; -import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; -import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.RegisterGenerator; -import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.SuffixValueGenerator; -import de.learnlib.ralib.learning.SymbolicSuffix; -import de.learnlib.ralib.oracles.Branching; -import de.learnlib.ralib.oracles.TreeOracle; -import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; -import de.learnlib.ralib.theory.SDT; -import de.learnlib.ralib.theory.SDTGuard; -import de.learnlib.ralib.theory.SDTLeaf; -import de.learnlib.ralib.words.InputSymbol; -import de.learnlib.ralib.words.PSymbolInstance; -import de.learnlib.ralib.words.ParameterizedSymbol; -import net.automatalib.word.Word; - -public class RegisterConsistencyTest extends RaLibTestSuite { - - private static final DataType T_INT = new DataType("int"); - - private static final InputSymbol A = new InputSymbol("a", T_INT); - - private static class DummyDT extends DT { - - private static class DummyOracle implements TreeOracle { - - @Override - public SDT treeQuery(Word prefix, SymbolicSuffix suffix) { - return null; - } - - @Override - public Branching getInitialBranching(Word prefix, ParameterizedSymbol ps, - SDT... sdts) { - return null; - } - - @Override - public Branching updateBranching(Word prefix, ParameterizedSymbol ps, Branching current, - SDT... sdts) { - return null; - } - - @Override - public Map, Boolean> instantiate(Word prefix, SymbolicSuffix suffix, - SDT sdt) { - return null; - } - - @Override - public SymbolicSuffixRestrictionBuilder getRestrictionBuilder() { - return null; - } - - } - - private final DTLeaf prefixLeaf; - private final DTLeaf leaf; - - public SymbolicSuffix addedSuffix = null; - - public DummyDT(MappedPrefix word, MappedPrefix prefix) { - super(new DummyOracle(), false, new Constants(), (ParameterizedSymbol[])null); - leaf = new DTLeaf(word, null); - prefixLeaf = new DTLeaf(prefix, null); - } - - @Override - public DTLeaf getLeaf(Word word) { - if (word.equals(leaf.getAccessSequence())) - return leaf; - if (word.equals(prefixLeaf.getAccessSequence())) - return prefixLeaf; - return null; - } - - @Override - public void addSuffix(SymbolicSuffix suffix, DTLeaf leaf) { - addedSuffix = suffix; - } - } - - @Test - public void testSymmetry() { - Word word = Word.fromSymbols( - new PSymbolInstance(A, new DataValue(T_INT, BigDecimal.ZERO)), - new PSymbolInstance(A, new DataValue(T_INT, BigDecimal.ONE)), - new PSymbolInstance(A, new DataValue(T_INT, BigDecimal.ONE))); - Word suffixWord = Word.fromSymbols( - new PSymbolInstance(A, new DataValue(T_INT, BigDecimal.ZERO)), - new PSymbolInstance(A, new DataValue(T_INT, BigDecimal.ONE))); - Word suffixExpected = Word.fromSymbols( - new PSymbolInstance(A, new DataValue(T_INT, BigDecimal.ONE)), - new PSymbolInstance(A, new DataValue(T_INT, BigDecimal.ZERO)), - new PSymbolInstance(A, new DataValue(T_INT, BigDecimal.ONE))); - Word prefix = word.prefix(2); - SymbolicSuffix symSuffixEps = new SymbolicSuffix(Word.epsilon(), Word.epsilon()); - SymbolicSuffix symSuffixWord = new SymbolicSuffix(word, suffixWord); - SymbolicSuffix symSuffixPrefix = new SymbolicSuffix(prefix, word.suffix(1)); - SymbolicSuffix symSuffixExpected = new SymbolicSuffix(prefix, suffixExpected); - - RegisterGenerator rgen = new RegisterGenerator(); - ParameterGenerator pgen = new ParameterGenerator(); - SuffixValueGenerator svgen = new SuffixValueGenerator(); - - Parameter p1 = pgen.next(T_INT); - Parameter p2 = pgen.next(T_INT); - DataValue r1 = new DataValue(T_INT, BigDecimal.ZERO); //rgen.next(T_INT); - DataValue r2 = new DataValue(T_INT, BigDecimal.ONE); // rgen.next(T_INT); - SuffixValue s1 = svgen.next(T_INT); - SuffixValue s2 = svgen.next(T_INT); - - Constants consts = new Constants(); - - SDT sdtEps = SDTLeaf.ACCEPTING; - SDT sdtPrefix = new SDT(Map.of( - new SDTGuard.SDTOrGuard(s1, List.of(new SDTGuard.EqualityGuard(s1, r1), new SDTGuard.EqualityGuard(s1, r2))), SDTLeaf.ACCEPTING, - new SDTGuard.SDTAndGuard(s1, List.of(new SDTGuard.DisequalityGuard(s1, r1), new SDTGuard.DisequalityGuard(s1, r2))), SDTLeaf.REJECTING)); - SDT sdtWord = new SDT(Map.of( - new SDTGuard.EqualityGuard(s1, r1), new SDT(Map.of( - new SDTGuard.EqualityGuard(s2, r2), SDTLeaf.ACCEPTING, - new SDTGuard.DisequalityGuard(s2, r2), SDTLeaf.REJECTING)), - new SDTGuard.DisequalityGuard(s1, r1), new SDT(Map.of( - new SDTGuard.SDTTrueGuard(s2), SDTLeaf.REJECTING)))); - - SDT tqrEps = sdtEps; - SDT tqrPrefix = sdtPrefix; - SDT tqrWord = sdtWord; - - MappedPrefix mpWord = new MappedPrefix(word, Bijection.identity(sdtWord.getDataValues())); - MappedPrefix mpPrefix = new MappedPrefix(prefix, Bijection.identity(sdtPrefix.getDataValues())); - - mpWord.addTQR(new SymbolicSuffix(Word.epsilon(), Word.epsilon()), tqrEps); - mpWord.addTQR(symSuffixWord, tqrWord); - mpPrefix.addTQR(symSuffixEps, tqrEps); - mpPrefix.addTQR(symSuffixPrefix, tqrPrefix); - - DummyDT dt = new DummyDT(mpWord, mpPrefix); - DTLeaf leafWord = dt.getLeaf(word); - - boolean consistent = leafWord.checkRegisterConsistency(dt, consts, null); - Assert.assertFalse(consistent); - Assert.assertEquals(dt.addedSuffix.getActions(), symSuffixExpected.getActions()); - } - -} diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java index d598057b..89c9c42e 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java @@ -15,7 +15,6 @@ import de.learnlib.ralib.automata.xml.RegisterAutomatonImporter; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; -import de.learnlib.ralib.dt.DTLeaf; import de.learnlib.ralib.equivalence.IOCounterExamplePrefixFinder; import de.learnlib.ralib.equivalence.IOCounterExamplePrefixReplacer; import de.learnlib.ralib.equivalence.IOCounterexampleLoopRemover; @@ -85,13 +84,13 @@ public void testLearnSipIO() { MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - for (ParameterizedSymbol ps : actions) { - if (!DTLeaf.isInput(ps) && ps.getArity() > 0) { -// if (ps.getArity() > 0) { - mto.treeQuery(Word.epsilon(), new SymbolicSuffix(ps)); - break; - } - } +// for (ParameterizedSymbol ps : actions) { +// if (!DTLeaf.isInput(ps) && ps.getArity() > 0) { +//// if (ps.getArity() > 0) { +// mto.treeQuery(Word.epsilon(), new SymbolicSuffix(ps)); +// break; +// } +// } TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); From bf766074ff7fefc6b145aaa51dc02a2f3cf4dac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Fri, 7 Nov 2025 10:32:57 +0100 Subject: [PATCH 09/31] apply spotless --- .../learnlib/ralib/automata/Assignment.java | 2 +- .../de/learnlib/ralib/automata/RARun.java | 2 +- .../learnlib/ralib/automata/Transition.java | 2 +- .../ralib/ceanalysis/PrefixFinder.java | 26 +++----- .../learnlib/ralib/ct/CTAutomatonBuilder.java | 21 +++--- .../de/learnlib/ralib/ct/CTHypothesis.java | 6 +- .../de/learnlib/ralib/ct/CTInnerNode.java | 2 +- .../java/de/learnlib/ralib/ct/CTLeaf.java | 5 +- .../java/de/learnlib/ralib/ct/CTPath.java | 5 +- .../learnlib/ralib/ct/ClassificationTree.java | 9 +-- .../de/learnlib/ralib/ct/MemorableSet.java | 1 - .../de/learnlib/ralib/ct/ShortPrefix.java | 1 - .../ralib/data/RegisterAssignment.java | 2 +- .../learnlib/ralib/data/util/DataUtils.java | 3 +- .../ralib/learning/ralambda/SLCT.java | 2 +- .../ralib/learning/ralambda/SLLambda.java | 34 +++++----- .../oracles/mto/MultiTheoryTreeOracle.java | 19 +++--- .../ralib/ceanalysis/PrefixFinderTest.java | 65 +++++++++---------- .../learning/ralambda/LearnLoginTest.java | 2 +- .../ralambda/LearnPalindromeIOTest.java | 2 +- .../learning/ralambda/LearnSipIOTest.java | 2 - .../learning/ralambda/LearnStackTest.java | 6 -- .../learning/ralambda/TestQueryCount.java | 4 +- 23 files changed, 93 insertions(+), 130 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/automata/Assignment.java b/src/main/java/de/learnlib/ralib/automata/Assignment.java index a709df38..2e469e41 100644 --- a/src/main/java/de/learnlib/ralib/automata/Assignment.java +++ b/src/main/java/de/learnlib/ralib/automata/Assignment.java @@ -42,7 +42,7 @@ public class Assignment { public Assignment(VarMapping assignment) { this.assignment = assignment; } - + public RegisterValuation valuation(RegisterValuation registers, ParameterValuation parameters, Constants consts) { RegisterValuation val = new RegisterValuation(); for (Map.Entry e : assignment.entrySet()) { diff --git a/src/main/java/de/learnlib/ralib/automata/RARun.java b/src/main/java/de/learnlib/ralib/automata/RARun.java index d9c82cba..3dff5d07 100644 --- a/src/main/java/de/learnlib/ralib/automata/RARun.java +++ b/src/main/java/de/learnlib/ralib/automata/RARun.java @@ -29,7 +29,7 @@ public RegisterValuation getValuation(int i) { public PSymbolInstance getTransition(int i) { return transitions[i-1]; } - + public DataValue[] getDataValues(int i) { ArrayList vals = new ArrayList<>(); for (int id = 0; id < i; id++) { diff --git a/src/main/java/de/learnlib/ralib/automata/Transition.java b/src/main/java/de/learnlib/ralib/automata/Transition.java index daf98e1d..c90ebe1a 100644 --- a/src/main/java/de/learnlib/ralib/automata/Transition.java +++ b/src/main/java/de/learnlib/ralib/automata/Transition.java @@ -52,7 +52,7 @@ public Transition(ParameterizedSymbol label, Expression guard, public boolean isEnabled(RegisterValuation registers, ParameterValuation parameters, Constants consts) { return guard.evaluateSMT(SMTUtil.compose(registers, parameters, consts)); } - + public RegisterValuation valuation(RegisterValuation registers, ParameterValuation parameters, Constants consts) { return this.getAssignment().valuation(registers, parameters, consts); } diff --git a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java index ed077f08..66760fce 100644 --- a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java +++ b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java @@ -1,9 +1,7 @@ package de.learnlib.ralib.ceanalysis; import java.util.ArrayList; -import java.util.Arrays; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Optional; @@ -25,10 +23,7 @@ import de.learnlib.ralib.data.SymbolicDataValue; import de.learnlib.ralib.data.SymbolicDataValue.Parameter; import de.learnlib.ralib.data.SymbolicDataValue.Register; -import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; -import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.SuffixValueGenerator; import de.learnlib.ralib.data.util.PermutationIterator; -import de.learnlib.ralib.data.util.RemappingIterator; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.oracles.Branching; @@ -38,7 +33,6 @@ import de.learnlib.ralib.smt.ReplacingValuesVisitor; import de.learnlib.ralib.theory.SDT; import de.learnlib.ralib.theory.Theory; -import de.learnlib.ralib.words.DataWords; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; import gov.nasa.jpf.constraints.api.Expression; @@ -119,7 +113,7 @@ public Result analyzeCounterExample(Word ce) { throw new IllegalStateException("Found no counterexample in " + ce); } - + /* * Generate a mapping from the register valuation of u on the hypothesis to val */ @@ -138,7 +132,7 @@ private Mapping valuationRenaming(Word u, } return ret; } - + private Set> extendedValuationRenamings(SDT uSDT, Set uValuation, RARun run, int id) { Set> identity = new LinkedHashSet<>(); identity.add(new Mapping<>()); @@ -153,7 +147,7 @@ private Set> extendedValuationRenamings(SDT uSDT, return identity; } DataValue[] sdtValsArr = sdtVals.toArray(new DataValue[sdtVals.size()]); - + ArrayList runVals = new ArrayList<>(); for (int i = 1; i <= id-1; i++) { for (DataValue d : run.getTransition(i).getParameterValues()) { @@ -163,7 +157,7 @@ private Set> extendedValuationRenamings(SDT uSDT, for (DataValue d : run.getValuation(id-1).values()) { runVals = removeFirst(runVals, d); } - + Set> renamings = new LinkedHashSet<>(); PermutationIterator permit = new PermutationIterator(runVals.size()); for (int[] order : permit) { @@ -182,10 +176,10 @@ private Set> extendedValuationRenamings(SDT uSDT, renamings.add(remapping); } } - + return renamings; } - + private ArrayList removeFirst(ArrayList list, DataValue d) { ArrayList ret = new ArrayList<>(); ret.addAll(list); @@ -228,7 +222,7 @@ private Optional checkTransition(RALocation loc_i, SDT uExtHypSDT = sulOracle.treeQuery(uExtHyp, vi).toRegisterSDT(uExtHyp, consts); SDT uExtSulSDT = sulOracle.treeQuery(uExtSul, vi).toRegisterSDT(uExtSul, consts); // assert false : "Remember to convert SDTs to register SDTs"; - + if (SDT.equivalentUnderId(uExtHypSDT, uExtSulSDT)) { return Optional.empty(); } @@ -297,16 +291,16 @@ private boolean isGuardSatisfied(Expression guard, Mapping mapping = new Mapping<>(); DataValue[] vals = symbol.getParameterValues(); ParameterGenerator pgen = new ParameterGenerator(); - + ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); Expression guardRenamed = rvv.apply(guard, renaming); - + for (int i = 0; i < vals.length; i++) { Parameter p = pgen.next(vals[i].getDataType()); mapping.put(p, vals[i]); } mapping.putAll(consts); - + return solver.isSatisfiable(guardRenamed, mapping); } } diff --git a/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java index aaef57dc..93b715ab 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java +++ b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java @@ -15,17 +15,14 @@ import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; -import de.learnlib.ralib.data.Mapping; import de.learnlib.ralib.data.ParameterValuation; import de.learnlib.ralib.data.RegisterAssignment; -import de.learnlib.ralib.data.RegisterValuation; import de.learnlib.ralib.data.SymbolicDataValue; import de.learnlib.ralib.data.SymbolicDataValue.Parameter; import de.learnlib.ralib.data.SymbolicDataValue.Register; import de.learnlib.ralib.data.VarMapping; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; import de.learnlib.ralib.learning.AutomatonBuilder; -import de.learnlib.ralib.learning.Hypothesis; import de.learnlib.ralib.learning.rastar.RaStar; import de.learnlib.ralib.oracles.Branching; import de.learnlib.ralib.smt.ConstraintSolver; @@ -51,7 +48,7 @@ public class CTAutomatonBuilder { // private final Set> visitedTransitions; private final CTHypothesis hyp; - + private final ConstraintSolver solver; // private final Constants consts; @@ -129,7 +126,7 @@ private void computeTransition(CTLeaf dest_l, Prefix prefix) { Prefix dest_rp = dest_l.getRepresentativePrefix(); Word src_id = prefix.prefix(prefix.length() - 1); CTLeaf src_l = ct.getLeaf(src_id); - + // if (!src_id.equals(src_l.getRepresentativePrefix())) { // return; // } @@ -140,7 +137,7 @@ private void computeTransition(CTLeaf dest_l, Prefix prefix) { RALocation src_loc = locations.get(src_id); RALocation dest_loc = locations.get(dest_rp); - + assert src_loc != null; assert dest_loc != null; @@ -156,7 +153,7 @@ private void computeTransition(CTLeaf dest_l, Prefix prefix) { // guard Branching b = src_u.getBranching(action); Expression guard = b.getBranches().get(prefix); - + if (guard == null) { for (Expression g : b.getBranches().values()) { DataValue[] vals = prefix.lastSymbol().getParameterValues(); @@ -173,7 +170,7 @@ private void computeTransition(CTLeaf dest_l, Prefix prefix) { } assert guard != null : "No guard for prefix " + prefix; - + for (Transition tr : hyp.getTransitions(src_loc, action)) { if (tr.getGuard().equals(guard)) { return; @@ -192,7 +189,7 @@ private void computeTransition(CTLeaf dest_l, Prefix prefix) { Assignment assign = AutomatonBuilder.computeAssignment(prefix, srcAssignRemapped, destAssign, remapping); Transition t = createTransition(action, guard, src_loc, dest_loc, assign); - + if (t != null) { hyp.addTransition(src_loc, action, t); hyp.setTransitionSequence(t, prefix); @@ -337,16 +334,16 @@ else if (expr instanceof NumericBooleanExpression nbe) { //throw new IllegalStateException("Unsupported: " + expr.getClass()); } } - + private VarMapping registerRemapping(RegisterAssignment raa, RegisterAssignment rab, Bijection bijection) { VarMapping ret = new VarMapping<>(); - + for (Map.Entry be : bijection.entrySet()) { Register replace = raa.get(be.getKey()); Register by = rab.get(be.getValue()); ret.put(replace, by); } - + return ret; } } diff --git a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java index f61f518a..1a2c89b0 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java +++ b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java @@ -43,11 +43,11 @@ public CTHypothesis(Constants consts, Map leaves, boolean io public void putLeaves(Map leaves) { this.leaves.putAll(leaves); } - + public void setSink(RALocation sink) { this.sink = sink; } - + public RALocation getSink() { return sink; } @@ -64,7 +64,7 @@ public RALocation getLocation(CTLeaf leaf) { public CTLeaf getLeaf(RALocation location) { return leaves.inverse().get(location); } - + @Override public RARun getRun(Word word) { int n = word.length(); diff --git a/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java index 0fd3b807..d56dd508 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java +++ b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java @@ -69,7 +69,7 @@ protected Map, CTLeaf> refine(CTLeaf leaf, SymbolicSuffix CTBranch b = getBranch(leaf); assert b != null : "Node is not the parent of leaf " + leaf; assert !getSuffixes().contains(suffix) : "Duplicate suffix: " + suffix; - + Set shorts = leaf.getShortPrefixes(); CTInnerNode newNode = new CTInnerNode(this, suffix); diff --git a/src/main/java/de/learnlib/ralib/ct/CTLeaf.java b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java index d522a026..c78b6d05 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTLeaf.java +++ b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java @@ -1,7 +1,6 @@ package de.learnlib.ralib.ct; import java.util.Collection; -import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; @@ -84,7 +83,7 @@ public Prefix getRepresentativePrefix() { public boolean isLeaf() { return true; } - + public boolean isAccepting() { return rp.getPath().isAccepting(); } @@ -107,7 +106,7 @@ protected ShortPrefix elevatePrefix(Word u, TreeOracle oracle, ShortPrefix sp = new ShortPrefix(prefix, oracle, inputs); shortPrefixes.add(sp); prefixes.add(sp); - + if (prefix == rp) { rp = sp; } diff --git a/src/main/java/de/learnlib/ralib/ct/CTPath.java b/src/main/java/de/learnlib/ralib/ct/CTPath.java index 8b0f153d..19080a00 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTPath.java +++ b/src/main/java/de/learnlib/ralib/ct/CTPath.java @@ -13,9 +13,6 @@ import de.learnlib.ralib.oracles.TreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.SDT; -import de.learnlib.ralib.words.InputSymbol; -import de.learnlib.ralib.words.OutputSymbol; -import de.learnlib.ralib.words.ParameterizedSymbol; public class CTPath { private final Map sdts; @@ -120,7 +117,7 @@ public static CTPath computePath(TreeOracle oracle, Prefix prefix, List 0 && // prefix.lastSymbol().getBaseSymbol() instanceof InputSymbol) { diff --git a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java index 17cf614c..9341d60f 100644 --- a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java +++ b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java @@ -15,14 +15,11 @@ import de.learnlib.ralib.data.DataValue; import de.learnlib.ralib.data.Mapping; import de.learnlib.ralib.data.ParameterValuation; -import de.learnlib.ralib.data.SuffixValuation; import de.learnlib.ralib.data.SymbolicDataValue; import de.learnlib.ralib.data.SymbolicDataValue.Parameter; import de.learnlib.ralib.data.SymbolicDataValue.Register; -import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; import de.learnlib.ralib.data.util.RemappingIterator; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; -import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.SuffixValueGenerator; import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.learning.rastar.RaStar; import de.learnlib.ralib.oracles.Branching; @@ -440,7 +437,7 @@ private Optional transitionConsistentB(Word uA, } return Optional.empty(); } - + private boolean suffixRevealsNewGuard(SymbolicSuffix av, CTLeaf leaf) { Word u = leaf.getRepresentativePrefix(); SDT sdt = oracle.treeQuery(u, av); @@ -563,7 +560,7 @@ private Register[] inequivalentMapping(Bijection a, Bijection getSink() { if (!ioMode) { return Optional.empty(); } - + for (CTBranch branch : root.getBranches()) { if (!branch.getPath().isAccepting()) { CTNode node = branch.getChild(); diff --git a/src/main/java/de/learnlib/ralib/ct/MemorableSet.java b/src/main/java/de/learnlib/ralib/ct/MemorableSet.java index f1391292..fc8a9924 100644 --- a/src/main/java/de/learnlib/ralib/ct/MemorableSet.java +++ b/src/main/java/de/learnlib/ralib/ct/MemorableSet.java @@ -4,7 +4,6 @@ import de.learnlib.ralib.data.Bijection; import de.learnlib.ralib.data.DataValue; -import de.learnlib.ralib.data.SymbolicDataValue.Register; public class MemorableSet extends LinkedHashSet { public MemorableSet relabel(Bijection renaming) { diff --git a/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java b/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java index c8f5fa6d..d15f9678 100644 --- a/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java +++ b/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java @@ -11,7 +11,6 @@ import de.learnlib.ralib.theory.SDT; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; -import gov.nasa.jpf.constraints.api.Expression; import net.automatalib.word.Word; public class ShortPrefix extends Prefix { diff --git a/src/main/java/de/learnlib/ralib/data/RegisterAssignment.java b/src/main/java/de/learnlib/ralib/data/RegisterAssignment.java index 06d4f070..18e3352c 100644 --- a/src/main/java/de/learnlib/ralib/data/RegisterAssignment.java +++ b/src/main/java/de/learnlib/ralib/data/RegisterAssignment.java @@ -17,7 +17,7 @@ public RegisterValuation registerValuation() { } return vars; } - + public RegisterAssignment relabel(VarMapping remapping) { RegisterAssignment ret = new RegisterAssignment(); for (Map.Entry e : entrySet()) { diff --git a/src/main/java/de/learnlib/ralib/data/util/DataUtils.java b/src/main/java/de/learnlib/ralib/data/util/DataUtils.java index 69b5af45..648edda4 100644 --- a/src/main/java/de/learnlib/ralib/data/util/DataUtils.java +++ b/src/main/java/de/learnlib/ralib/data/util/DataUtils.java @@ -7,7 +7,6 @@ import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; import de.learnlib.ralib.data.SuffixValuation; -import de.learnlib.ralib.data.SymbolicDataValue; import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; import de.learnlib.ralib.data.TypedValue; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.SuffixValueGenerator; @@ -24,7 +23,7 @@ public static Map typedSize(Set set) { } return ts; } - + public static SuffixValuation actionValuation(PSymbolInstance action) { SuffixValuation valuation = new SuffixValuation(); DataValue[] vals = action.getParameterValues(); diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java index d3f43f57..5645f6b2 100644 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java @@ -184,7 +184,7 @@ public QueryStatistics getQueryStatistics() { public RaLearningAlgorithmName getName() { return RaLearningAlgorithmName.RADT; } - + public ClassificationTree getCT() { return ct; } diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java b/src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java index 8d9c5b54..7e2aa535 100644 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java @@ -28,13 +28,13 @@ import net.automatalib.word.Word; public class SLLambda implements RaLearningAlgorithm { - + private final ClassificationTree ct; - + private final Constants consts; private final Deque> counterexamples; - + private CTHypothesis hyp; private final TreeOracle sulOracle; @@ -45,7 +45,7 @@ public class SLLambda implements RaLearningAlgorithm { private final OptimizedSymbolicSuffixBuilder suffixBuilder; private final SymbolicSuffixRestrictionBuilder restrictionBuilder; - + private final Map teachers; private QueryStatistics queryStats; @@ -71,21 +71,21 @@ public SLLambda(TreeOracle sulOracle, TreeOracleFactory hypOracleFactory, SDTLog ct = new ClassificationTree(sulOracle, solver, restrictionBuilder, suffixBuilder, consts, ioMode, inputs); ct.initialize(); } - + @Override public void learn() { if (hyp == null) { while(!checkClosedness()); buildHypothesis(); } - + while(analyzeCounterExample()); - + if (queryStats != null) { queryStats.hypothesisConstructed(); } } - + private boolean checkClosedness() { if (!ct.checkOutputClosed()) { return false; @@ -101,7 +101,7 @@ private boolean checkClosedness() { } return true; } - + private boolean checkConsistency() { if (!ct.checkLocationConsistency()) { return false; @@ -119,12 +119,12 @@ private void buildHypothesis() { CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, ioMode, solver); hyp = ab.buildHypothesis(); } - + private boolean analyzeCounterExample() { if (counterexamples.isEmpty()) { return false; } - + // check whether ce is still a ce DefaultQuery ce = counterexamples.peek(); Word ceWord = ce.getInput(); @@ -137,12 +137,12 @@ private boolean analyzeCounterExample() { } // analyze counterexample - + if (queryStats != null) { queryStats.analyzingCounterExample(); queryStats.analyzeCE(ceWord); } - + PrefixFinder prefixFinder = new PrefixFinder(sulOracle, hyp, ct, @@ -150,11 +150,11 @@ private boolean analyzeCounterExample() { restrictionBuilder, solver, consts); - + Result res = prefixFinder.analyzeCounterExample(ceWord); // process counterexample - + if (queryStats != null) queryStats.processingCounterExample(); @@ -168,7 +168,7 @@ private boolean analyzeCounterExample() { ct.expand(res.prefix()); break; } - + boolean closedAndConsistent = false; while(!closedAndConsistent) { if (checkClosedness()) { @@ -177,7 +177,7 @@ private boolean analyzeCounterExample() { } } } - + buildHypothesis(); return true; } diff --git a/src/main/java/de/learnlib/ralib/oracles/mto/MultiTheoryTreeOracle.java b/src/main/java/de/learnlib/ralib/oracles/mto/MultiTheoryTreeOracle.java index dfe98391..97078c4b 100644 --- a/src/main/java/de/learnlib/ralib/oracles/mto/MultiTheoryTreeOracle.java +++ b/src/main/java/de/learnlib/ralib/oracles/mto/MultiTheoryTreeOracle.java @@ -18,7 +18,6 @@ import java.util.ArrayList; import java.util.Collections; -import java.util.Deque; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -480,12 +479,12 @@ public Map getTeachers() { public SymbolicSuffixRestrictionBuilder getRestrictionBuilder() { return restrictionBuilder; } - + private boolean isValid(Word word) { if (word.length() < 1) { return true; } - + Word actions = DataWords.actsOf(word); if (actions.stream() .filter(a -> a instanceof OutputSymbol) @@ -493,7 +492,7 @@ private boolean isValid(Word word) { .isEmpty()) { return true; } - + boolean inExpected = true; for (ParameterizedSymbol action : actions) { if (inExpected ^ (action instanceof InputSymbol)) { @@ -501,10 +500,10 @@ private boolean isValid(Word word) { } inExpected = !inExpected; } - + return true; } - + private SDT makeRejectingSDT(SymbolicSuffix suffix) { Queue types = new LinkedList<>(); for (ParameterizedSymbol ps : suffix.getActions()) { @@ -514,19 +513,19 @@ private SDT makeRejectingSDT(SymbolicSuffix suffix) { } return makeRejectingSDT(1, types); } - + private SDT makeRejectingSDT(int param, Queue types) { if (types.isEmpty()) { return SDTLeaf.REJECTING; } - + DataType type = types.poll(); SuffixValue sv = new SuffixValue(type, param); SDTGuard g = new SDTGuard.SDTTrueGuard(sv); - + Map child = new LinkedHashMap<>(); child.put(g, makeRejectingSDT(param+1, types)); - + return new SDT(child); } } diff --git a/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java b/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java index 8ba9706b..5555ae84 100644 --- a/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java +++ b/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java @@ -45,15 +45,8 @@ import de.learnlib.ralib.data.SymbolicDataValue.Parameter; import de.learnlib.ralib.data.SymbolicDataValue.Register; import de.learnlib.ralib.data.VarMapping; -import de.learnlib.ralib.dt.DTHyp; -import de.learnlib.ralib.dt.DTLeaf; -import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.learning.rastar.RaStar; import de.learnlib.ralib.oracles.DataWordOracle; -import de.learnlib.ralib.oracles.SDTLogicOracle; import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; @@ -97,12 +90,12 @@ public void testPrefixFinder() { // RaStar rastar = new RaStar(mto, hypFactory, slo, // consts, I_LOGIN, I_LOGOUT, I_REGISTER); - + SymbolicSuffixRestrictionBuilder rb = new SymbolicSuffixRestrictionBuilder(consts, teachers); OptimizedSymbolicSuffixBuilder sb = new OptimizedSymbolicSuffixBuilder(consts, rb); ClassificationTree ct = new ClassificationTree(mto, solver, rb, sb, consts, false, I_LOGIN, I_LOGOUT, I_REGISTER); - + ct.initialize(); boolean closed = false; while(!closed) { @@ -124,7 +117,7 @@ public void testPrefixFinder() { new DataValue(T_UID, BigDecimal.ONE), new DataValue(T_PWD, BigDecimal.ONE))); PrefixFinder pf = new PrefixFinder(mto, hyp, ct, teachers, rb, solver, consts); - + // PrefixFinder pf = new PrefixFinder( // MTO, // HYPFACTORY.CREATETREEORACLE(HYP), HYP, @@ -169,7 +162,7 @@ public void testPrefixFinderMultipleAccessSequences() { OptimizedSymbolicSuffixBuilder sb = new OptimizedSymbolicSuffixBuilder(consts, rb); ClassificationTree ct = new ClassificationTree(mto, solver, rb, sb, consts, false, I_PUSH, I_POP); - + ct.initialize(); boolean closed = false; while(!closed) { @@ -200,39 +193,39 @@ public void testPrefixFinderMultipleAccessSequences() { // ); PrefixFinder pf = new PrefixFinder(mto, hyp, ct, teachers, rb, solver, consts); - + // Word prefix = pf.analyzeCounterexample(ce).getPrefix(); Result res = pf.analyzeCounterExample(ce); Assert.assertEquals(res.result(), PrefixFinder.ResultType.TRANSITION); Assert.assertEquals(res.prefix().toString(), "push[0[T_int]] pop[0[T_int]]"); } - + private final DataType DT = new DataType("double"); private final InputSymbol A = new InputSymbol("α", DT); private final InputSymbol B = new InputSymbol("β"); - + private RegisterAutomaton buildTestAutomaton() { MutableRegisterAutomaton ra = new MutableRegisterAutomaton(); - + Register x1 = new Register(DT, 1); Parameter p1 = new Parameter(DT, 1); - + RALocation l0 = ra.addInitialState(true); RALocation l1 = ra.addState(false); RALocation l2 = ra.addState(false); RALocation l3 = ra.addState(false); - + Expression gTrue = ExpressionUtil.TRUE; Expression gGT = new NumericBooleanExpression(x1, NumericComparator.GE, p1); Expression gLT = new NumericBooleanExpression(x1, NumericComparator.LT, p1); - + VarMapping mapX1P1 = new VarMapping<>(); mapX1P1.put(x1, p1); VarMapping mapNo = new VarMapping<>(); - + Assignment assX1P1 = new Assignment(mapX1P1); Assignment assNo = new Assignment(mapNo); - + ra.addTransition(l0, A, new InputTransition(gTrue, A, l0, l1, assX1P1)); ra.addTransition(l0, B, new InputTransition(gTrue, B, l0, l0, assNo)); ra.addTransition(l1, A, new InputTransition(gGT, A, l1, l2, assNo)); @@ -242,25 +235,25 @@ private RegisterAutomaton buildTestAutomaton() { ra.addTransition(l2, B, new InputTransition(gTrue, B, l2, l2, assNo)); ra.addTransition(l3, A, new InputTransition(gTrue, A, l3, l0, assNo)); ra.addTransition(l3, B, new InputTransition(gTrue, B, l3, l0, assNo)); - + return ra; } - + @Test public void testAnalyzeCELocation() { RegisterAutomaton ra = buildTestAutomaton(); DataWordOracle dwOracle = new SimulatorOracle(ra); - + final Map teachers = new LinkedHashMap<>(); DoubleInequalityTheory dit = new DoubleInequalityTheory(DT); dit.useSuffixOptimization(false); teachers.put(DT, dit); - + ConstraintSolver solver = new ConstraintSolver(); Constants consts = new Constants(); - + MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(dwOracle, teachers, consts, solver); - + SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); @@ -268,42 +261,42 @@ public void testAnalyzeCELocation() { DataValue dv1 = new DataValue(DT, BigDecimal.ONE); DataValue dv2 = new DataValue(DT, BigDecimal.valueOf(2)); DataValue dv3 = new DataValue(DT, BigDecimal.valueOf(3)); - + ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, false, A, B); - + ct.initialize(); ct.checkLocationClosedness(); ct.checkLocationClosedness(); CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), false, solver); CTHypothesis hyp = ab.buildHypothesis(); - + Word ce1 = Word.fromSymbols( new PSymbolInstance(A, dv1), new PSymbolInstance(A, dv2), new PSymbolInstance(A, dv3)); - + PrefixFinder pf = new PrefixFinder(mto, hyp, ct, teachers, restrBuilder, solver, consts); - + Result res = pf.analyzeCounterExample(ce1); Assert.assertEquals(res.result(), PrefixFinder.ResultType.LOCATION); Assert.assertEquals(res.prefix().toString(), "α[1[double]] α[2[double]]"); - + ct.expand(res.prefix()); boolean consistent = ct.checkLocationConsistency(); Assert.assertFalse(consistent); - + ab = new CTAutomatonBuilder(ct, consts, false, solver); hyp = ab.buildHypothesis(); pf = new PrefixFinder(mto, hyp, ct, teachers, restrBuilder, solver, consts); - + Word ce2 = Word.fromSymbols( new PSymbolInstance(A, dv1), new PSymbolInstance(A, dv0), new PSymbolInstance(B)); - + Assert.assertFalse(hyp.accepts(ce2) == ra.accepts(ce2)); - + res = pf.analyzeCounterExample(ce2); Assert.assertEquals(res.result(), PrefixFinder.ResultType.TRANSITION); Assert.assertEquals(res.prefix().toString(), "α[1[double]] α[0[double]]"); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java index 4a65255d..96b06dd4 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java @@ -119,7 +119,7 @@ public void testLearnLoginRandom() { measuresStar[seed] = runner.getMeasurements(); runner.resetMeasurements(); } - + Assert.assertEquals(Arrays.toString(measuresLambda), "[{TQ: 88, Resets: 1997, Inputs: 0}," + " {TQ: 88, Resets: 1984, Inputs: 0}," + diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java index b67148f3..331f185b 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java @@ -75,7 +75,7 @@ public void testLearnPalindromeIO() { // RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); // ralambda.setSolver(solver); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); - + IOEquivalenceTest ioEquiv = new IOEquivalenceTest( model, teachers, consts, true, actions); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java index 89c9c42e..0b21941c 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java @@ -20,7 +20,6 @@ import de.learnlib.ralib.equivalence.IOCounterexampleLoopRemover; import de.learnlib.ralib.equivalence.IOEquivalenceTest; import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.oracles.SimulatorOracle; import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOCache; @@ -37,7 +36,6 @@ import de.learnlib.ralib.tools.theories.IntegerEqualityTheory; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; -import net.automatalib.word.Word; public class LearnSipIOTest extends RaLibTestSuite { @Test diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java index ba0a7c00..4b7f9da3 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java @@ -7,14 +7,9 @@ import java.math.BigDecimal; import java.util.Arrays; -import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Set; import java.util.logging.Level; -import java.util.stream.Collectors; - -import com.google.common.collect.ImmutableSet; import org.testng.Assert; import org.testng.annotations.Test; @@ -30,7 +25,6 @@ import de.learnlib.ralib.learning.Measurements; import de.learnlib.ralib.learning.MeasuringOracle; import de.learnlib.ralib.learning.RaLearningAlgorithmName; -import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.oracles.DataWordOracle; import de.learnlib.ralib.oracles.SDTLogicOracle; import de.learnlib.ralib.oracles.SimulatorOracle; diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java index 3331ca7e..279083ab 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java @@ -20,8 +20,6 @@ import de.learnlib.ralib.learning.QueryStatistics; import de.learnlib.ralib.oracles.SimulatorOracle; import de.learnlib.ralib.oracles.TreeOracleFactory; -import de.learnlib.ralib.oracles.io.IOCache; -import de.learnlib.ralib.oracles.io.IOFilter; import de.learnlib.ralib.oracles.io.IOOracle; import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; @@ -115,7 +113,7 @@ public void testQueryCount() { learner.addCounterexample(ceQuery); learner.learn(); - + long memQueries3 = learner.getQueryStatistics().getMemQueries(); Assert.assertEquals(memQueries3, 48); } From decd5ea014e53c0face9fd102d016ccfacd662db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Fri, 7 Nov 2025 10:33:36 +0100 Subject: [PATCH 10/31] remove one additional unused file --- .../ralambda/GeneratedHypothesesTest.java | 72 ------------------- 1 file changed, 72 deletions(-) delete mode 100644 src/test/java/de/learnlib/ralib/learning/ralambda/GeneratedHypothesesTest.java diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/GeneratedHypothesesTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/GeneratedHypothesesTest.java deleted file mode 100644 index 4f19abbf..00000000 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/GeneratedHypothesesTest.java +++ /dev/null @@ -1,72 +0,0 @@ -//package de.learnlib.ralib.learning.ralambda; -// -//import static de.learnlib.ralib.example.stack.StackAutomatonExample.AUTOMATON; -//import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_POP; -//import static de.learnlib.ralib.example.stack.StackAutomatonExample.I_PUSH; -//import static de.learnlib.ralib.example.stack.StackAutomatonExample.T_INT; -// -//import java.util.LinkedHashMap; -//import java.util.Map; -// -//import org.testng.Assert; -//import org.testng.annotations.Ignore; -//import org.testng.annotations.Test; -// -//import de.learnlib.ralib.RaLibTestSuite; -//import de.learnlib.ralib.automata.RegisterAutomaton; -//import de.learnlib.ralib.data.Constants; -//import de.learnlib.ralib.data.DataType; -//import de.learnlib.ralib.dt.DTHyp; -//import de.learnlib.ralib.learning.Hypothesis; -//import de.learnlib.ralib.learning.Measurements; -//import de.learnlib.ralib.learning.MeasuringOracle; -//import de.learnlib.ralib.oracles.DataWordOracle; -//import de.learnlib.ralib.oracles.SDTLogicOracle; -//import de.learnlib.ralib.oracles.SimulatorOracle; -//import de.learnlib.ralib.oracles.TreeOracleFactory; -//import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; -//import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; -//import de.learnlib.ralib.smt.ConstraintSolver; -//import de.learnlib.ralib.theory.Theory; -//import de.learnlib.ralib.tools.theories.IntegerEqualityTheory; -// -//@Ignore -//public class GeneratedHypothesesTest extends RaLibTestSuite { -// -// /** -// * Tests that {@link RaLambda#getHypothesis()} returns a generic {@link Hypothesis} -// * (and not a specialized Hypothesis, such as a {@link DTHyp}, which is a lot slower) -// * -// */ -// @Test -// public void testGetHypothesis() { -// Constants consts = new Constants(); -// RegisterAutomaton sul = AUTOMATON; -// DataWordOracle dwOracle = new SimulatorOracle(sul); -// ConstraintSolver solver = new ConstraintSolver(); -// -// final Map teachers = new LinkedHashMap<>(); -// IntegerEqualityTheory theory = new IntegerEqualityTheory(T_INT); -// theory.setUseSuffixOpt(false); -// teachers.put(T_INT, theory); -// -// Measurements mes = new Measurements(); -// -// MeasuringOracle mto = new MeasuringOracle(new MultiTheoryTreeOracle( -// dwOracle, teachers, new Constants(), solver), mes); -// -// SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); -// -// TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> -// new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, -// new Constants(), solver); -// -// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); -// ralambda.setSolver(solver); -// -// ralambda.learn(); -// RegisterAutomaton hyp = ralambda.getHypothesis(); -// -// Assert.assertEquals(hyp.getClass(), Hypothesis.class); -// } -//} From a4244499a17a4dc1f8d2ac246df3b741e5557a7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Fri, 7 Nov 2025 10:35:32 +0100 Subject: [PATCH 11/31] change variable name to keep codespell happy --- src/main/java/de/learnlib/ralib/ct/ClassificationTree.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java index 9341d60f..7a364444 100644 --- a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java +++ b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java @@ -342,9 +342,9 @@ public boolean checkLocationConsistency() { while (sp.hasNext()) { ShortPrefix uPrime = sp.next(); for (ParameterizedSymbol action : inputs) { - for (Map.Entry, Expression> ue : u.getBranching(action).getBranches().entrySet()) { - Word ua = ue.getKey(); - Expression g = ue.getValue(); + for (Map.Entry, Expression> uEntry : u.getBranching(action).getBranches().entrySet()) { + Word ua = uEntry.getKey(); + Expression g = uEntry.getValue(); Bijection gamma = u.getRpBijection().compose(uPrime.getRpBijection().inverse()); ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); From 5574133c9b62b5fb44b24436d3cdd34ef1bdd4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Fri, 7 Nov 2025 10:50:33 +0100 Subject: [PATCH 12/31] remove some prints --- src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java | 4 ---- src/test/java/de/learnlib/ralib/ct/CTTest.java | 6 ------ 2 files changed, 10 deletions(-) diff --git a/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java b/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java index bbe0644b..d206df9e 100644 --- a/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java +++ b/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java @@ -132,8 +132,6 @@ public void testLocationConsistency() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, consts, solver); - System.out.println(sul); - DataValue dv0 = new DataValue(DT, BigDecimal.ZERO); DataValue dv1 = new DataValue(DT, BigDecimal.ONE); DataValue dv2 = new DataValue(DT, BigDecimal.valueOf(2)); @@ -265,8 +263,6 @@ public void testRegisterConsistency() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, consts, solver); - System.out.println(sul); - DataValue dv0 = new DataValue(T_INT, BigDecimal.ZERO); DataValue dv1 = new DataValue(T_INT, BigDecimal.ONE); DataValue dv2 = new DataValue(T_INT, BigDecimal.valueOf(2)); diff --git a/src/test/java/de/learnlib/ralib/ct/CTTest.java b/src/test/java/de/learnlib/ralib/ct/CTTest.java index c5298f71..8a608561 100644 --- a/src/test/java/de/learnlib/ralib/ct/CTTest.java +++ b/src/test/java/de/learnlib/ralib/ct/CTTest.java @@ -265,8 +265,6 @@ public void testCTAutomatonBuilder() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, consts, solver); - System.out.println(sul); - DataValue dv0 = new DataValue(doubleType, BigDecimal.ZERO); DataValue dv1 = new DataValue(doubleType, BigDecimal.ONE); DataValue dv2 = new DataValue(doubleType, BigDecimal.valueOf(2)); @@ -320,12 +318,8 @@ public void testCTAutomatonBuilder() { ct.expand(o1yo2yo0y); ct.expand(o1yo2yo2y); - System.out.println(ct); - CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), true, solver); Hypothesis hyp = ab.buildHypothesis(); - - System.out.println(hyp); } private RegisterAutomaton buildTestRA() { From 4b8e2533e07ad9e8d17f72848d7363e7031c3109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Fri, 7 Nov 2025 10:59:04 +0100 Subject: [PATCH 13/31] remove unused dependency --- pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pom.xml b/pom.xml index afac763a..55f1db95 100644 --- a/pom.xml +++ b/pom.xml @@ -218,11 +218,6 @@ de.learnlib learnlib-util - - org.apache.commons - commons-lang3 - ${commons-lang.version} - tools.aqua jconstraints-core From 0041267929c5f0f5df3205e838840f56c4df7d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Fri, 7 Nov 2025 11:51:30 +0100 Subject: [PATCH 14/31] remove unused and commented out code --- .../ralib/ceanalysis/PrefixFinder.java | 4 - .../learnlib/ralib/ct/CTAutomatonBuilder.java | 97 --------- .../java/de/learnlib/ralib/ct/CTBranch.java | 2 - .../de/learnlib/ralib/ct/CTHypothesis.java | 1 - .../de/learnlib/ralib/ct/CTInnerNode.java | 46 +---- .../java/de/learnlib/ralib/ct/CTLeaf.java | 17 -- .../java/de/learnlib/ralib/ct/CTPath.java | 26 --- .../learnlib/ralib/ct/ClassificationTree.java | 29 --- .../java/de/learnlib/ralib/ct/Prefix.java | 16 -- .../ralib/data/util/RemappingIterator.java | 1 - .../ralib/learning/AutomatonBuilder.java | 16 -- .../ralib/learning/IOAutomatonBuilder.java | 10 - .../ralib/learning/ralambda/SLCT.java | 1 - .../ralib/theory/equality/EqualityTheory.java | 2 - .../inequality/InequalityTheoryWithEq.java | 7 - .../learnlib/ralib/tools/ClassAnalyzer.java | 3 - .../de/learnlib/ralib/tools/IOSimulator.java | 3 - .../learnlib/ralib/ct/CTConsistencyTest.java | 12 -- .../java/de/learnlib/ralib/ct/CTTest.java | 191 ------------------ .../learning/ralambda/IOHandlingTest.java | 22 -- .../learning/ralambda/LearnABPOutputTest.java | 2 - .../learning/ralambda/LearnEchoTest.java | 1 - .../learning/ralambda/LearnLoginTest.java | 3 - .../learning/ralambda/LearnMixedIOTest.java | 2 - .../learning/ralambda/LearnPQIOTest.java | 3 - .../ralib/learning/ralambda/LearnPQTest.java | 1 - .../ralib/learning/ralambda/LearnPadlock.java | 2 - .../ralambda/LearnPalindromeIOTest.java | 3 - .../learning/ralambda/LearnRepeaterTest.java | 2 - .../learning/ralambda/LearnSipIOTest.java | 10 - .../learning/ralambda/LearnStackTest.java | 18 -- .../TestDistinguishingSuffixOptimization.java | 2 - .../learning/ralambda/TestOutputSuffixes.java | 1 - .../learning/ralambda/TestQueryCount.java | 2 - .../ralambda/TestSuffixOptimization.java | 4 - .../ralib/learning/ralambda/TestSymmetry.java | 2 - .../ralambda/TestUnknownMemorable.java | 6 - 37 files changed, 2 insertions(+), 568 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java index 66760fce..42a41058 100644 --- a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java +++ b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java @@ -127,7 +127,6 @@ private Mapping valuationRenaming(Word u, if (by == null) { by = replace; } -// assert by != null; ret.put(replace, by); } return ret; @@ -221,7 +220,6 @@ private Optional checkTransition(RALocation loc_i, Word uExtHyp = extensions.next(); // u_{i-1}\alpha_i(d_i') SDT uExtHypSDT = sulOracle.treeQuery(uExtHyp, vi).toRegisterSDT(uExtHyp, consts); SDT uExtSulSDT = sulOracle.treeQuery(uExtSul, vi).toRegisterSDT(uExtSul, consts); -// assert false : "Remember to convert SDTs to register SDTs"; if (SDT.equivalentUnderId(uExtHypSDT, uExtSulSDT)) { return Optional.empty(); @@ -271,12 +269,10 @@ private Optional> getHypGuard(RARun run, int idx) { CTLeaf leafNext = hyp.getLeaf(locNext); RegisterValuation mu = run.getValuation(idx-1); PSymbolInstance a = run.getTransition(idx); -// ShortPrefix rp = (ShortPrefix) hyp.getLeaf(loc).getRepresentativePrefix(); ShortPrefix sp = hyp.getLeaf(loc).getShortPrefixes().iterator().next(); Mapping renaming = valuationRenaming(sp, mu); for (Word ua : ct.getExtensions(sp, a.getBaseSymbol())) { if (leafNext.getPrefixes().contains(ua)) { -// Expression g = sp.getBranching(a.getBaseSymbol()).getBranches().get(ua); for (Expression g : sp.getBranching(a.getBaseSymbol()).getBranches().values()) { if (isGuardSatisfied(g, renaming, a)) { return Optional.of(g); diff --git a/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java index 93b715ab..a2f8dc0b 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java +++ b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java @@ -43,28 +43,20 @@ public class CTAutomatonBuilder { private final Map, RALocation> locations; private final Map leaves; -// private final Map, Bijection> rpRenamings; - -// private final Set> visitedTransitions; private final CTHypothesis hyp; private final ConstraintSolver solver; -// private final Constants consts; - private boolean ioMode; public CTAutomatonBuilder(ClassificationTree ct, Constants consts, boolean ioMode, ConstraintSolver solver) { this.ct = ct; -// this.consts = consts; this.ioMode = ioMode; this.solver = solver; locations = new LinkedHashMap<>(); leaves = new LinkedHashMap<>(); -// rpRenamings = new LinkedHashMap<>(); -// visitedTransitions = new LinkedHashSet<>(); hyp = new CTHypothesis(consts, ct.getLeaves().size(), ioMode); } @@ -87,14 +79,12 @@ private void computeLocations() { locations.put(sp, l0); } hyp.setAccessSequence(l0, RaStar.EMPTY_PREFIX); -// rpRenamings.put(RaStar.EMPTY_PREFIX, new Bijection()); leaves.put(initial, l0); for (CTLeaf leaf : ct.getLeaves()) { if (leaf != initial) { RALocation l = hyp.addState(leaf.isAccepting()); hyp.setAccessSequence(l, leaf.getRepresentativePrefix()); -// locations.put(leaf.getRepresentativePrefix(), l); for (Word sp : leaf.getShortPrefixes()) { locations.put(sp, l); } @@ -106,7 +96,6 @@ private void computeLocations() { private void computeTransitions() { for (CTLeaf leaf : ct.getLeaves()) { -// computeTransition(leaf, leaf.getRepresentativePrefix()); for (Prefix prefix : leaf.getPrefixes()) { computeTransition(leaf, prefix); } @@ -114,26 +103,16 @@ private void computeTransitions() { } private void computeTransition(CTLeaf dest_l, Prefix prefix) { -// if (visitedTransitions.contains(prefix)) { -// return; -// } - if (prefix.length() < 1) { return; } -// Word dest_id = prefix; Prefix dest_rp = dest_l.getRepresentativePrefix(); Word src_id = prefix.prefix(prefix.length() - 1); CTLeaf src_l = ct.getLeaf(src_id); -// if (!src_id.equals(src_l.getRepresentativePrefix())) { -// return; -// } - assert src_l != null : "Source prefix not present in classification tree: " + src_id; assert src_l.getPrefix(src_id) instanceof ShortPrefix : "Source prefix is not short: " + src_id; -// assert dest_rp instanceof ShortPrefix : "Representative prefix is not short: " + dest_rp; RALocation src_loc = locations.get(src_id); RALocation dest_loc = locations.get(dest_rp); @@ -143,8 +122,6 @@ private void computeTransition(CTLeaf dest_l, Prefix prefix) { ParameterizedSymbol action = prefix.lastSymbol().getBaseSymbol(); -// assert src_l.getRepresentativePrefix() instanceof ShortPrefix : "Representative prefix is not a short prefix: " + src_l; - Prefix src_prefix = src_l.getPrefix(src_id); ShortPrefix src_u = (ShortPrefix)(src_prefix instanceof ShortPrefix ? src_prefix : @@ -182,7 +159,6 @@ private void computeTransition(CTLeaf dest_l, Prefix prefix) { RegisterAssignment rpAssign = src_l.getRepresentativePrefix().getAssignment(); RegisterAssignment srcAssignRemapped = srcAssign.relabel(registerRemapping(srcAssign, rpAssign, src_u.getRpBijection())); guard = rvv.apply(guard, srcAssignRemapped); -// guard = rvv.apply(guard, src_u.getAssignment()); RegisterAssignment destAssign = dest_rp.getAssignment(); Bijection remapping = prefix.getRpBijection(); @@ -194,73 +170,6 @@ private void computeTransition(CTLeaf dest_l, Prefix prefix) { hyp.addTransition(src_loc, action, t); hyp.setTransitionSequence(t, prefix); } -// -// Word src_rp = src_l.getRepresentativePrefix(); -// Bijection src_renaming = rpRenamings.get(src_rp); -// if (src_renaming == null) { -// computeTransition(src_l, src_l.getRepresentativePrefix()); -// src_renaming = rpRenamings.get(src_rp); -// } -// -// int max = DataWords.paramValLength(src_id); -// List regs = new ArrayList<>(prefix.getRegisters()); -// regs.sort((r1, r2) -> Integer.compare(r1.getId(), r2.getId())); -// RegisterGenerator rgen = new RegisterGenerator(); -// -// Map mapping = new LinkedHashMap<>(); -// -// Bijection dest_renaming; -// if (prefix == dest_l.getRepresentativePrefix()) { -// // case 1 : prefix is the rp -// dest_renaming = new Bijection(); -// for (Register r : regs) { -// Register reg = rgen.next(r.getDataType()); -// dest_renaming.put(r, reg); -// if (r.getId() > max) { -// Parameter p = new Parameter(r.getDataType(), r.getId() - max); -// mapping.put(reg, p); -// } else { -// Register p = src_renaming.get(r); -// assert p != null : "Register not memorable in source location: " + r; -// mapping.put(reg, p); -// } -// } -// rpRenamings.put(prefix, dest_renaming); -// } else { -// // case 2 : prefix is not the rp -//// Word dest_rp = dest_l.getRepresentativePrefix().getPrefix(); -// Bijection rp_renaming = rpRenamings.get(dest_rp); -// assert rp_renaming != null : "No rp mapping: " + dest_rp; -// dest_renaming = prefix.getRpBijection().compose(rp_renaming); -// for (Register r : regs) { -// Register reg = dest_renaming.get(r); -// assert reg != null : "Register not compatible with rp: " + r; -// if (r.getId() > max) { -// Parameter p = new Parameter(r.getDataType(), r.getId() - max); -// mapping.put(reg, p); -// } else { -// Register src_r = src_renaming.get(r); -// assert src_r != null : "Register not memorable in source location: " + r; -// mapping.put(reg, src_r); -// } -// } -// } -// -// VarMapping vars = new VarMapping<>(); -// vars.putAll(mapping); -// Assignment assignment = new Assignment(vars); -// -// VarMapping guardRenaming = new VarMapping<>(); -// guardRenaming.putAll(src_renaming); -// Expression guardRenamed = SMTUtil.renameVars(guard, guardRenaming); -// -// Transition transition = createTransition(action, guardRenamed, src_loc, dest_loc, assignment); -// if (transition != null) { -// hyp.addTransition(src_loc, action, transition); -// hyp.setTransitionSequence(transition, dest_id); -// } -// -// visitedTransitions.add(dest_id); } private Transition createTransition(ParameterizedSymbol action, Expression guard, @@ -273,7 +182,6 @@ private Transition createTransition(ParameterizedSymbol action, Expression expr = guard; VarMapping outmap = new VarMapping<>(); @@ -305,7 +213,6 @@ private void analyzeExpression(Expression expr, else if (expr instanceof NumericBooleanExpression nbe) { if (nbe.getComparator() == NumericComparator.EQ) { // FIXME: this is unchecked! - //System.out.println(expr); SymbolicDataValue left = (SymbolicDataValue) nbe.getLeft(); SymbolicDataValue right = (SymbolicDataValue) nbe.getRight(); @@ -329,10 +236,6 @@ else if (expr instanceof NumericBooleanExpression nbe) { outmap.put(p, sv); } } - else { - // true and false ... - //throw new IllegalStateException("Unsupported: " + expr.getClass()); - } } private VarMapping registerRemapping(RegisterAssignment raa, RegisterAssignment rab, Bijection bijection) { diff --git a/src/main/java/de/learnlib/ralib/ct/CTBranch.java b/src/main/java/de/learnlib/ralib/ct/CTBranch.java index bd042363..4e6299f4 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTBranch.java +++ b/src/main/java/de/learnlib/ralib/ct/CTBranch.java @@ -37,8 +37,6 @@ public Bijection matches(CTPath other, ConstraintSolver solver) { for (Bijection vars : it) { if (reprPath.isEquivalent(other, vars, solver)) { -// if (reprPath.isEquivalent(other, vars, solver) && -// other.isEquivalent(getPath(), vars, solver)) { return vars; } } diff --git a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java index 1a2c89b0..12c88b7b 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java +++ b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java @@ -90,7 +90,6 @@ public RARun getRun(Word word) { for (Transition t : candidates) { if (t.isEnabled(vals[i], pars, constants)) { -// vals[i+1] = t.execute(vals[i], pars, constants); vals[i+1] = t.valuation(vals[i], pars, constants); locs[i+1] = t.getDestination(); found = true; diff --git a/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java index d56dd508..c107d8b6 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java +++ b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java @@ -8,6 +8,7 @@ import java.util.Set; import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.data.DataValue; import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.oracles.TreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; @@ -45,13 +46,10 @@ protected CTBranch getBranch(CTNode child) { @Override protected CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, boolean ioMode) { CTPath path = CTPath.computePath(oracle, prefix, getSuffixes(), ioMode); -// SDT sdt = path.getSDT(suffix); -// prefix.putSDT(suffix, sdt); for (CTBranch b : branches) { - Bijection vars = b.matches(path, solver); + Bijection vars = b.matches(path, solver); if (vars != null) { -// prefix.setRpBijection(vars); prefix = new Prefix(prefix, vars, path); return b.getChild().sift(prefix, oracle, solver, ioMode); } @@ -119,44 +117,4 @@ public String toString() { return "(" + suffix + ")"; } -// @Override -// protected void sift(Prefix u, Map rpSDTs, ConstraintSolver solver, TreeOracle oracle) { -// TreeQueryResult tqr = oracle.treeQuery(u.getPrefix(), suffix); -// SDT sdt = tqr.getSdt().relabel(tqr.getPiv().getRenaming().toVarMapping()); -// -// Set regs = new LinkedHashSet<>(); -// regs.addAll(u.getRegisters()); -// regs.addAll(sdt.getRegisters()); -// -// Set rpRegs = new LinkedHashSet<>(); -// for (SDT sdt : rpSDTs.values()) { -// rpRegs.addAll(sdt.getRegisters()); -// } -// -// for (CTBranch b : branches) { -// Set branchRegs = new LinkedHashSet<>(rpRegs); -// branchRegs.addAll(b.getSDT().getRegisters()); -// -// RemappingIterator it = new RemappingIterator(regs, branchRegs); -// -// while(it.hasNext()) { -// Bijection renaming = it.next(); -// if (!b.equivalentUnderRenaming(u, rpSDTs, renaming, solver, oracle)) { -// continue; -// } -// -// // equivalent for all SDTs up to this point -// u = new Prefix(u, new Bijection(renaming)); -// u.putSDT(suffix, sdt); -// rpSDTs.put(suffix, sdt); -// b.getChild().sift(u, rpSDTs, solver, oracle); -// return; -// } -// } -// -// // no branch with equivalent SDT, create new leaf -// u.putSDT(suffix, sdt); -// CTLeaf leaf = new CTLeaf(u, this); -// } - } diff --git a/src/main/java/de/learnlib/ralib/ct/CTLeaf.java b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java index c78b6d05..2e23df87 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTLeaf.java +++ b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java @@ -55,26 +55,10 @@ public Prefix getPrefix(Word u) { return null; } -// public Set> getWords() { -// return getWords(prefixes); -// } - public Set getShortPrefixes() { return shortPrefixes; } -// public Set> getShortWords() { -// return getWords(shortPrefixes); -// } - -// private static Set> getWords(Set prefixes) { -// Set> words = new LinkedHashSet<>(); -// for (Prefix p : prefixes) { -// words.add(p.getPrefix()); -// } -// return words; -// } - public Prefix getRepresentativePrefix() { return rp; } @@ -115,7 +99,6 @@ protected ShortPrefix elevatePrefix(Word u, TreeOracle oracle, @Override public String toString() { -// return prefixes.toString(); String str = "{RP:[" + rp.toString() + "]"; for (Prefix u : prefixes) { if (u != rp) { diff --git a/src/main/java/de/learnlib/ralib/ct/CTPath.java b/src/main/java/de/learnlib/ralib/ct/CTPath.java index 19080a00..3bbe926c 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTPath.java +++ b/src/main/java/de/learnlib/ralib/ct/CTPath.java @@ -105,37 +105,11 @@ public static CTPath computePath(TreeOracle oracle, Prefix prefix, List 0) { -// // error path -// if (prefix.length() > 0 && !r.isAccepting()) { -// continue; -// } -// -// // umatched suffix -// ParameterizedSymbol first = s.getActions().firstSymbol(); -// if (first instanceof OutputSymbol && -// (prefix.length() < 1 || prefix.lastSymbol().getBaseSymbol() instanceof OutputSymbol)) { -// continue; -// } -// -// if (first instanceof InputSymbol && -// prefix.length() > 0 && -// prefix.lastSymbol().getBaseSymbol() instanceof InputSymbol) { -// continue; -// } -//// if ((prefix.length() < 1 && (s.getActions().firstSymbol() instanceof OutputSymbol))) { -//// continue; -//// } -// } - sdt = prefix.getSDT(s); if (sdt == null) { sdt = oracle.treeQuery(prefix, s); -// sdt = tqr.sdt(); -// sdt = tqr.getSdt().relabel(tqr.getPiv().getRenaming().toVarMapping()); } -// r.sdts.put(s, sdt); if (r.getSDT(s) == null) { r.putSDT(s, sdt); } diff --git a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java index 7a364444..65dbe61a 100644 --- a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java +++ b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java @@ -94,10 +94,6 @@ public Set> getPrefixes() { return new LinkedHashSet<>(prefixes.keySet()); } -// public Set> getShortPrefixes() { -// return new LinkedHashSet<>(shortPrefixes); -// } - public CTLeaf getLeaf(Word u) { return prefixes.get(u); } @@ -370,9 +366,6 @@ public boolean checkLocationConsistency() { public boolean checkTransitionConsistency() { for (ShortPrefix u : getShortPrefixes()) { -// if (u.length() < 1) { -// continue; -// } for (ParameterizedSymbol action : inputs) { Set> extensions = getExtensions(u, action); for (Map.Entry, Expression> e : u.getBranching(action).getBranches().entrySet()) { @@ -382,7 +375,6 @@ public boolean checkTransitionConsistency() { if (uB.equals(uA)) { continue; } -// ParameterValuation uBVals = actionValuation(uB); Mapping mapping = new Mapping<>(); mapping.putAll(actionValuation(uB)); mapping.putAll(consts); @@ -424,7 +416,6 @@ private Optional transitionConsistentB(Word uA, SDT sdtA = pA.getSDT(v).toRegisterSDT(uA, consts); SDT sdtB = pB.getSDT(v).toRegisterSDT(uB, consts); if (!SDT.equivalentUnderId(sdtA, sdtB)) { -// if (!SDT.equivalentUnderId(pA.getSDT(v), pB.getSDT(v))) { CTLeaf uLeaf = getLeaf(uA.prefix(uA.length() - 1)); assert uLeaf != null; Register[] regs = inequivalentMapping(rpRegBijection(pA.getRpBijection(), pA), rpRegBijection(pB.getRpBijection(), pB)); @@ -493,25 +484,6 @@ public boolean checkRegisterConsistency() { } } } - - -// for (Map.Entry e : u.getPath().getSDTs().entrySet()) { -// // is u equivalent to u for v under gamma? -// SymbolicSuffix v = e.getKey(); -// SDT uSDT = e.getValue(); -// if (SDT.equivalentUnderBijection(uSDT, uSDT, gamma, solver) == null) { -// continue; -// } -// -// // is ua equivalent to ua for v under (gamma union {regs(a) -> regs(a)]) -// SDT uaSDT = ua.getSDT(v); -// if (SDT.equivalentUnderBijection(uaSDT, uaSDT, gamma, solver) == null) { -// DataValue[] regs = gamma.keySet().toArray(new DataValue[gamma.size()]); -// SymbolicSuffix av = extendSuffix(ua, v, regs); -// refine(getLeaf(u), av); -// return false; -// } -// } } } } @@ -537,7 +509,6 @@ private ParameterValuation actionValuation(Word ua) { } public Set> getExtensions(Word u, ParameterizedSymbol action) { -// assert u.length() > 0; return prefixes.keySet() .stream() .filter(w -> w.length() == u.length() + 1) diff --git a/src/main/java/de/learnlib/ralib/ct/Prefix.java b/src/main/java/de/learnlib/ralib/ct/Prefix.java index 90a36c46..db38dbb0 100644 --- a/src/main/java/de/learnlib/ralib/ct/Prefix.java +++ b/src/main/java/de/learnlib/ralib/ct/Prefix.java @@ -23,15 +23,12 @@ public class Prefix extends Word implements PrefixContainer { private final Word prefix; private Bijection rpBijection; -// private final Map sdts; private final CTPath path; -// public Prefix(Word prefix, Bijection rpBijection) { public Prefix(Word u, Bijection rpRenaming, CTPath path) { this.prefix = u instanceof Prefix ? ((Prefix) u).getPrefix() : u; this.rpBijection = rpRenaming; this.path = path; -// sdts = new LinkedHashMap<>(); } public Prefix(Word prefix, CTPath path) { @@ -40,7 +37,6 @@ public Prefix(Word prefix, CTPath path) { public Prefix(Prefix prefix, Bijection rpRenaming) { this(prefix.prefix, rpRenaming, prefix.path); -// sdts.putAll(u.sdts); } public Prefix(Prefix other) { @@ -62,14 +58,6 @@ public SDT[] getSDTs(ParameterizedSymbol ps) { return list.toArray(new SDT[list.size()]); } -// public void putSDT(SymbolicSuffix s, SDT sdt) { -// sdts.put(s, sdt); -// } - -// public Word getPrefix() { -// return prefix; -// } - public SDT getSDT(SymbolicSuffix s) { return path.getSDT(s); } @@ -92,10 +80,6 @@ public boolean equals(Object other) { return ((Prefix) other).prefix.equals(prefix); } return prefix.equals(other); -// if (!(other instanceof Prefix)) { -// return false; -// } -// return ((Prefix) other).prefix.equals(prefix); } @Override diff --git a/src/main/java/de/learnlib/ralib/data/util/RemappingIterator.java b/src/main/java/de/learnlib/ralib/data/util/RemappingIterator.java index 5089715d..d13e4525 100644 --- a/src/main/java/de/learnlib/ralib/data/util/RemappingIterator.java +++ b/src/main/java/de/learnlib/ralib/data/util/RemappingIterator.java @@ -30,7 +30,6 @@ public boolean hasNext() { } @Override -// public VarMapping next() { public Bijection next() { assert next != null : "No more permutations"; if (replace.length == 0) { diff --git a/src/main/java/de/learnlib/ralib/learning/AutomatonBuilder.java b/src/main/java/de/learnlib/ralib/learning/AutomatonBuilder.java index 6d6b79c4..670fe1bc 100644 --- a/src/main/java/de/learnlib/ralib/learning/AutomatonBuilder.java +++ b/src/main/java/de/learnlib/ralib/learning/AutomatonBuilder.java @@ -63,12 +63,6 @@ public AutomatonBuilder(Map, LocationComponent> components this.automaton = new Hypothesis(consts); } -// public AutomatonBuilder(Map, LocationComponent> components, Constants consts, DT dt) { -// this.consts = consts; -// this.components = components; -// this.automaton = new DTHyp(consts, dt); -// } - public Hypothesis toRegisterAutomaton() { LOGGER.debug(Category.EVENT, "computing hypothesis"); computeLocations(); @@ -125,9 +119,6 @@ private void computeTransition(LocationComponent dest_c, PrefixContainer r) { //this.components.get(src_id); assert src_c != null; -// if (src_c == null && automaton instanceof DTHyp) -// return; - // locations RALocation src_loc = this.locations.get(src_id); RALocation dest_loc = this.locations.get(dest_id); @@ -148,11 +139,6 @@ private void computeTransition(LocationComponent dest_c, PrefixContainer r) { ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); guard = rvv.apply(guard, src_c.getPrimePrefix().getAssignment()); - // TODO: better solution - // guard is null because r is transition from a short prefix -// if (automaton instanceof DTHyp && guard == null) -// return; - assert true; assert guard != null; @@ -162,8 +148,6 @@ private void computeTransition(LocationComponent dest_c, PrefixContainer r) { Bijection remapping = dest_c.getRemapping(r); Assignment assign = computeAssignment(r.getPrefix(), srcAssign, destAssign, remapping); - //System.out.println(assign); - // create transition Transition t = createTransition(action, guard, src_loc, dest_loc, assign); if (t != null) { diff --git a/src/main/java/de/learnlib/ralib/learning/IOAutomatonBuilder.java b/src/main/java/de/learnlib/ralib/learning/IOAutomatonBuilder.java index e102a21a..72a074b1 100644 --- a/src/main/java/de/learnlib/ralib/learning/IOAutomatonBuilder.java +++ b/src/main/java/de/learnlib/ralib/learning/IOAutomatonBuilder.java @@ -63,16 +63,6 @@ public IOAutomatonBuilder(Map, LocationComponent> componen } } -// public IOAutomatonBuilder(Map, LocationComponent> components, -// Constants consts, DT dt) { -// super(components, consts, dt); -// -// this.reverseConsts = new LinkedHashMap<>(); -// for (Entry c : consts) { -// reverseConsts.put(c.getValue().getValue(), c.getKey()); -// } -// } - @Override protected Transition createTransition(ParameterizedSymbol action, Expression guard, RALocation src_loc, RALocation dest_loc, diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java index 5645f6b2..6bfa050f 100644 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java @@ -120,7 +120,6 @@ private boolean analyzeCounterExample() { Map, LocationComponent> components = new LinkedHashMap<>(); for (CTLeaf leaf : ct.getLeaves()) { -// LeafComponent c = new LeafComponent(leaf); for (Word u : leaf.getPrefixes()) { components.put(u, leaf); } diff --git a/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java b/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java index 6429d916..9aa451b5 100644 --- a/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java +++ b/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java @@ -418,7 +418,6 @@ public DataValue instantiate(Word prefix, Expression guard, int param, ConstraintSolver solver) { Parameter p = new Parameter(ps.getPtypes()[param-1], param); -// SuffixValue sv = new SuffixValue(ps.getPtypes()[param-1], param); Set vals = DataWords.valSet(prefix, p.getDataType()); vals.addAll(vals.stream() .filter(v -> v.getDataType().equals(p.getDataType())) @@ -440,7 +439,6 @@ public DataValue instantiate(Word prefix, } private boolean tryEquality(Expression guard, Parameter p, DataValue val, ConstraintSolver solver, Constants consts) { -// SuffixValuation valuation = new SuffixValuation(); Mapping valuation = new Mapping<>(); valuation.put(p, val); valuation.putAll(consts); diff --git a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java index 6e7a2c8c..cc16e6ea 100644 --- a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java +++ b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java @@ -616,7 +616,6 @@ public DataValue instantiate(Word prefix, Expression guard, int param, ConstraintSolver solver) { Parameter p = new Parameter(ps.getPtypes()[param-1], param); -// SuffixValue sv = new SuffixValue(ps.getPtypes()[param-1], param); Set vals = DataWords.valSet(prefix, p.getDataType()); vals.addAll(vals.stream() .filter(w -> w.getDataType().equals(p.getDataType())) @@ -652,12 +651,6 @@ private boolean tryEquality(Expression guard, Parameter p, DataValue va valuation.put(p, val); return solver.isSatisfiable(guard, valuation); } -// private boolean tryEquality(Expression guard, SuffixValue sv, DataValue val, ConstraintSolver solver) { -// SuffixValuation valuation = new SuffixValuation(); -// valuation.put(sv, val); -// return solver.isSatisfiable(guard, valuation); -// } - public void useSuffixOptimization(boolean useSuffixOpt) { this.useSuffixOpt = useSuffixOpt; diff --git a/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java b/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java index 6b4cae71..2d559546 100644 --- a/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java +++ b/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java @@ -249,12 +249,9 @@ public TreeOracle createTreeOracle(RegisterAutomaton hyp) { this.rastar = new RaStar(mto, hypFactory, mlo, consts, true, actions); break; case AbstractToolWithRandomWalk.LEARNER_SLLAMBDA: -// this.rastar = new RaLambda(mto, hypFactory, mlo, consts, true, actions); -// ((RaLambda)this.rastar).setSolver(solver); this.rastar = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); break; case AbstractToolWithRandomWalk.LEARNER_RADT: -// this.rastar = new RaDT(mto, hypFactory, mlo, consts, true, actions); this.rastar = new SLCT(mto, hypFactory, mlo, consts, true, solver, actions); break; default: diff --git a/src/main/java/de/learnlib/ralib/tools/IOSimulator.java b/src/main/java/de/learnlib/ralib/tools/IOSimulator.java index 8f95ba0b..6bb4c0cf 100644 --- a/src/main/java/de/learnlib/ralib/tools/IOSimulator.java +++ b/src/main/java/de/learnlib/ralib/tools/IOSimulator.java @@ -218,12 +218,9 @@ public TreeOracle createTreeOracle(RegisterAutomaton hyp) { this.rastar = new RaStar(mto, hypFactory, mlo, consts, true, actions); break; case AbstractToolWithRandomWalk.LEARNER_SLLAMBDA: -// this.rastar = new RaLambda(mto, hypFactory, mlo, consts, true, actions); -// ((RaLambda)this.rastar).setSolver(solver); this.rastar = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); break; case AbstractToolWithRandomWalk.LEARNER_RADT: -// this.rastar = new RaDT(mto, hypFactory, mlo, consts, true, actions); this.rastar = new SLCT(mto, hypFactory, mlo, consts, true, solver, actions); break; default: diff --git a/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java b/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java index d206df9e..5ec4420e 100644 --- a/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java +++ b/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java @@ -73,23 +73,16 @@ public void testConsistencyStack() { DataValue dv0 = new DataValue(T_INT, BigDecimal.ZERO); DataValue dv1 = new DataValue(T_INT, BigDecimal.ONE); - DataValue dv2 = new DataValue(T_INT, BigDecimal.valueOf(2)); PSymbolInstance push0 = new PSymbolInstance(I_PUSH, dv0); PSymbolInstance push1 = new PSymbolInstance(I_PUSH, dv1); PSymbolInstance pop0 = new PSymbolInstance(I_POP, dv0); - PSymbolInstance pop1 = new PSymbolInstance(I_POP, dv1); Word pu0 = Word.fromSymbols(push0); - Word po0 = Word.fromSymbols(pop0); Word pu0pu1 = Word.fromSymbols(push0, push1); Word pu0po0 = Word.fromSymbols(push0, pop0); - Word pu0pu1po1 = Word.fromSymbols(push0, push1, pop1); SymbolicSuffix s1 = new SymbolicSuffix(pu0, Word.fromSymbols(push1)); - SymbolicSuffix s2 = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(push0, push1)); - SymbolicSuffix s3 = new SymbolicSuffix(pu0, Word.fromSymbols(pop0)); - SymbolicSuffix s4 = new SymbolicSuffix(pu0pu1, Word.fromSymbols(pop1, pop0)); ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, false, I_PUSH, I_POP); @@ -266,7 +259,6 @@ public void testRegisterConsistency() { DataValue dv0 = new DataValue(T_INT, BigDecimal.ZERO); DataValue dv1 = new DataValue(T_INT, BigDecimal.ONE); DataValue dv2 = new DataValue(T_INT, BigDecimal.valueOf(2)); - DataValue dv3 = new DataValue(T_INT, BigDecimal.valueOf(3)); Word b0 = Word.fromSymbols(new PSymbolInstance(BETA, dv0)); Word a0 = Word.fromSymbols(new PSymbolInstance(ALPHA, dv0)); @@ -280,10 +272,6 @@ public void testRegisterConsistency() { new PSymbolInstance(ALPHA, dv0), new PSymbolInstance(ALPHA, dv1), new PSymbolInstance(ALPHA, dv0)); - Word a0a1b2 = Word.fromSymbols( - new PSymbolInstance(ALPHA, dv0), - new PSymbolInstance(ALPHA, dv1), - new PSymbolInstance(BETA, dv2)); Word b2b1 = Word.fromSymbols( new PSymbolInstance(BETA, dv2), new PSymbolInstance(BETA, dv1)); diff --git a/src/test/java/de/learnlib/ralib/ct/CTTest.java b/src/test/java/de/learnlib/ralib/ct/CTTest.java index 8a608561..be970022 100644 --- a/src/test/java/de/learnlib/ralib/ct/CTTest.java +++ b/src/test/java/de/learnlib/ralib/ct/CTTest.java @@ -9,7 +9,6 @@ import static de.learnlib.ralib.example.stack.StackAutomatonExample.T_INT; import java.math.BigDecimal; -import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Map; @@ -17,21 +16,10 @@ import org.testng.annotations.Test; import de.learnlib.ralib.TestUtil; -import de.learnlib.ralib.automata.Assignment; -import de.learnlib.ralib.automata.InputTransition; -import de.learnlib.ralib.automata.MutableRegisterAutomaton; -import de.learnlib.ralib.automata.RALocation; import de.learnlib.ralib.automata.RegisterAutomaton; -import de.learnlib.ralib.automata.output.OutputMapping; -import de.learnlib.ralib.automata.output.OutputTransition; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; -import de.learnlib.ralib.data.SymbolicDataValue; -import de.learnlib.ralib.data.SymbolicDataValue.Parameter; -import de.learnlib.ralib.data.SymbolicDataValue.Register; -import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; -import de.learnlib.ralib.data.VarMapping; import de.learnlib.ralib.learning.Hypothesis; import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.oracles.DataWordOracle; @@ -43,18 +31,10 @@ import de.learnlib.ralib.theory.Theory; import de.learnlib.ralib.tools.theories.DoubleInequalityTheory; import de.learnlib.ralib.tools.theories.IntegerEqualityTheory; -import de.learnlib.ralib.words.OutputSymbol; import de.learnlib.ralib.words.PSymbolInstance; -import gov.nasa.jpf.constraints.api.Expression; -import gov.nasa.jpf.constraints.expressions.NumericBooleanExpression; -import gov.nasa.jpf.constraints.expressions.NumericComparator; -import gov.nasa.jpf.constraints.util.ExpressionUtil; import net.automatalib.word.Word; public class CTTest { - private final OutputSymbol YES = new OutputSymbol("yes"); - private final OutputSymbol NO = new OutputSymbol("no"); - @Test public void testStackCT() { Map teachers = new LinkedHashMap<>(); @@ -73,7 +53,6 @@ public void testStackCT() { DataValue dv0 = new DataValue(T_INT, BigDecimal.ZERO); DataValue dv1 = new DataValue(T_INT, BigDecimal.ONE); - DataValue dv2 = new DataValue(T_INT, BigDecimal.valueOf(2)); PSymbolInstance push0 = new PSymbolInstance(I_PUSH, dv0); PSymbolInstance push1 = new PSymbolInstance(I_PUSH, dv1); @@ -81,7 +60,6 @@ public void testStackCT() { PSymbolInstance pop1 = new PSymbolInstance(I_POP, dv1); Word w1 = Word.fromSymbols(push0); - Word w2 = Word.fromSymbols(pop0); Word w3 = Word.fromSymbols(push0, push1); Word w4 = Word.fromSymbols(push0, pop0); Word w5 = Word.fromSymbols(push0, push1, pop1); @@ -89,12 +67,10 @@ public void testStackCT() { SymbolicSuffix s1 = new SymbolicSuffix(w1, Word.fromSymbols(push1)); SymbolicSuffix s2 = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(push0, push1)); SymbolicSuffix s3 = new SymbolicSuffix(w1, Word.fromSymbols(pop0)); - SymbolicSuffix s4 = new SymbolicSuffix(w2, Word.fromSymbols(pop1, pop0)); ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, false, I_PUSH, I_POP); ct.sift(Word.epsilon()); -// ct.expand(Word.epsilon()); boolean consistent = ct.checkLocationClosedness(); Assert.assertFalse(consistent); Assert.assertEquals(ct.getLeaves().size(), 2); @@ -106,7 +82,6 @@ public void testStackCT() { Assert.assertTrue(consistent); ct.expand(w1); -// ct.expand(w2); Assert.assertEquals(ct.getLeaves().size(), 2); Assert.assertEquals(ct.getPrefixes().size(), 7); @@ -122,7 +97,6 @@ public void testStackCT() { Assert.assertEquals(ct.getPrefixes().size(), 9); ct.refine(ct.getLeaf(w1), s3); -// ct.sift(w4); consistent = ct.checkTransitionClosedness(); Assert.assertFalse(consistent); Assert.assertEquals(ct.getLeaves().size(), 4); @@ -130,16 +104,12 @@ public void testStackCT() { Assert.assertTrue(ct.getLeaf(Word.epsilon()).getPrefixes().contains(w4)); ct.refine(ct.getLeaf(w3), s3); -// ct.expand(w3); consistent = ct.checkTransitionClosedness(); Assert.assertFalse(consistent); Assert.assertEquals(ct.getLeaves().size(), 4); Assert.assertEquals(ct.getPrefixes().size(), 11); Assert.assertTrue(ct.getLeaf(w1).getPrefixes().contains(w5)); -// Register r1 = new Register(T_INT, 1); -// Register r2 = new Register(T_INT, 2); -// ct.refine(ct.getLeaf(w3), s4); consistent = ct.checkRegisterClosedness(); Assert.assertFalse(consistent); Assert.assertTrue(ct.getLeaf(w3).getRepresentativePrefix().getRegisters().contains(dv0)); @@ -178,20 +148,14 @@ public void testPQCT() { PSymbolInstance offer2 = new PSymbolInstance(OFFER, dv2); PSymbolInstance poll0 = new PSymbolInstance(POLL, dv0); PSymbolInstance poll1 = new PSymbolInstance(POLL, dv1); - PSymbolInstance poll2 = new PSymbolInstance(POLL, dv2); Word o1 = Word.fromSymbols(offer1); Word o1o2 = Word.fromSymbols(offer1, offer2); - Word o1o1 = Word.fromSymbols(offer1, offer1); Word o1o0 = Word.fromSymbols(offer1, offer0); Word o1p1 = Word.fromSymbols(offer1, poll1); Word o1o2p1 = Word.fromSymbols(offer1, offer2, poll1); Word o1o0p0 = Word.fromSymbols(offer1, offer0, poll0); - SymbolicSuffix s1 = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(offer1, poll1)); - SymbolicSuffix s2 = new SymbolicSuffix(o1, Word.fromSymbols(poll1)); - SymbolicSuffix s3 = new SymbolicSuffix(o1o2, Word.fromSymbols(poll1, poll2)); - ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, false, OFFER, POLL); ct.sift(Word.epsilon()); @@ -219,25 +183,6 @@ public void testPQCT() { closed = ct.checkRegisterClosedness(); Assert.assertTrue(closed); -// ct.sift(o1p1); - - -// ct.refine(ct.getLeaf(Word.epsilon()), s1); -// ct.expand(Word.epsilon()); -// Assert.assertEquals(ct.getLeaves().size(), 3); -// -// ct.expand(o1); -// Assert.assertEquals(ct.getLeaves().size(), 4); -// -// ct.refine(ct.getLeaf(o1), s2); -// ct.sift(o1p1); - -// ct.refine(ct.getLeaf(o1o1), s3); -// ct.expand(o1o1); -// ct.expand(o1o0); -// Assert.assertEquals(ct.getLeaves().size(), 5); - - CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), false, solver); Hypothesis hyp = ab.buildHypothesis(); @@ -247,140 +192,4 @@ public void testPQCT() { Assert.assertTrue(hyp.accepts(o1o2p1)); Assert.assertTrue(hyp.accepts(o1o0p0));; } - - @Test(enabled=false) - public void testCTAutomatonBuilder() { - RegisterAutomaton sul = buildTestRA(); - DataWordOracle dwOracle = new SimulatorOracle(sul); - - final Map teachers = new LinkedHashMap<>(); - teachers.put(doubleType, new DoubleInequalityTheory(doubleType)); - - Constants consts = new Constants(); - - SymbolicSuffixRestrictionBuilder restrBuilder = new SymbolicSuffixRestrictionBuilder(consts, teachers); - OptimizedSymbolicSuffixBuilder suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrBuilder); - - ConstraintSolver solver = TestUtil.getZ3Solver(); - MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( - dwOracle, teachers, consts, solver); - - DataValue dv0 = new DataValue(doubleType, BigDecimal.ZERO); - DataValue dv1 = new DataValue(doubleType, BigDecimal.ONE); - DataValue dv2 = new DataValue(doubleType, BigDecimal.valueOf(2)); - DataValue dv3 = new DataValue(doubleType, BigDecimal.valueOf(3)); - - PSymbolInstance offer0 = new PSymbolInstance(OFFER, dv0); - PSymbolInstance offer1 = new PSymbolInstance(OFFER, dv1); - PSymbolInstance offer2 = new PSymbolInstance(OFFER, dv2); - PSymbolInstance offer3 = new PSymbolInstance(OFFER, dv3); - PSymbolInstance yes = new PSymbolInstance(YES); - PSymbolInstance no = new PSymbolInstance(NO); - - Word o1 = Word.fromSymbols(offer1); - Word o1y = Word.fromSymbols(offer1, yes); - Word o1yo2 = Word.fromSymbols(offer1, yes, offer2); - Word o1yo2y = Word.fromSymbols(offer1, yes, offer2, yes); - Word o1yo2yo3 = Word.fromSymbols(offer1, yes, offer2, yes, offer3); - Word o1yo2yo2 = Word.fromSymbols(offer1, yes, offer2, yes, offer2); - Word o1yo2yo0 = Word.fromSymbols(offer1, yes, offer2, yes, offer0); - Word o1yo2yo3y = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes); - Word o1yo2yo2y = Word.fromSymbols(offer1, yes, offer2, yes, offer2, yes); - Word o1yo2yo0y = Word.fromSymbols(offer1, yes, offer2, yes, offer0, yes); - Word o1yo2yo3yo3 = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes, offer3); - Word o1yo2yo3yo2 = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes, offer2); - Word o1yo2yo3yo3y = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes, offer3, yes); - Word o1yo2yo3yo2n = Word.fromSymbols(offer1, yes, offer2, yes, offer3, yes, offer2, no); - - SymbolicSuffix sy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(yes)); - SymbolicSuffix sn = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(no)); - SymbolicSuffix so = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(offer1)); - SymbolicSuffix syoyoyoy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(yes, offer2, yes, offer3, yes, offer3, yes)); - SymbolicSuffix soyoyoy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(offer2, yes, offer3, yes, offer3, yes)); - SymbolicSuffix syoyoy = new SymbolicSuffix(Word.epsilon(), Word.fromSymbols(yes, offer3, yes, offer3, yes)); - - ClassificationTree ct = new ClassificationTree(mto, solver, restrBuilder, suffixBuilder, consts, true, OFFER, YES, NO); - - ct.sift(Word.epsilon()); - ct.refine(ct.getLeaf(Word.epsilon()), sn); - ct.refine(ct.getLeaf(Word.epsilon()), sy); - ct.refine(ct.getLeaf(Word.epsilon()), so); - ct.refine(ct.getLeaf(Word.epsilon()), syoyoyoy); - ct.expand(Word.epsilon()); - ct.refine(ct.getLeaf(Word.epsilon()), soyoyoy); - ct.expand(o1); - ct.refine(ct.getLeaf(o1), syoyoy); - ct.expand(o1y); - ct.expand(o1yo2); - ct.expand(o1yo2y); - ct.expand(o1yo2yo0); - ct.expand(o1yo2yo2); - ct.expand(o1yo2yo0y); - ct.expand(o1yo2yo2y); - - CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, new Constants(), true, solver); - Hypothesis hyp = ab.buildHypothesis(); - } - - private RegisterAutomaton buildTestRA() { - MutableRegisterAutomaton ra = new MutableRegisterAutomaton(); - - RALocation l0i = ra.addInitialState(); - RALocation l0o = ra.addState(); - RALocation l1i = ra.addState(); - RALocation l1o = ra.addState(); - RALocation l2i = ra.addState(); - RALocation l2o = ra.addState(); - RALocation l3i = ra.addState(); - RALocation l3o1 = ra.addState(); - RALocation l3o2 = ra.addState(); - - Parameter p1 = new Parameter(doubleType, 1); - Register r1 = new Register(doubleType, 1); - Register r2 = new Register(doubleType, 2); - SuffixValue s1 = new SuffixValue(doubleType, 1); - - Expression gT = ExpressionUtil.TRUE; - Expression gL = new NumericBooleanExpression(r1, NumericComparator.LE, p1); - Expression gG = new NumericBooleanExpression(r1, NumericComparator.GE, p1); - Expression gEq = new NumericBooleanExpression(r1, NumericComparator.EQ, p1); - Expression gNe = new NumericBooleanExpression(r1, NumericComparator.NE, p1); - - VarMapping storeP1 = new VarMapping<>(); - storeP1.put(r1, p1); - VarMapping storeR1 = new VarMapping<>(); - storeR1.put(r1, r1); - VarMapping storeP1R1 = new VarMapping<>(); - storeP1R1.put(r1, p1); - storeP1R1.put(r2, r1); - VarMapping storeR1P1 = new VarMapping<>(); - storeR1P1.put(r1, r1); - storeR1P1.put(r2, p1); - VarMapping storeR1R1 = new VarMapping<>(); - storeR1R1.put(r1, r1); - storeR1R1.put(r2, r2); - VarMapping emptyMapping = new VarMapping<>(); - - Assignment assP1 = new Assignment(storeP1); - Assignment assR1 = new Assignment(storeR1); - Assignment assP1R1 = new Assignment(storeP1R1); - Assignment assR1P1 = new Assignment(storeR1P1); - Assignment assR1R1 = new Assignment(storeR1R1); - Assignment assNo = new Assignment(emptyMapping); - OutputMapping om = new OutputMapping(new ArrayList<>(), new VarMapping<>()); - - ra.addTransition(l0i, OFFER, new InputTransition(gT, OFFER, l0i, l0o, assNo)); - ra.addTransition(l0o, YES, new OutputTransition(gT, om, YES, l0o, l1i, assNo)); - ra.addTransition(l1i, OFFER, new InputTransition(gT, OFFER, l1i, l1o, assP1)); - ra.addTransition(l1o, YES, new OutputTransition(gT, om, YES, l1o, l2i, assR1)); - ra.addTransition(l2i, OFFER, new InputTransition(gL, OFFER, l2i, l2o, assR1P1)); - ra.addTransition(l2i, OFFER, new InputTransition(gG, OFFER, l2i, l2o, assP1R1)); - ra.addTransition(l2o, YES, new OutputTransition(gT, om, YES, l2o, l3i, assR1R1)); - ra.addTransition(l3i, OFFER, new InputTransition(gEq, OFFER, l3i, l3o1, assR1)); - ra.addTransition(l3o1, YES, new OutputTransition(gT, om, YES, l3o1, l1i, assNo)); - ra.addTransition(l3i, OFFER, new InputTransition(gNe, OFFER, l3i, l3o2, assNo)); - ra.addTransition(l3o2, YES, new OutputTransition(gT, om, NO, l3o2, l3i, assR1R1)); - - return ra; - } } diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java index c8d95af8..6ec65bf6 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java @@ -82,7 +82,6 @@ private static RegisterAutomaton buildAutomatonWithNoOutputParams() { RALocation l1 = ra.addState(true); RALocation l2 = ra.addState(true); RALocation l3 = ra.addState(true); -// RALocation ls = ra.addState(false); // registers and parameters RegisterGenerator rgen = new RegisterGenerator(); @@ -110,30 +109,17 @@ private static RegisterAutomaton buildAutomatonWithNoOutputParams() { // initial location ra.addTransition(l0, IN, new InputTransition(trueGuard, IN, l0, l1, storeAssign)); -// ra.addTransition(l0, OK, new OutputTransition(outMapping, OK, l0, ls, noAssign)); -// ra.addTransition(l0, NOK, new OutputTransition(outMapping, NOK, l0, ls, noAssign)); // IN 0 location -// ra.addTransition(l1, IN, new InputTransition(trueGuard, IN, l1, ls, noAssign)); ra.addTransition(l1, OK, new OutputTransition(outMapping, OK, l1, l2, copyAssign)); -// ra.addTransition(l1, NOK, new OutputTransition(outMapping, NOK, l1, ls, noAssign)); // IN 0 OK location ra.addTransition(l2, IN, new InputTransition(okGuard, IN, l2, l1, copyAssign)); ra.addTransition(l2, IN, new InputTransition(nokGuard, IN, l2, l3, copyAssign)); -// ra.addTransition(l2, OK, new OutputTransition(outMapping, OK, l2, ls, noAssign)); -// ra.addTransition(l2, NOK, new OutputTransition(outMapping, NOK, l2, ls, noAssign)); // IN 0 OK in 1 location -// ra.addTransition(l3, IN, new InputTransition(trueGuard, IN, l3, ls, noAssign)); -// ra.addTransition(l3, OK, new OutputTransition(outMapping, OK, l3, ls, noAssign)); ra.addTransition(l3, NOK, new OutputTransition(outMapping, NOK, l3, l2, copyAssign)); - // sink location -// ra.addTransition(ls, IN, new InputTransition(trueGuard, IN, ls, ls, noAssign)); -// ra.addTransition(ls, OK, new OutputTransition(outMapping, OK, ls, ls, noAssign)); -// ra.addTransition(ls, NOK, new OutputTransition(outMapping, NOK, ls, ls, copyAssign)); - return ra; } @@ -185,8 +171,6 @@ private static RegisterAutomaton buildAutomatonOutputParam(boolean fresh) { ra.addTransition(l2, IN, new InputTransition(nokGuard, IN, l2, l3, copyAssign)); // IN 0 OUT fresh/0 in 1 location -// ra.addTransition(l3, IN, new InputTransition(trueGuard, IN, l3, ls, noAssign)); -// ra.addTransition(l3, OK, new OutputTransition(outMapping, OK, l3, ls, noAssign)); ra.addTransition(l3, NOK, new OutputTransition(nokOutputMapping, NOK, l3, l2, copyAssign)); return ra; @@ -219,7 +203,6 @@ public void testLearnIORAWithNoOutputParams() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, IN, OK, NOK); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, IN, OK, NOK); sllambda.learn(); @@ -267,7 +250,6 @@ public void testLearnIORAWithEqualOutputParam() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, IN, NOK, OUT); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, IN, NOK, OUT); sllambda.learn(); @@ -275,9 +257,6 @@ public void testLearnIORAWithEqualOutputParam() { RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP1: {0}", hyp); -// Word ce = Word.fromSymbols(new PSymbolInstance(IN, new DataValue(ID, 0)), -// new PSymbolInstance(OUT, new DataValue(ID, 0)), new PSymbolInstance(IN, new DataValue(ID, 1)), -// new PSymbolInstance(NOK)); Word ce = Word.fromSymbols(new PSymbolInstance(IN, new DataValue(ID, BigDecimal.ZERO)), new PSymbolInstance(OUT, new DataValue(ID, BigDecimal.ZERO)), new PSymbolInstance(IN, new DataValue(ID, BigDecimal.ONE)), new PSymbolInstance(NOK)); @@ -319,7 +298,6 @@ public void testLearnIORAWithFreshOutputParam() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, IN, NOK, OUT); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, IN, NOK, OUT); sllambda.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java index 67e11ba1..7f04608b 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java @@ -86,8 +86,6 @@ public void testLearnABPOutput() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); -// ralambda.setSolver(solver); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); IOEquivalenceTest ioEquiv = new IOEquivalenceTest( diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java index 98d37594..3f2dcaba 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java @@ -59,7 +59,6 @@ public void testLearnEcho() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda learner = new RaLambda(mto, hypFactory, mlo, consts, true, sul.getActionSymbols()); SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, sul.getActionSymbols()); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java index 96b06dd4..ff5e8a77 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java @@ -61,11 +61,8 @@ public void testLearnLogin() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, -// consts, I_LOGIN, I_LOGOUT, I_REGISTER); SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, I_LOGIN, I_LOGOUT, I_REGISTER); -// sllambda.setSolver(solver); sllambda.learn(); RegisterAutomaton hyp = sllambda.getHypothesis(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java index 2dfce1a5..e4b980ef 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java @@ -106,8 +106,6 @@ public void testLearnMixedIO() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda rastar = new RaLambda(mto, hypFactory, mlo, consts, true, actions); -// rastar.setSolver(solver); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); IORandomWalk iowalk = new IORandomWalk(random, diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java index 32acf928..3662e089 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java @@ -114,8 +114,6 @@ private Hypothesis learnPQ(long seed, Map teachers, Constants TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda rastar = new RaLambda(mto, hypFactory, mlo, -// consts, true, sul.getActionSymbols()); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, sul.getActionSymbols()); @@ -141,7 +139,6 @@ private Hypothesis learnPQ(long seed, Map teachers, Constants Hypothesis hyp = sllambda.getHypothesis(); DefaultQuery ce = iowalk.findCounterExample(hyp, null); - //System.out.println("CE: " + ce); if (ce == null) { break; } diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java index 77a979df..503a38ed 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java @@ -79,7 +79,6 @@ public void testLearnPQ() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); -// RaLambda rastar = new RaLambda(mto, hypFactory, mlo, consts, OFFER, POLL); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, false, solver, OFFER, POLL); sllambda.learn(); RegisterAutomaton hyp = sllambda.getHypothesis(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java index 3245b1d0..18b292cd 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java @@ -117,8 +117,6 @@ public void testLearnPadlock() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, true, IN); -// ralambda.setSolver(solver); SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, IN); sllambda.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java index 331f185b..01aa9fcb 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java @@ -72,8 +72,6 @@ public void testLearnPalindromeIO() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); -// ralambda.setSolver(solver); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); IOEquivalenceTest ioEquiv = new IOEquivalenceTest( @@ -101,7 +99,6 @@ public void testLearnPalindromeIO() { DefaultQuery ce = ioEquiv.findCounterExample(hyp, null); Assert.assertNull(ce); -// Assert.assertEquals(hyp.getStates().size(), 5); Assert.assertEquals(hyp.getTransitions().size(), 16); } } diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java index 2559eb4d..7efa08e0 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java @@ -65,7 +65,6 @@ public void testLearnRepeater() { SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, sul.getActionSymbols()); learner.setStatisticCounter(stats); -// learner.setSolver(solver); learner.learn(); @@ -87,7 +86,6 @@ public void testLearnRepeater() { learner.learn(); String str = stats.toString(); - // System.out.println(str); Assert.assertTrue(str.contains("Counterexamples: 1")); Assert.assertTrue(str.contains("CE max length: 6")); Assert.assertTrue(str.contains("CE Analysis: {TQ: 0, Resets: 7, Inputs: 0}")); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java index 0b21941c..aa1ebcbb 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java @@ -82,20 +82,10 @@ public void testLearnSipIO() { MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); -// for (ParameterizedSymbol ps : actions) { -// if (!DTLeaf.isInput(ps) && ps.getArity() > 0) { -//// if (ps.getArity() > 0) { -// mto.treeQuery(Word.epsilon(), new SymbolicSuffix(ps)); -// break; -// } -// } - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); -// sllambda.setSolver(solver); IOEquivalenceTest ioEquiv = new IOEquivalenceTest( model, teachers, consts, true, actions); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java index 4b7f9da3..c897a12f 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java @@ -63,12 +63,8 @@ public void testLearnStack() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); -// ralambda.setSolver(solver); SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, I_PUSH, I_POP); -// ralambda.learn(); -// RegisterAutomaton hyp = ralambda.getHypothesis(); sllambda.learn(); RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP0: {0}", hyp); @@ -118,8 +114,6 @@ public void testLearnStackSwitchedCE() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); -// ralambda.setSolver(solver); SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, I_PUSH, I_POP); sllambda.learn(); @@ -158,18 +152,8 @@ public void testLearnStackSwitchedCE() { sllambda.learn(); hyp = sllambda.getHypothesis(); -// Collection suffixes = ralambda.getDT().getSuffixes(); -// Set> suffixActions = suffixes.stream().map(s -> s.getActions()).collect(Collectors.toSet()); -// Set> expectedSuffixActions = ImmutableSet.of( -// Word.fromSymbols(), -// Word.fromSymbols(I_PUSH), -// Word.fromSymbols(I_PUSH, I_PUSH), -// Word.fromSymbols(I_POP), -// Word.fromSymbols(I_POP, I_POP)); - Assert.assertEquals(hyp.getStates().size(), 4); Assert.assertEquals(hyp.getTransitions().size(), 10); -// Assert.assertEquals(suffixActions, expectedSuffixActions); } @Test @@ -192,8 +176,6 @@ public void testLearnStackLongCE() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, consts, false, false, I_PUSH, I_POP); -// ralambda.setSolver(solver); SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, I_PUSH, I_POP); sllambda.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java index 7b48aa38..647058ec 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java @@ -91,8 +91,6 @@ public void testDistinguishingSuffixOptimization() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); -// RaLambda learner = new RaLambda(mto, hypFactory, slo, consts, false, false, A, B); -// learner.setSolver(solver); SLLambda learner = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, A, B); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestOutputSuffixes.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestOutputSuffixes.java index 48a8e886..9ec6fd49 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestOutputSuffixes.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestOutputSuffixes.java @@ -77,7 +77,6 @@ public void testSIPOutputSuffixesPresent() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaDT radt = new RaDT(mto, hypFactory, mlo, consts, true, actions); SLCT slct = new SLCT(mto, hypFactory, mlo, consts, true, solver, actions); slct.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java index 279083ab..3d9a1241 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java @@ -57,8 +57,6 @@ public void testQueryCount() { -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); QueryStatistics queryStats = new QueryStatistics(measurements, ioOracle); -// RaLambda learner = new RaLambda(mto, hypFactory, mlo, -// consts, true, sul.getActionSymbols()); SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, sul.getActionSymbols()); learner.setStatisticCounter(queryStats); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java index 500bdae9..849daf29 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java @@ -74,10 +74,8 @@ public void testLearnRepeaterSuffixOpt() { Measurements measurements = new Measurements(); QueryStatistics stats = new QueryStatistics(measurements, sul); -// RaLambda learner = new RaLambda(mto, hypFactory, mlo, consts, true, sul.getActionSymbols()); SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, sul.getActionSymbols()); learner.setStatisticCounter(stats); -// learner.setSolver(solver); learner.learn(); @@ -126,8 +124,6 @@ public void testLearnPQSuffixOpt() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); -// RaLambda learner = new RaLambda(mto, hypFactory, mlo, consts, OFFER, POLL); -// learner.setSolver(solver); SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, false, solver, OFFER, POLL); learner.setStatisticCounter(stats); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java index acd558c8..984f2695 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java @@ -203,8 +203,6 @@ public void testLearnSymmetryExampleCT1() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); -// RaLambda learner = new RaLambda(mto, hypFactory, slo, consts, false, false, A, B); -// learner.setSolver(solver); SLLambda learner = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, A, B); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java index e0fe8b3d..b69be264 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java @@ -193,8 +193,6 @@ public void testUnknownMemorable() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); -// ralambda.setSolver(solver); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); sllambda.learn(); @@ -267,8 +265,6 @@ public void testSkippingMemorable() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); -// ralambda.setSolver(solver); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); sllambda.learn(); @@ -327,8 +323,6 @@ public void testSkippingMemorable2() { TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, mlo, consts, true, actions); -// ralambda.setSolver(solver); SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); sllambda.learn(); From acf70bd19863e44f140832f034633f344048ef55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Tue, 11 Nov 2025 14:39:02 +0100 Subject: [PATCH 15/31] improve readability with code reorganization and documentation/comments --- .../ralib/ceanalysis/PrefixFinder.java | 200 ++++-- .../learnlib/ralib/ct/CTAutomatonBuilder.java | 31 +- .../java/de/learnlib/ralib/ct/CTBranch.java | 26 +- .../de/learnlib/ralib/ct/CTHypothesis.java | 24 + .../de/learnlib/ralib/ct/CTInnerNode.java | 33 +- .../java/de/learnlib/ralib/ct/CTLeaf.java | 76 ++- .../java/de/learnlib/ralib/ct/CTNode.java | 31 + .../java/de/learnlib/ralib/ct/CTPath.java | 35 + .../learnlib/ralib/ct/ClassificationTree.java | 596 ++++++++++++------ .../de/learnlib/ralib/ct/MemorableSet.java | 5 + .../java/de/learnlib/ralib/ct/Prefix.java | 13 + .../de/learnlib/ralib/ct/ShortPrefix.java | 15 +- .../de/learnlib/ralib/oracles/Branching.java | 14 + .../java/de/learnlib/ralib/theory/Theory.java | 18 +- .../ralib/theory/equality/EqualityTheory.java | 6 +- .../inequality/InequalityTheoryWithEq.java | 6 +- .../theories/UniqueIntegerEqualityTheory.java | 5 +- 17 files changed, 869 insertions(+), 265 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java index 42a41058..a35be0fc 100644 --- a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java +++ b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java @@ -39,6 +39,11 @@ import gov.nasa.jpf.constraints.util.ExpressionUtil; import net.automatalib.word.Word; +/** + * Analyzes counterexamples according to the SLλ algorithm. + * + * @author fredrik + */ public class PrefixFinder { public enum ResultType { @@ -46,6 +51,9 @@ public enum ResultType { LOCATION } + /** + * Container for the result of a counterexample analysis + */ public record Result(Word prefix, ResultType result) {}; private final CTHypothesis hyp; @@ -72,13 +80,21 @@ public PrefixFinder(TreeOracle sulOracle, CTHypothesis hyp, ClassificationTree c this.consts = consts; } + /** + * Analyze counterexample {@code ce} from right to leaf to find a transition or + * location discrepancy. If a discrepancy is found, returns the prefix which reveals + * the discrepancy, along with a {@code ResultType} indicating the type of discrepancy. + * + * @param ce + * @return + */ public Result analyzeCounterExample(Word ce) { RARun run = hyp.getRun(ce); for (int i = ce.length(); i >= 1; i--) { RALocation loc = run.getLocation(i-1); RALocation locNext = run.getLocation(i); PSymbolInstance symbol = run.getTransition(i); - RegisterValuation mu = run.getValuation(i-1); + RegisterValuation runValuation = run.getValuation(i-1); ParameterizedSymbol action = symbol.getBaseSymbol(); SymbolicSuffix vNext = new SymbolicSuffix(ce.prefix(i), ce.suffix(ce.length() - i), restrBuilder); @@ -90,13 +106,15 @@ public Result analyzeCounterExample(Word ce) { for (ShortPrefix u : hyp.getLeaf(loc).getShortPrefixes()) { SDT sdt = sulOracle.treeQuery(u, v); + Set uVals = hyp.getLeaf(loc).getPrefix(u).getRegisters(); - Mapping muRenaming = valuationRenaming(u, mu); - Set> renamings = extendedValuationRenamings(sdt, uVals, run, i); + Mapping uToRunRenaming = valuationRenaming(u, runValuation); + Set> uToRunExtendedRenamings = extendedValuationRenamings(sdt, uVals, run, i); + Branching branching = sulOracle.getInitialBranching(u, action, sdt); for (Expression gSul : branching.guardSet()) { - for (Mapping renaming : renamings) { - renaming.putAll(muRenaming); + for (Mapping renaming : uToRunExtendedRenamings) { + renaming.putAll(uToRunRenaming); if (isGuardSatisfied(gSul, renaming, symbol)) { Optional res = checkTransition(locNext, u, action, vNext, gHyp, gSul); if (res.isEmpty()) { @@ -114,12 +132,16 @@ public Result analyzeCounterExample(Word ce) { throw new IllegalStateException("Found no counterexample in " + ce); } - /* - * Generate a mapping from the register valuation of u on the hypothesis to val + /** + * @param u + * @param val + * @return a mapping from the register valuation of {@code u} on the hypothesis to the {@code val} */ private Mapping valuationRenaming(Word u, RegisterValuation val) { + // get register mapping for u when run over the hypothesis RARun uRun = hyp.getRun(u); RegisterValuation uVal = uRun.getValuation(u.size()); + // create mapping from u's valuation to val Mapping ret = new Mapping<>(); for (Map.Entry e : uVal.entrySet()) { DataValue replace = e.getValue(); @@ -132,31 +154,57 @@ private Mapping valuationRenaming(Word u, return ret; } - private Set> extendedValuationRenamings(SDT uSDT, Set uValuation, RARun run, int id) { - Set> identity = new LinkedHashSet<>(); - identity.add(new Mapping<>()); - if (id <= 1) { - return identity; + /** + * Create extensions of the valuation from the hypothesis at index {@code id}, and map + * data values from {@code uSDT} to these extended valuations. + * The returned remappings do not include parameters present in the valuation at {@code id} + * (which should be mapped to parameters in {@code uVals}, except for duplicate parameters. + * For example, if the parameters of {@code run} at index {@code id} contain the data values + * 5,5,7 and the valuation contains 5, then the 7 and a single 5 will be considered for the + * extension of the valuation. Similarly, if {@code uSDT} has data values 0,1,2 with 0 in + * {@code uValuation}, then 1,2 will be considered. In this example, this method would + * return the mappings {1->5, 2->7} and {1->7, 2->5}. + * + * @param uSDT sdt for prefix {@code u} + * @param uVals memorable data values of {@code u} + * @param run + * @param id + * @return + */ + private Set> extendedValuationRenamings(SDT uSDT, Set uVals, RARun run, int id) { + Set> empty = new LinkedHashSet<>(); + empty.add(new Mapping<>()); + if (id < 1) { + return empty; } + + // gather data values from uSDT, and remove values from uValuation Set sdtVals = new LinkedHashSet<>(uSDT.getDataValues()); - for (DataValue d : uValuation) { + for (DataValue d : uVals) { sdtVals.remove(d); } if (sdtVals.isEmpty()) { - return identity; + return empty; } DataValue[] sdtValsArr = sdtVals.toArray(new DataValue[sdtVals.size()]); + // gather data values from prefix of run at index id ArrayList runVals = new ArrayList<>(); for (int i = 1; i <= id-1; i++) { for (DataValue d : run.getTransition(i).getParameterValues()) { runVals.add(d); } } + + /* remove data values from valuation. + * may have multiple copies of same data value, which may be mapped to different + * data values in uSDT, so only remove one instance of data values in valuation + */ for (DataValue d : run.getValuation(id-1).values()) { runVals = removeFirst(runVals, d); } + // compute all possible permutations of mappings between extended uSDT values and run values Set> renamings = new LinkedHashSet<>(); PermutationIterator permit = new PermutationIterator(runVals.size()); for (int[] order : permit) { @@ -179,6 +227,11 @@ private Set> extendedValuationRenamings(SDT uSDT, return renamings; } + /** + * @param list + * @param d + * @return array containing data values of {@code list}, with one occurrence of {@code d} removed + */ private ArrayList removeFirst(ArrayList list, DataValue d) { ArrayList ret = new ArrayList<>(); ret.addAll(list); @@ -191,71 +244,98 @@ private ArrayList removeFirst(ArrayList list, DataValue d) return ret; } - private Optional checkTransition(RALocation loc_i, + /** + * Check for a transition discrepancy. This is done by checking whether there exists no + * {@code action}-extension of {@code u} in the leaf of {@code loc} that is equivalent + * to the {@code (hypGuard && sulGuard)} extension of {@code u} after {@code v}. + * + * @param loc the source location + * @param u short prefix from leaf of {@code loc} + * @param action the symbol of the next transition + * @param v the suffix after {@code u} and {@code action} + * @param hypGuard guard of {@code action} after {@code u} on the hypothesis + * @param sulGuard guard of {@code action} after {@code u} on the SUL + * @return an {@code Optional} containing the result if there is a transition discrepancy, or an empty {@code Optional} otherwise + */ + private Optional checkTransition(RALocation loc, ShortPrefix u, ParameterizedSymbol action, - SymbolicSuffix vi, - Expression gi, - Expression giPrime) { + SymbolicSuffix v, + Expression hypGuard, + Expression sulGuard) { + // rename hyp guard to match RP ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); - Expression giRenamed = rvv.apply(gi, u.getRpBijection().inverse().toVarMapping()); - Expression con = ExpressionUtil.and(giRenamed, giPrime); + Expression hypGuardRenamed = rvv.apply(hypGuard, u.getRpBijection().inverse().toVarMapping()); + Expression conjunction = ExpressionUtil.and(hypGuardRenamed, sulGuard); + // instantiate a representative data value for the conjunction DataType[] types = action.getPtypes(); DataValue[] reprDataVals = new DataValue[types.length]; - Set prior = new LinkedHashSet<>(); for (int i = 0; i < types.length; i++) { - reprDataVals[i] = teachers.get(types[i]).instantiate(u, action, prior, consts, con, i+1, solver); - prior.add(reprDataVals[i]); + reprDataVals[i] = teachers.get(types[i]).instantiate(u, action, conjunction, i+1, consts, solver); } PSymbolInstance psi = new PSymbolInstance(action, reprDataVals); Word uExtSul = u.append(psi); - CTLeaf leaf_i = hyp.getLeaf(loc_i); + // check whether leaf of loc contains an extension of u that is equivalent to uExtSul after v + CTLeaf leaf = hyp.getLeaf(loc); Iterator> extensions = ct.getExtensions(u, action) .stream() - .filter(w -> leaf_i.getPrefixes().contains(w)) + .filter(w -> leaf.getPrefixes().contains(w)) .iterator(); while (extensions.hasNext()) { Word uExtHyp = extensions.next(); // u_{i-1}\alpha_i(d_i') - SDT uExtHypSDT = sulOracle.treeQuery(uExtHyp, vi).toRegisterSDT(uExtHyp, consts); - SDT uExtSulSDT = sulOracle.treeQuery(uExtSul, vi).toRegisterSDT(uExtSul, consts); + SDT uExtHypSDT = sulOracle.treeQuery(uExtHyp, v).toRegisterSDT(uExtHyp, consts); + SDT uExtSulSDT = sulOracle.treeQuery(uExtSul, v).toRegisterSDT(uExtSul, consts); if (SDT.equivalentUnderId(uExtHypSDT, uExtSulSDT)) { - return Optional.empty(); + return Optional.empty(); // there is an equivalent extension, so no discrepancy } } + // no equivalent extension exists Result res = new Result(uExtSul, ResultType.TRANSITION); return Optional.of(res); } - private Optional checkLocation(RALocation loc_i, + /** + * Check for a location discrepancy. This is done by checking whether there is some + * {@code action}-extension of {@code u} in the leaf of {@code locNext} such that there + * does not exist some short prefix in the leaf of {@code locNext} that is equivalent + * to the {@code action}-extension of {@code u} after {@code v}. + * + * @param locNext the destination location + * @param u short prefix in leaf prior to {@code locNext} in the run + * @param action the symbol of the next transition + * @param v the suffix after {@code u} and {@code action} + * @return an {@code Optional} containing the result if there is a location discrepancy, or an empty {@code Optional} otherwise + */ + private Optional checkLocation(RALocation locNext, Word u, ParameterizedSymbol action, - SymbolicSuffix vi) { - CTLeaf leaf_i = hyp.getLeaf(loc_i); + SymbolicSuffix v) { + CTLeaf leafNext = hyp.getLeaf(locNext); Iterator extensions = ct.getExtensions(u, action) .stream() - .filter(w -> leaf_i.getPrefixes().contains(w)) - .map(w -> leaf_i.getPrefix(w)) + .filter(w -> leafNext.getPrefixes().contains(w)) + .map(w -> leafNext.getPrefix(w)) .iterator(); while (extensions.hasNext()) { - Prefix uExt = extensions.next(); - Bijection uExtBi = uExt.getRpBijection(); - boolean noEquivUi = true; - for (Prefix ui : leaf_i.getShortPrefixes()) { - Bijection uiBi = ui.getRpBijection(); - Bijection gamma = uiBi.compose(uExtBi.inverse()); - SDT uExtSDT = sulOracle.treeQuery(uExt, vi); - SDT uiSDT = sulOracle.treeQuery(ui, vi); - if (SDT.equivalentUnderBijection(uiSDT, uExtSDT, gamma) != null) { - noEquivUi = false; + Prefix uExtended = extensions.next(); + Bijection uExtBijection = uExtended.getRpBijection(); + boolean noEquivU = true; + for (Prefix uNext : leafNext.getShortPrefixes()) { + Bijection uNextBijection = uNext.getRpBijection(); + Bijection gamma = uNextBijection.compose(uExtBijection.inverse()); + SDT uExtSDT = sulOracle.treeQuery(uExtended, v); + SDT uNextSDT = sulOracle.treeQuery(uNext, v); + if (SDT.equivalentUnderBijection(uNextSDT, uExtSDT, gamma) != null) { + noEquivU = false; break; } } - if (noEquivUi) { - Result res = new Result(uExt, ResultType.LOCATION); + if (noEquivU) { + Result res = new Result(uExtended, ResultType.LOCATION); return Optional.of(res); } } @@ -263,18 +343,25 @@ private Optional checkLocation(RALocation loc_i, return Optional.empty(); } + /** + * Get the guard in the hypothesis corresponding to {@code run} at index {@code idx} + * + * @param run + * @param idx + * @return + */ private Optional> getHypGuard(RARun run, int idx) { RALocation locNext = run.getLocation(idx); RALocation loc = run.getLocation(idx - 1); CTLeaf leafNext = hyp.getLeaf(locNext); - RegisterValuation mu = run.getValuation(idx-1); - PSymbolInstance a = run.getTransition(idx); - ShortPrefix sp = hyp.getLeaf(loc).getShortPrefixes().iterator().next(); - Mapping renaming = valuationRenaming(sp, mu); - for (Word ua : ct.getExtensions(sp, a.getBaseSymbol())) { + RegisterValuation hypValuation = run.getValuation(idx-1); + PSymbolInstance action = run.getTransition(idx); + ShortPrefix u = hyp.getLeaf(loc).getShortPrefixes().iterator().next(); + Mapping renaming = valuationRenaming(u, hypValuation); + for (Word ua : ct.getExtensions(u, action.getBaseSymbol())) { if (leafNext.getPrefixes().contains(ua)) { - for (Expression g : sp.getBranching(a.getBaseSymbol()).getBranches().values()) { - if (isGuardSatisfied(g, renaming, a)) { + for (Expression g : u.getBranching(action.getBaseSymbol()).getBranches().values()) { + if (isGuardSatisfied(g, renaming, action)) { return Optional.of(g); } } @@ -283,6 +370,15 @@ private Optional> getHypGuard(RARun run, int idx) { return Optional.empty(); } + /** + * Check whether {@code guard} is satisfied by the parameters of {@code symbol}, after renaming + * the parameters of {@code guard} according to {@code renaming}. + * + * @param guard + * @param renaming + * @param symbol + * @return {@code true} if {@code symbol} satisfies {@code guard}, renamed according to {@code renaming} + */ private boolean isGuardSatisfied(Expression guard, Mapping renaming, PSymbolInstance symbol) { Mapping mapping = new Mapping<>(); DataValue[] vals = symbol.getParameterValues(); diff --git a/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java index a2f8dc0b..f89f2028 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java +++ b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java @@ -15,6 +15,7 @@ import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.Mapping; import de.learnlib.ralib.data.ParameterValuation; import de.learnlib.ralib.data.RegisterAssignment; import de.learnlib.ralib.data.SymbolicDataValue; @@ -37,21 +38,37 @@ import gov.nasa.jpf.constraints.util.ExpressionUtil; import net.automatalib.word.Word; +/** + * Builder class for building a {@link CTHypothesis} from a {@link ClassificationTree}. + * This class implements similar functionality as {@link AutomatonBuilder} and {@link IOAutomatonBuilder}, + * but tailored for the {@link SLLambda} and {@link SLCT} learning algorithms. + * + * {@code CTAutomatonBuilder} supports construction of automata from an incomplete classification tree, + * so long as the classification tree is closed and consistent. + * Multiple short prefixes in the same leaf, as well as one-symbol extensions without matching guards, + * will be ignored during construction. + * The access sequence for each location will be set to the representative prefix of the corresponding leaf. + * + * @author fredrik + */ public class CTAutomatonBuilder { private final ClassificationTree ct; - private final Map, RALocation> locations; + private final Map, RALocation> locations; // to keep track of which prefix maps to which location private final Map leaves; private final CTHypothesis hyp; private final ConstraintSolver solver; + + private final Constants consts; private boolean ioMode; public CTAutomatonBuilder(ClassificationTree ct, Constants consts, boolean ioMode, ConstraintSolver solver) { this.ct = ct; + this.consts = consts; this.ioMode = ioMode; this.solver = solver; @@ -72,6 +89,7 @@ public CTHypothesis buildHypothesis() { } private void computeLocations() { + // compute initial location CTLeaf initial = ct.getLeaf(RaStar.EMPTY_PREFIX); RALocation l0 = hyp.addInitialState(initial.isAccepting()); locations.put(RaStar.EMPTY_PREFIX, l0); @@ -81,6 +99,7 @@ private void computeLocations() { hyp.setAccessSequence(l0, RaStar.EMPTY_PREFIX); leaves.put(initial, l0); + // compute non-initial locations for (CTLeaf leaf : ct.getLeaves()) { if (leaf != initial) { RALocation l = hyp.addState(leaf.isAccepting()); @@ -104,6 +123,7 @@ private void computeTransitions() { private void computeTransition(CTLeaf dest_l, Prefix prefix) { if (prefix.length() < 1) { + // empty prefix has no transition return; } @@ -131,14 +151,16 @@ private void computeTransition(CTLeaf dest_l, Prefix prefix) { Branching b = src_u.getBranching(action); Expression guard = b.getBranches().get(prefix); + // prefix may not yet have a guard if ct is incomplete, so find a corresponding guard if (guard == null) { for (Expression g : b.getBranches().values()) { DataValue[] vals = prefix.lastSymbol().getParameterValues(); - ParameterValuation pars = new ParameterValuation(); + Mapping pars = new Mapping<>(); for (int i = 0; i < vals.length; i++) { Parameter p = new Parameter(vals[i].getDataType(), i+1); pars.put(p, vals[i]); } + pars.putAll(consts); if (solver.isSatisfiable(g, pars)) { guard = g; break; @@ -154,12 +176,14 @@ private void computeTransition(CTLeaf dest_l, Prefix prefix) { } } + // rename guard to use register mapping of predecessor prefix ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); RegisterAssignment srcAssign = src_u.getAssignment(); RegisterAssignment rpAssign = src_l.getRepresentativePrefix().getAssignment(); RegisterAssignment srcAssignRemapped = srcAssign.relabel(registerRemapping(srcAssign, rpAssign, src_u.getRpBijection())); guard = rvv.apply(guard, srcAssignRemapped); + // compute register assignment RegisterAssignment destAssign = dest_rp.getAssignment(); Bijection remapping = prefix.getRpBijection(); Assignment assign = AutomatonBuilder.computeAssignment(prefix, srcAssignRemapped, destAssign, remapping); @@ -179,9 +203,12 @@ private Transition createTransition(ParameterizedSymbol action, Expression expr = guard; VarMapping outmap = new VarMapping<>(); diff --git a/src/main/java/de/learnlib/ralib/ct/CTBranch.java b/src/main/java/de/learnlib/ralib/ct/CTBranch.java index 4e6299f4..4d422750 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTBranch.java +++ b/src/main/java/de/learnlib/ralib/ct/CTBranch.java @@ -7,6 +7,16 @@ import de.learnlib.ralib.data.util.RemappingIterator; import de.learnlib.ralib.smt.ConstraintSolver; +/** + * Branch forming an edge between two nodes in a {@link ClassificationTree}. + * The branch is labeled by the representative path of the first prefix which + * was sifted through the branch. + * + * @author fredrik + * + * @see CTNode + * @see CTPath + */ public class CTBranch { private final CTNode child; @@ -17,7 +27,7 @@ public CTBranch(CTPath path, CTNode child) { this.child = child; } - public CTPath getPath() { + public CTPath getRepresentativePath() { return reprPath; } @@ -25,6 +35,16 @@ public CTNode getChild() { return child; } + /** + * Check whether the SDTs of {@code other} are equivalent to the SDTs of {@code this}. + * under the same {@link Bijection}. If so, returns the {@code Bijection} under which the {@code SDT}s + * are equivalent. + * + * @param other the path to compare for equivalence + * @param solver constraint solver to use when comparing for equivalence + * @return {@code Bijection} under which the {@code SDT}s of {@code other} are equivalent to those of {@code this}, or {@code null} if the {@code SDT}s are not equivalent. + * @see SDT + */ public Bijection matches(CTPath other, ConstraintSolver solver) { if (!reprPath.typeSizesMatch(other)) { return null; @@ -44,10 +64,6 @@ public Bijection matches(CTPath other, ConstraintSolver solver) { return null; } - public CTPath getRepresentativePath() { - return reprPath; - } - @Override public String toString() { return child.toString(); diff --git a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java index 12c88b7b..68608a60 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java +++ b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java @@ -21,6 +21,14 @@ import de.learnlib.ralib.words.ParameterizedSymbol; import net.automatalib.word.Word; +/** + * Hypothesis constructed from a {@link ClassificationTree}. Maintains a mapping between + * locations in the hypothesis and leaf nodes of the {@code ClassificationTree} from which the + * hypothesis was constructed. + * + * @author fredrik + * @see Hypothesis + */ public class CTHypothesis extends Hypothesis { private final BiMap leaves; @@ -57,10 +65,25 @@ public RALocation getSink() { return super.getSuccessor(state, input); } + /** + * Get location corresponding to {@code leaf}. + * + * @param leaf + * @return {@link RALocation} corresponding to {@code leaf} + */ public RALocation getLocation(CTLeaf leaf) { return leaves.get(leaf); } + /** + * Get leaf node of {@link ClassificationTree} from which this hypothesis was constructed. + * which corresponds to {@code location}. + * + * @param location + * @return leaf node corresponding to {@code location} + * @see CTLeaf + * @see RALocation + */ public CTLeaf getLeaf(RALocation location) { return leaves.inverse().get(location); } @@ -98,6 +121,7 @@ public RARun getRun(Word word) { } if (!found) { + // in IO automata, invalid sequences go to sink if (ioMode) { if ((symbols[i].getBaseSymbol() instanceof OutputSymbol && (output || candidates.isEmpty())) || locs[i].equals(sink)) { diff --git a/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java index c107d8b6..d904b458 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java +++ b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java @@ -16,6 +16,14 @@ import de.learnlib.ralib.words.ParameterizedSymbol; import net.automatalib.word.Word; +/** + * Inner node of a {@link ClassificationTree}, containing a {@link SymbolicSuffix}. + * Maintains a set of branches to child nodes. + * + * @author fredrik + * @see CTBranch + * @see CTNode + */ public class CTInnerNode extends CTNode { private final SymbolicSuffix suffix; private final List branches; @@ -47,6 +55,7 @@ protected CTBranch getBranch(CTNode child) { protected CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, boolean ioMode) { CTPath path = CTPath.computePath(oracle, prefix, getSuffixes(), ioMode); + // find a matching branch and sift to child for (CTBranch b : branches) { Bijection vars = b.matches(path, solver); if (vars != null) { @@ -63,6 +72,20 @@ protected CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, return leaf; } + /** + * Replace {@code leaf} with a new {@link CTInnerNode} containing {@code suffix}. + * The prefixes in {@code leaf} will be sifted into this new inner node. + * If this sifting creates a new {@link CTLeaf}, the first prefix to be sifted + * into that leaf node will be made the representative prefix. + * + * @param leaf + * @param suffix + * @param oracle + * @param solver + * @param ioMode + * @param inputs + * @return a mapping of prefixes in {@code leaf} to their new leaf nodes + */ protected Map, CTLeaf> refine(CTLeaf leaf, SymbolicSuffix suffix, TreeOracle oracle, ConstraintSolver solver, boolean ioMode, ParameterizedSymbol[] inputs) { CTBranch b = getBranch(leaf); assert b != null : "Node is not the parent of leaf " + leaf; @@ -70,15 +93,18 @@ protected Map, CTLeaf> refine(CTLeaf leaf, SymbolicSuffix Set shorts = leaf.getShortPrefixes(); + // replace leaf with a new inner node, with same path as leaf CTInnerNode newNode = new CTInnerNode(this, suffix); - CTBranch newBranch = new CTBranch(b.getPath(), newNode); + CTBranch newBranch = new CTBranch(b.getRepresentativePath(), newNode); branches.remove(b); branches.add(newBranch); + // sift leaf's RP into the new inner node Map, CTLeaf> leaves = new LinkedHashMap<>(); CTLeaf l = sift(leaf.getRepresentativePrefix(), oracle, solver, ioMode); leaves.put(leaf.getRepresentativePrefix(), l); + // resift leaf's prefixes into this node (except the RP, which was already sifted) Set prefixes = new LinkedHashSet<>(leaf.getPrefixes()); prefixes.remove(leaf.getRepresentativePrefix()); @@ -86,6 +112,8 @@ protected Map, CTLeaf> refine(CTLeaf leaf, SymbolicSuffix l = sift(u, oracle, solver, ioMode); leaves.put(u, l); } + + // make sure all short prefixes of leaf are still short for (ShortPrefix u : shorts) { if (!(u instanceof ShortPrefix)) { leaves.get(u).elevatePrefix(u, oracle, inputs); @@ -107,6 +135,9 @@ public List getSuffixes() { return suffixes; } + /** + * @return {@code false} + */ @Override public boolean isLeaf() { return false; diff --git a/src/main/java/de/learnlib/ralib/ct/CTLeaf.java b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java index 2e23df87..c48bba80 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTLeaf.java +++ b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java @@ -18,6 +18,15 @@ import de.learnlib.ralib.words.ParameterizedSymbol; import net.automatalib.word.Word; +/** + * Leaf node of a {@link ClassificationTree}, containing a number of prefixes. + * A leaf node must contain at least one prefix, which is the representative + * prefix of the leaf. Any number of prefixes may also be short prefixes. + * + * @author fredrik + * @see Prefix + * @see ShortPrefix + */ public class CTLeaf extends CTNode implements LocationComponent { private Prefix rp; private final Set shortPrefixes; @@ -42,10 +51,19 @@ public List getSuffixes() { return getParent().getSuffixes(); } + /** + * @return all prefixes contained within this leaf + */ public Set getPrefixes() { return prefixes; } + /** + * Helper method for retrieving the {@link Prefix} representation of a {@code Word}. + * + * @param u + * @return the {@code Prefix} form of {@code u} if {@code u} is in this leaf, or {@code null} otherwise + */ public Prefix getPrefix(Word u) { for (Prefix p : prefixes) { if (p.equals(u)) { @@ -55,23 +73,49 @@ public Prefix getPrefix(Word u) { return null; } + /** + * @return all short prefixes in this leaf + */ public Set getShortPrefixes() { return shortPrefixes; } + /** + * @return the representative prefix of this leaf + */ public Prefix getRepresentativePrefix() { return rp; } + /** + * @return {@code true} + */ @Override public boolean isLeaf() { return true; } + /** + * Returns {@code true} if this leaf is accepting, i.e., if a tree query for this + * leaf's representative prefix with the empty suffix (ε) is accepting. + * + * @return {@code true} if this leaf corresponds to an accepting location + */ public boolean isAccepting() { return rp.getPath().isAccepting(); } + /** + * Adds {@code prefix} to this leaf. If {@code prefix} is a short prefix, this method updates + * the branching of {@code prefix} to include initial guards from the conjunction of all SDTs + * along its path. + * + * @param prefix that will be added to this leaf + * @param oracle unused + * @param solver unused + * @param ioMode unused + * @return {@code this} + */ @Override protected CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, boolean ioMode) { prefixes.add(prefix); @@ -83,6 +127,19 @@ protected CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, return this; } + /** + * Elevate {@code u} to a short prefix by converting it to a {@link ShortPrefix}. The branching + * of {@code u} will be initialized to reflect the initial guards of the conjunction of SDTs + * along its path. + * + * @param u the prefix to elevate + * @param oracle tree oracle to use for updating the branching + * @param inputs all input symbols + * @return {@code u} as a {@code ShortPrefix} + * @see Branching + * @see SDT + * @see CTPath + */ protected ShortPrefix elevatePrefix(Word u, TreeOracle oracle, ParameterizedSymbol ... inputs) { Prefix prefix = getPrefix(u); assert !(prefix instanceof ShortPrefix) : "Prefix is already short: " + prefix; @@ -108,6 +165,9 @@ public String toString() { return str + "}"; } + /** + * @return this leaf's representative prefix + */ @Override public Word getAccessSequence() { return getRepresentativePrefix(); @@ -119,17 +179,31 @@ public Bijection getRemapping(PrefixContainer r) { return ((Prefix) r).getRpBijection(); } + /** + * Get the branching for symbol {@code action} of the representative prefix. + * Requires that the representative prefix is a {@link ShortPrefix}. + * + * @param action + * @return {@code Branching} of {@code action} for the representative prefix of this leaf + */ @Override public Branching getBranching(ParameterizedSymbol action) { + // FIXME: should get branching from a short prefix if representative prefix is not short assert rp instanceof ShortPrefix : "Representative prefix is not a short prefix"; return ((ShortPrefix) rp).getBranching(action); } + /** + * @return the representative prefix of this leaf + */ @Override public PrefixContainer getPrimePrefix() { - return rp; + return getRepresentativePrefix(); } + /** + * @return {@code Collection} of all prefixes in this leaf other than the representative prefix + */ @Override public Collection getOtherPrefixes() { Collection prefs = new LinkedList<>(); diff --git a/src/main/java/de/learnlib/ralib/ct/CTNode.java b/src/main/java/de/learnlib/ralib/ct/CTNode.java index 1f1be9ad..bddafdce 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTNode.java +++ b/src/main/java/de/learnlib/ralib/ct/CTNode.java @@ -6,6 +6,11 @@ import de.learnlib.ralib.oracles.TreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; +/** + * Node of a {@link ClassificationTree}. + * + * @author fredrik + */ public abstract class CTNode { private final CTNode parent; @@ -13,13 +18,39 @@ public CTNode(CTNode parent) { this.parent = parent; } + /** + * + * @return immediate ancestor of this node + */ public CTNode getParent() { return parent; } + /** + * @return all symbolic suffixes from all the ancestor nodes. + */ public abstract List getSuffixes(); + /** + * + * @return {@code true} if this node is a {@link CTLeaf} + */ public abstract boolean isLeaf(); + /** + * Sifts {@code prefix} into the node. If this is a {@link CTLeaf}, adds {@code prefix} to it. + * If this is a {@link CTInnerNode}, a tree query is made for {@code prefix} with the node's + * {@link SymbolicSuffix}, after which {@code prefix} is sifted to the child whose path + * matches the tree query, determined with a call to {@link CTBranch#matches(CTPath, ConstraintSolver)}. + * If no such child exists, this method creates a new {@code CTLeaf} and adds {@code prefix} + * to it as its representative prefix. + * + * @param prefix the prefix to sift through this node + * @param oracle the {@link TreeOracle} to use when making tree queries + * @param solver the {@link ConstraintSolver} to use for comparing paths for equivalence + * @param ioMode {@code true} if using IO mode + * @return the {@code CTLeaf} node to which {@code prefix} is sifted + * @see CTPath + */ protected abstract CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, boolean ioMode); } diff --git a/src/main/java/de/learnlib/ralib/ct/CTPath.java b/src/main/java/de/learnlib/ralib/ct/CTPath.java index 3bbe926c..03bb61f2 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTPath.java +++ b/src/main/java/de/learnlib/ralib/ct/CTPath.java @@ -14,6 +14,15 @@ import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.SDT; +/** + * This data structure stores the SDTs from tree queries for a prefix along a path + * in a {@link ClassificationTree}. It contains much of the same functionality as + * {@link Row}, but adapted for use with classification trees. + * + * @author fredrik + * @author falk + * @see Row + */ public class CTPath { private final Map sdts; private final MemorableSet memorable; @@ -49,6 +58,14 @@ public boolean isAccepting() { return s.isAccepting(); } + /** + * Checks whether two paths are equivalent under {@code renaming}. + * + * @param other + * @param renaming + * @param solver + * @return {@code true} if the SDTs of {@code this} are equivalent to those of {@code other} under {@code renaming} + */ public boolean isEquivalent(CTPath other, Bijection renaming, ConstraintSolver solver) { if (!typeSizesMatch(other)) { return false; @@ -69,6 +86,13 @@ public boolean isEquivalent(CTPath other, Bijection renaming, Constra return true; } + /** + * Checks whether the SDTs of {@code this} and {@code other} have the same number of + * data value types. + * + * @param other + * @return {@code true} if the number of types match for the SDTs of {@code this} and {@code other} + */ protected boolean typeSizesMatch(CTPath other) { if (!DataUtils.typedSize(memorable).equals(DataUtils.typedSize(other.memorable))) { return false; @@ -99,6 +123,17 @@ private static boolean equalTypeSizes(Set s1, Set s2) { return DataUtils.typedSize(s1).equals(DataUtils.typedSize(s2)); } + /** + * Computes the path for {@code prefix} by computing SDTs for each suffix in {@code suffixes}. + * The SDTs already contained within the path {@code prefix} will be copied to the new path. + * Remaining SDTs are computed via tree queries. + * + * @param oracle the oracle to use for tree queries + * @param prefix the prefix for which the new path is to be computed + * @param suffixes the suffixes along the path + * @param ioMode {@code true} if the language being learned is an IO language + * @return a {@code CTPath} containing SDTs for each suffix in {@code suffixes} + */ public static CTPath computePath(TreeOracle oracle, Prefix prefix, List suffixes, boolean ioMode) { CTPath r = new CTPath(ioMode); SDT sdt = prefix.getSDT(RaStar.EMPTY_SUFFIX); diff --git a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java index 65dbe61a..40af6cdf 100644 --- a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java +++ b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java @@ -36,6 +36,12 @@ import gov.nasa.jpf.constraints.api.Expression; import net.automatalib.word.Word; +/** + * Data structure for a classification tree. Implements methods for sifting new prefixes into the tree + * and refining the tree with additional symbolic suffixes, as well as closedness and consistency checks. + * + * @author fredrik + */ public class ClassificationTree { private final CTInnerNode root; @@ -76,28 +82,34 @@ public ClassificationTree(TreeOracle oracle, root = new CTInnerNode(null, RaStar.EMPTY_SUFFIX); } - private static List outputSuffixes(ParameterizedSymbol[] inputs) { - List ret = new ArrayList<>(); - for (ParameterizedSymbol ps : inputs) { - if (ps instanceof OutputSymbol) { - ret.add(new SymbolicSuffix(ps)); - } - } - return ret; - } - public Set getLeaves() { return new LinkedHashSet<>(prefixes.values()); } + public CTLeaf getLeaf(Word u) { + return prefixes.get(u); + } + public Set> getPrefixes() { return new LinkedHashSet<>(prefixes.keySet()); } - public CTLeaf getLeaf(Word u) { - return prefixes.get(u); + public Set getShortPrefixes() { + Set sp = new LinkedHashSet<>(); + for (CTLeaf leaf : getLeaves()) { + sp.addAll(leaf.getShortPrefixes()); + } + assert sp.size() == shortPrefixes.size(); + assert sp.containsAll(shortPrefixes); + return sp; } + /** + * Get all one-symbol extensions of prefix {@code u}. + * + * @param u + * @return set of prefixes which are one-symbol extensions of {@code u} + */ public Set getExtensions(Word u) { Set extensions = new LinkedHashSet<>(); for (ParameterizedSymbol action : inputs) { @@ -109,6 +121,68 @@ public Set getExtensions(Word u) { return extensions; } + /** + * Get the sink node of the classification tree (IO mode only). The sink node of an IO classification + * tree is the leaf node in the rejecting branch of the tree (i.e., the branch for the empty symbolic suffix + * which is rejecting. Note that in IO mode, there should only be one rejecting leaf. + * + * @return an {@code Optional} containing the sink node if one exists, or an empty {@code Optional} otherwise + */ + public Optional getSink() { + if (!ioMode) { + return Optional.empty(); + } + + for (CTBranch branch : root.getBranches()) { + if (!branch.getRepresentativePath().isAccepting()) { + CTNode node = branch.getChild(); + while (!node.isLeaf()) { + CTInnerNode inner = (CTInnerNode) node; + List children = inner.getBranches(); + if (children.isEmpty()) { + return Optional.empty(); + } + node = children.stream().findFirst().get().getChild(); + } + return Optional.of((CTLeaf) node); + } + } + return Optional.empty(); + } + + /** + * Get all one-symbol {@code action}-extensions of prefix {@code u}. + * + * @param u + * @param action + * @return set of prefixes which are one-symbol extensions of {@code u} with symbol {@code action} + */ + public Set> getExtensions(Word u, ParameterizedSymbol action) { + return prefixes.keySet() + .stream() + .filter(w -> w.length() == u.length() + 1) + .filter(w -> w.prefix(w.length() - 1).equals(u) && w.lastSymbol().getBaseSymbol().equals(action)) + .collect(Collectors.toSet()); + } + + /** + * Initialize the classification tree by sifting the empty prefix. + */ + public void initialize() { + sift(RaStar.EMPTY_PREFIX); + } + + ////////////////////////////////////////// + // OPERATION ON THE CLASSIFICATION TREE // + ////////////////////////////////////////// + + /** + * Sift prefix into the tree. If prefix sifts to a new leaf, it becomes the representative prefix + * for that leaf. + * + * @param u prefix to sift + * @return the leaf into which {@code u} has been sifted + */ public CTLeaf sift(Word u) { Prefix prefix = new Prefix(u, new CTPath(ioMode)); CTLeaf leaf = root.sift(prefix, oracle, solver, ioMode); @@ -116,14 +190,22 @@ public CTLeaf sift(Word u) { return leaf; } + /** + * Expands a prefix by turning it into a short prefix. The new short prefix will have + * branching information initialized from the initial guards of the conjunction of all its SDTs. + * + * @param u the prefix to be expanded + */ public void expand(Word u) { CTLeaf leaf = prefixes.get(u); + // sift u into leaf, if not already present if (leaf == null) { leaf = sift(u); } ShortPrefix prefix = leaf.elevatePrefix(u, oracle, inputs); shortPrefixes.add(u); + // sift one-symbol extensions of u for (ParameterizedSymbol ps : inputs) { Branching b = prefix.getBranching(ps); for (Word ua : b.getBranches().keySet()) { @@ -133,12 +215,22 @@ public void expand(Word u) { } } + /** + * Refine a {@code leaf} by adding a new inner node with above it. After the new inner node is added, + * all prefixes of {@code leaf} will be sifted into the classification tree with a call to + * {@link ClassificationTree#sift(Word)}. Any short prefix in {@code leaf} will have its branching + * updated. + * + * @param leaf the leaf to refine + * @param suffix the symbolic suffix to be contained within the new inner node + */ public void refine(CTLeaf leaf, SymbolicSuffix suffix) { CTInnerNode parent = (CTInnerNode) leaf.getParent(); assert parent != null; Map, CTLeaf> leaves = parent.refine(leaf, suffix, oracle, solver, ioMode, inputs); prefixes.putAll(leaves); + // make sure all short prefixes are still short (this may not be the case if a new leaf was created) for (Word sp : shortPrefixes) { CTLeaf l = prefixes.get(sp); Prefix p = l.getPrefix(sp); @@ -148,56 +240,17 @@ public void refine(CTLeaf leaf, SymbolicSuffix suffix) { } } - public void initialize() { - sift(RaStar.EMPTY_PREFIX); - } - - public Set getShortPrefixes() { - Set sp = new LinkedHashSet<>(); - for (CTLeaf leaf : getLeaves()) { - sp.addAll(leaf.getShortPrefixes()); - } - assert sp.size() == shortPrefixes.size(); - assert sp.containsAll(shortPrefixes); - return sp; - } - - public CTInnerNode lca(CTNode n1, CTNode n2) { - if (n1 == n2) { - if (n1.isLeaf()) { - return (CTInnerNode) n1.getParent(); - } - return (CTInnerNode) n1; - } - int h1 = height(n1); - int h2 = height(n2); - - return lca(n1, h1, n2, h2); - } - - private CTInnerNode lca(CTNode n1, int h1, CTNode n2, int h2) { - if (n1 == n2) { - assert n1 instanceof CTInnerNode; - return (CTInnerNode) n1; - } - if (h1 < h2) { - return lca(n1, h1, n2.getParent(), h2 - 1); - } - if (h1 > h2) { - return lca(n1.getParent(), h1 - 1, n2, h2); - } - return lca(n1.getParent(), h1 - 1, n2.getParent(), h2 - 1); - } - - private int height(CTNode n) { - int h = 0; - while (n.getParent() != null) { - h++; - n = n.getParent(); - } - return h; - } - + /////////////////////// + // CLOSEDNESS CHECKS // + /////////////////////// + + /** + * Checks for output closedness, i.e., whether a symbolic suffix for each output symbol is + * present for each leaf. If not output closed, add one missing output suffix as a new inner + * node with a call to {@link ClassificationTree#refine(CTLeaf, SymbolicSuffix)}. + * + * @return {@code true} if output closed + */ public boolean checkOutputClosed() { if (!ioMode) { return true; @@ -226,8 +279,13 @@ private boolean checkOutputClosed(CTNode node) { return true; } - // CLOSEDNESS CHECKS - + /** + * Checks for location closedness, i.e., whether each leaf has at least one short prefix. If + * not location closed, this method expands, with a call to {@link ClassificationTree#expand(Word)}, + * the representative prefix of one leaf which does not have a short prefix. + * + * @return {@code true} if location closed + */ public boolean checkLocationClosedness() { for (CTLeaf leaf : getLeaves()) { if (leaf.getShortPrefixes().isEmpty()) { @@ -238,6 +296,13 @@ public boolean checkLocationClosedness() { return true; } + /** + * Checks for transition closedness, i.e., whether each short prefix has a one-symbol extension + * for each guard. If not transition closed, one new one-symbol prefix will be sifted for one + * short prefix missing an extension. + * + * @return {@code true} if transition closed + */ public boolean checkTransitionClosedness() { for (CTLeaf leaf : getLeaves()) { for (ShortPrefix u : leaf.getShortPrefixes()) { @@ -254,6 +319,16 @@ public boolean checkTransitionClosedness() { return true; } + /** + * Checks for register closedness, i.e., whether for each short prefix {@code u}, the memorable parameters + * of {@code u} contain all the memorable parameters of its one-symbol extensions {@code ua(d)}. If not register + * closed, a new symbolic suffix {@code av}, formed by prepending the symbol {@code a} of {@code ua(d)} with a + * symbolic suffix {@code v} which reveals a missing memorable parameter of {@code ua(d)}, will be added to + * the leaf of {@code u}. Note that only one new symbolic suffix will be added, even if there are multiple + * short prefixes for which a memorable parameter is missing. + * + * @return {@code true} if register closed + */ public boolean checkRegisterClosedness() { for (Map.Entry, CTLeaf> e : prefixes.entrySet()) { Word ua = e.getKey(); @@ -270,10 +345,11 @@ public boolean checkRegisterClosedness() { Set a_mem = actionRegisters(ua); if (!consistentMemorable(ua_mem, u_mem, a_mem)) { + // memorables are missing, find suffix which reveals missing memorables for (SymbolicSuffix v : leaf.getSuffixes()) { Set s_mem = ua_pref.getSDT(v).getDataValues(); if (!consistentMemorable(s_mem, u_mem, a_mem)) { - DataValue[] missingRegs = missingRegisters(s_mem, u_mem, a_mem); + DataValue[] missingRegs = missingRegisters(s_mem, u_mem, a_mem); // registers to not optimize away SymbolicSuffix av = extendSuffix(ua, v, missingRegs); refine(u_leaf, av); break; @@ -284,50 +360,21 @@ public boolean checkRegisterClosedness() { } return true; } - - private boolean consistentMemorable(Set ua_mem, Set u_mem, Set a_mem) { - Set union = new LinkedHashSet<>(); - union.addAll(u_mem); - union.addAll(a_mem); - return union.containsAll(ua_mem); - } - - private Set actionRegisters(Word ua) { - int ua_arity = DataWords.paramLength(DataWords.actsOf(ua)); - int u_arity = ua_arity - ua.lastSymbol().getBaseSymbol().getArity(); - DataValue[] vals = DataWords.valsOf(ua); - - Set regs = new LinkedHashSet<>(); - for (int i = u_arity; i < ua_arity; i++) { - regs.add(vals[i]); - } - return regs; - } - - private DataValue[] missingRegisters(Set s_mem, Set u_mem, Set a_mem) { - Set union = new LinkedHashSet<>(u_mem); - union.addAll(a_mem); - Set difference = new LinkedHashSet<>(s_mem); - difference.removeAll(union); - return difference.toArray(new DataValue[difference.size()]); - } - - private SymbolicSuffix extendSuffix(Word ua, SymbolicSuffix v, DataValue[] missingRegs) { - if (suffixBuilder == null) { - PSymbolInstance a = ua.lastSymbol(); - Word u = ua.prefix(ua.length() - 1); - SymbolicSuffix alpha = new SymbolicSuffix(u, Word.fromSymbols(a), restrBuilder); - return alpha.concat(v); - } - - SDT u_sdt = prefixes.get(ua).getPrefix(ua).getSDT(v); - assert u_sdt != null : "SDT for symbolic suffix " + v + " does not exist for prefix " + ua; - - return suffixBuilder.extendSuffix(ua, u_sdt, v, missingRegs); - } - - // CONSISTENCY CHECKS - + + //////////////////////// + // CONSISTENCY CHECKS // + //////////////////////// + + /** + * Checks for location consistency. This property states that, for each pair of short prefixes {@code u} and {@code v}, + * each one-symbol extension {@code ua(d)} and {@code va(d)} of {@code u} and {@code v}, corresponding to the same + * guard, is in the same leaf. If the classification tree is not location consistent, this method refines the tree with a + * new symbolic suffix formed by prepending the symbolic suffix of the lowest common ancestor of {@code u} and {@code v} + * by the symbol {@code a} of the one-symbol extensions revealing the inconsistency. Note that only one location inconsistency + * will be resolved by this method. To resolve multiple inconsistencies, call the method multiple times. + * + * @return {@code true} if location consistent + */ public boolean checkLocationConsistency() { for (CTLeaf l : getLeaves()) { Iterator sp = l.getShortPrefixes().iterator(); @@ -336,24 +383,28 @@ public boolean checkLocationConsistency() { } ShortPrefix u = sp.next(); while (sp.hasNext()) { - ShortPrefix uPrime = sp.next(); + ShortPrefix uOther = sp.next(); for (ParameterizedSymbol action : inputs) { + // loop over one-symbol extensions for (Map.Entry, Expression> uEntry : u.getBranching(action).getBranches().entrySet()) { - Word ua = uEntry.getKey(); - Expression g = uEntry.getValue(); - Bijection gamma = u.getRpBijection().compose(uPrime.getRpBijection().inverse()); + // rename guard to make parameters consistent with RP + Word uExtension = uEntry.getKey(); + Expression uGuard = uEntry.getValue(); + Bijection uRenaming = u.getRpBijection().compose(uOther.getRpBijection().inverse()); ReplacingValuesVisitor rvv = new ReplacingValuesVisitor(); - Expression gammaG = rvv.apply(g, gamma.toVarMapping()); - - Optional> uPrimeA = uPrime.getBranching(action).getPrefix(gammaG, solver); - assert uPrimeA.isPresent(); - - CTLeaf uALeaf = getLeaf(ua); - CTLeaf uPrimeALeaf = getLeaf(uPrimeA.get()); - if (uALeaf != uPrimeALeaf) { - SymbolicSuffix v = lca(uALeaf, uPrimeALeaf).getSuffix(); - SymbolicSuffix av = extendSuffix(ua, uPrimeA.get(), v); + Expression uGuardRenamed = rvv.apply(uGuard, uRenaming.toVarMapping()); + + // find equivalent one-symbol extension for RP + Optional> uOtherExtension = uOther.getBranching(action).getPrefix(uGuardRenamed, solver); + assert uOtherExtension.isPresent(); + + CTLeaf uExtLeaf = getLeaf(uExtension); + CTLeaf uOtherExtLeaf = getLeaf(uOtherExtension.get()); + if (uExtLeaf != uOtherExtLeaf) { + // inconsistent, refine leaf with extended suffix + SymbolicSuffix v = lca(uExtLeaf, uOtherExtLeaf).getSuffix(); + SymbolicSuffix av = extendSuffix(uExtension, uOtherExtension.get(), v); refine(l, av); return false; } @@ -364,6 +415,20 @@ public boolean checkLocationConsistency() { return true; } + /** + * Checks for transition consistency. There are two types of transition consistency, (a) and (b). + * This method checks for both. The transition consistency (a) property states that all one-symbol + * extensions {@code ua(d)} of a prefix {@code u} which satisfy the same guard are in the same leaf. + * Transition consistency (b) states that all one-symbol extensions {@code ua(d)} of a prefix {@code u} + * that satisfy the same guard and are in the same leaf should have equivalent SDTs under identity renaming. + * If either property is not satisfied, the classification tree will be refined by adding a new inner + * node to the leaf of {@code u} with a symbolic suffix formed by prepending the symbolic suffix + * revealing the inconsistency by the symbol {@code a} of the one-symbol extension. + * Note that only one inconsistency will be resolved. Multiple inconsistencies can be resolved through + * multiple calls to this method. + * + * @return {@code true} if transition consistent + */ public boolean checkTransitionConsistency() { for (ShortPrefix u : getShortPrefixes()) { for (ParameterizedSymbol action : inputs) { @@ -375,12 +440,16 @@ public boolean checkTransitionConsistency() { if (uB.equals(uA)) { continue; } + + // check if guard for uA is satisfiable under mapping of uB Mapping mapping = new Mapping<>(); mapping.putAll(actionValuation(uB)); mapping.putAll(consts); if (solver.isSatisfiable(g, mapping)) { + // check transition consistency A Optional av = transitionConsistentA(uA, uB); if (av.isEmpty()) { + // check transition consistency B av = transitionConsistentB(uA, uB); } if (av.isPresent()) { @@ -418,8 +487,11 @@ private Optional transitionConsistentB(Word uA, if (!SDT.equivalentUnderId(sdtA, sdtB)) { CTLeaf uLeaf = getLeaf(uA.prefix(uA.length() - 1)); assert uLeaf != null; + + // find registers that should not be removed through optimization Register[] regs = inequivalentMapping(rpRegBijection(pA.getRpBijection(), pA), rpRegBijection(pB.getRpBijection(), pB)); DataValue[] regVals = regsToDvs(regs, uA); + SymbolicSuffix av = extendSuffix(uA, v, regVals); if (suffixRevealsNewGuard(av, getLeaf(uA.prefix(uA.length() - 1)))) { return Optional.of(av); @@ -429,33 +501,17 @@ private Optional transitionConsistentB(Word uA, return Optional.empty(); } - private boolean suffixRevealsNewGuard(SymbolicSuffix av, CTLeaf leaf) { - Word u = leaf.getRepresentativePrefix(); - SDT sdt = oracle.treeQuery(u, av); - ParameterizedSymbol a = av.getActions().firstSymbol(); - Branching branching = leaf.getBranching(a); - Branching newBranching = oracle.updateBranching(u, a, branching, sdt); - for (Expression guard : newBranching.getBranches().values()) { - if (!branching.getBranches().values().contains(guard)) { - return true; - } - } - return false; - } - - private Bijection rpRegBijection(Bijection bijection, Word prefx) { - return Bijection.DVtoRegBijection(bijection, prefx, getLeaf(prefx).getRepresentativePrefix()); - } - - private DataValue[] regsToDvs(Register[] regs, Word prefix) { - DataValue[] vals = DataWords.valsOf(prefix); - DataValue[] ret = new DataValue[regs.length]; - for (int i = 0; i < ret.length; i++) { - ret[i] = vals[regs[i].getId()-1]; - } - return ret; - } - + /** + * Checks for register consistency. This property states that if there are any symmetries between + * memorable parameters of any prefix, then these symmetries must be present also in its + * one-symbol extensions. If this property does not hold for some prefix {@code u}, a new inner + * node will be added to break the symmetry of {@code u}. This node will contain a symbolic suffix + * formed by prepending the symbolic suffix breaking the symmetry in the one-symbol extension + * {@code ua(d)} by the symbol {@code a}. Not that only one inconsistency will be resolved in this + * manner. Multiple inconsistencies should be resolved with multiple calls to this method. + * + * @return {@code true} if register consistent + */ public boolean checkRegisterConsistency() { for (Prefix u : getShortPrefixes()) { if (u.length() < 2) { @@ -467,18 +523,21 @@ public boolean checkRegisterConsistency() { .map(w -> getLeaf(w).getPrefix(w)) .iterator(); while (extensions.hasNext()) { - Prefix ua = extensions.next(); + Prefix uExtended = extensions.next(); + // loop over all bijections exhibiting symmetry RemappingIterator rit = new RemappingIterator<>(u.getRegisters(), u.getRegisters()); for (Bijection gamma : rit) { CTPath uPath = u.getPath(); if (uPath.isEquivalent(uPath, gamma, solver)) { - for (Map.Entry e : ua.getPath().getSDTs().entrySet()) { + // u exhibits symmetry under gamma + for (Map.Entry e : uExtended.getPath().getSDTs().entrySet()) { SymbolicSuffix v = e.getKey(); SDT uaSDT = e.getValue(); if (SDT.equivalentUnderBijection(uaSDT, uaSDT, gamma) == null) { + // one-symbol extension uExtended does not exhibit symmetry under gamma DataValue[] regs = gamma.keySet().toArray(new DataValue[gamma.size()]); - SymbolicSuffix av = extendSuffix(ua, v, regs); + SymbolicSuffix av = extendSuffix(uExtended, v, regs); refine(getLeaf(u), av); return false; } @@ -491,12 +550,193 @@ public boolean checkRegisterConsistency() { return true; } + //////////////////// + // HELPER METHODS // + //////////////////// + + /** + * + * @param n1 + * @param n2 + * @return lowest common ancestor of {@code n1} and {@code n2} + */ + private CTInnerNode lca(CTNode n1, CTNode n2) { + if (n1 == n2) { + if (n1.isLeaf()) { + return (CTInnerNode) n1.getParent(); + } + return (CTInnerNode) n1; + } + int h1 = height(n1); + int h2 = height(n2); + + return lca(n1, h1, n2, h2); + } + + private CTInnerNode lca(CTNode n1, int h1, CTNode n2, int h2) { + if (n1 == n2) { + assert n1 instanceof CTInnerNode; + return (CTInnerNode) n1; + } + if (h1 < h2) { + return lca(n1, h1, n2.getParent(), h2 - 1); + } + if (h1 > h2) { + return lca(n1.getParent(), h1 - 1, n2, h2); + } + return lca(n1.getParent(), h1 - 1, n2.getParent(), h2 - 1); + } + + private int height(CTNode n) { + int h = 0; + while (n.getParent() != null) { + h++; + n = n.getParent(); + } + return h; + } + + /** + * + * @param ua_mem + * @param u_mem + * @param a_mem + * @return {@code true} if {@code ua_mem} contains all of {@code u_mem} and {@code a_mem} + */ + private boolean consistentMemorable(Set ua_mem, Set u_mem, Set a_mem) { + Set union = new LinkedHashSet<>(); + union.addAll(u_mem); + union.addAll(a_mem); + return union.containsAll(ua_mem); + } + + /** + * @param ua + * @return the set of data values in the last symbol instance of {@code ua} + */ + private Set actionRegisters(Word ua) { + int ua_arity = DataWords.paramLength(DataWords.actsOf(ua)); + int u_arity = ua_arity - ua.lastSymbol().getBaseSymbol().getArity(); + DataValue[] vals = DataWords.valsOf(ua); + + Set regs = new LinkedHashSet<>(); + for (int i = u_arity; i < ua_arity; i++) { + regs.add(vals[i]); + } + return regs; + } + + /** + * + * @param s_mem + * @param u_mem + * @param a_mem + * @return an array containing the data values of {@code s_mem} not contained in either {@code u_mem} or {@code a_mem} + */ + private DataValue[] missingRegisters(Set s_mem, Set u_mem, Set a_mem) { + Set union = new LinkedHashSet<>(u_mem); + union.addAll(a_mem); + Set difference = new LinkedHashSet<>(s_mem); + difference.removeAll(union); + return difference.toArray(new DataValue[difference.size()]); + } + + /** + * Form a new symbolic suffix by prepending {@code v} by the last symbol of {@code ua}, + * using suffix optimization. + * + * @param ua + * @param v + * @param missingRegs the register which should not be removed through suffix optimizations + * @return the last symbol of {@code ua} concatenated with {@code v} + */ + private SymbolicSuffix extendSuffix(Word ua, SymbolicSuffix v, DataValue[] missingRegs) { + if (suffixBuilder == null) { + PSymbolInstance a = ua.lastSymbol(); + Word u = ua.prefix(ua.length() - 1); + SymbolicSuffix alpha = new SymbolicSuffix(u, Word.fromSymbols(a), restrBuilder); + return alpha.concat(v); + } + + SDT u_sdt = prefixes.get(ua).getPrefix(ua).getSDT(v); + assert u_sdt != null : "SDT for symbolic suffix " + v + " does not exist for prefix " + ua; + + return suffixBuilder.extendSuffix(ua, u_sdt, v, missingRegs); + } + + /** + * Perform a tree query for the representative prefix of {@code leaf} with {@code av} to check + * whether {@code av} reveals additional guards. + * + * @param av + * @param leaf + * @return {@code true} if {@code av} reveals additional guards + */ + private boolean suffixRevealsNewGuard(SymbolicSuffix av, CTLeaf leaf) { + Word u = leaf.getRepresentativePrefix(); + SDT sdt = oracle.treeQuery(u, av); + ParameterizedSymbol a = av.getActions().firstSymbol(); + Branching branching = leaf.getBranching(a); + Branching newBranching = oracle.updateBranching(u, a, branching, sdt); + for (Expression guard : newBranching.getBranches().values()) { + if (!branching.getBranches().values().contains(guard)) { + return true; + } + } + return false; + } + + /** + * Convert {@code Bijection} to {@code Bijection} using the + * data values of {@code prefix} to determine register ids. + * + * @param bijection + * @param prefx + * @return + */ + private Bijection rpRegBijection(Bijection bijection, Word prefx) { + return Bijection.DVtoRegBijection(bijection, prefx, getLeaf(prefx).getRepresentativePrefix()); + } + + /** + * Convert array of {@code Register} to array of {@code DataValue} by matching {@link Register#getId()} + * values to data value positions in {@code prefix}. + * + * @param regs + * @param prefix + * @return + */ + private DataValue[] regsToDvs(Register[] regs, Word prefix) { + DataValue[] vals = DataWords.valsOf(prefix); + DataValue[] ret = new DataValue[regs.length]; + for (int i = 0; i < ret.length; i++) { + ret[i] = vals[regs[i].getId()-1]; + } + return ret; + } + + /** + * Form a {@code SymbolicSuffix} by prepending {@code v} by the last symbol of {@code u1} and {@code u2}. + * The new suffix will be optimized for separating {@code u1} and {@code u2}. + * Note that {@code u1} and {@code u2} must have the same last symbol. + * + * @param u1 + * @param u2 + * @param v + * @return + */ private SymbolicSuffix extendSuffix(Word u1, Word u2, SymbolicSuffix v) { SDT sdt1 = getLeaf(u1).getPrefix(u1).getSDT(v); SDT sdt2 = getLeaf(u2).getPrefix(u2).getSDT(v); return suffixBuilder.extendDistinguishingSuffix(u1, sdt1, u2, sdt2, v); } + /** + * {@code ParameterValuation} of the last symbol instance of {@code ua}. + * + * @param ua + * @return + */ private ParameterValuation actionValuation(Word ua) { ParameterGenerator pgen = new ParameterGenerator(); DataValue[] vals = ua.lastSymbol().getParameterValues(); @@ -508,14 +748,12 @@ private ParameterValuation actionValuation(Word ua) { return valuation; } - public Set> getExtensions(Word u, ParameterizedSymbol action) { - return prefixes.keySet() - .stream() - .filter(w -> w.length() == u.length() + 1) - .filter(w -> w.prefix(w.length() - 1).equals(u) && w.lastSymbol().getBaseSymbol().equals(action)) - .collect(Collectors.toSet()); - } - + /** + * + * @param a + * @param b + * @return array of registers in {@code a} and {@code b} which are not mapped the same + */ private Register[] inequivalentMapping(Bijection a, Bijection b) { Set ret = new LinkedHashSet<>(); for (Map.Entry ea : a.entrySet()) { @@ -532,31 +770,6 @@ private Register[] inequivalentMapping(Bijection a, Bijection getSink() { - if (!ioMode) { - return Optional.empty(); - } - - for (CTBranch branch : root.getBranches()) { - if (!branch.getPath().isAccepting()) { - CTNode node = branch.getChild(); - while (!node.isLeaf()) { - CTInnerNode inner = (CTInnerNode) node; - List children = inner.getBranches(); - if (children.isEmpty()) { - return Optional.empty(); - } - node = children.stream().findFirst().get().getChild(); - } - return Optional.of((CTLeaf) node); - } - } - return Optional.empty(); - } - @Override public String toString() { StringBuilder builder = new StringBuilder(); @@ -583,4 +796,15 @@ private void buildTreeString(StringBuilder builder, CTNode node, String currentI } } } + + private static List outputSuffixes(ParameterizedSymbol[] inputs) { + List ret = new ArrayList<>(); + for (ParameterizedSymbol ps : inputs) { + if (ps instanceof OutputSymbol) { + ret.add(new SymbolicSuffix(ps)); + } + } + return ret; + } + } diff --git a/src/main/java/de/learnlib/ralib/ct/MemorableSet.java b/src/main/java/de/learnlib/ralib/ct/MemorableSet.java index fc8a9924..52074d43 100644 --- a/src/main/java/de/learnlib/ralib/ct/MemorableSet.java +++ b/src/main/java/de/learnlib/ralib/ct/MemorableSet.java @@ -5,6 +5,11 @@ import de.learnlib.ralib.data.Bijection; import de.learnlib.ralib.data.DataValue; +/** + * A set of memorable data values + * + * @author fredrik + */ public class MemorableSet extends LinkedHashSet { public MemorableSet relabel(Bijection renaming) { MemorableSet renamed = new MemorableSet(); diff --git a/src/main/java/de/learnlib/ralib/ct/Prefix.java b/src/main/java/de/learnlib/ralib/ct/Prefix.java index db38dbb0..667d4e61 100644 --- a/src/main/java/de/learnlib/ralib/ct/Prefix.java +++ b/src/main/java/de/learnlib/ralib/ct/Prefix.java @@ -20,6 +20,19 @@ import de.learnlib.ralib.words.ParameterizedSymbol; import net.automatalib.word.Word; +/** + * Data structure for a prefix stored within a leaf of a {@link ClassificationTree}. + * Along with the prefix itself, also stores the SDTs for each suffix along the path + * through which the prefix was sifted, as well as the {@code Bijection} under which + * the SDTs along the path are equivalent to those of the leaf's representative prefix + * (the RP bijection). If this prefix is the representative prefix, the RP bijection + * should be the identity mapping. + * + * @author fredrik + * @see CTLeaf + * @see CTPath + * @see Bijection + */ public class Prefix extends Word implements PrefixContainer { private final Word prefix; private Bijection rpBijection; diff --git a/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java b/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java index d15f9678..a165b36b 100644 --- a/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java +++ b/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java @@ -13,6 +13,13 @@ import de.learnlib.ralib.words.ParameterizedSymbol; import net.automatalib.word.Word; +/** + * Data structure for storing branching information of a short prefix, + * in addition to the SDTs from the suffixes along its path stored + * in {@link Prefix}. + * + * @author fredrik + */ public class ShortPrefix extends Prefix { private final Map branching; @@ -42,6 +49,10 @@ public Branching getBranching(ParameterizedSymbol ps) { return branching.get(ps); } + /** + * Update the branching according to the SDTs computed for the suffixes along the path to + * the leaf in which this short prefix is stored. + */ public void updateBranching() { for (ParameterizedSymbol ps : inputs) { SDT[] sdts = getSDTs(ps); @@ -49,8 +60,4 @@ public void updateBranching() { branching.put(ps, b); } } - - public Set> getInitialReprPrefixes(ParameterizedSymbol ps) { - return branching.get(ps).getBranches().keySet(); - } } diff --git a/src/main/java/de/learnlib/ralib/oracles/Branching.java b/src/main/java/de/learnlib/ralib/oracles/Branching.java index ba5ac5a8..9388c89d 100644 --- a/src/main/java/de/learnlib/ralib/oracles/Branching.java +++ b/src/main/java/de/learnlib/ralib/oracles/Branching.java @@ -40,7 +40,17 @@ public interface Branching { Word transformPrefix(Word prefix); + /** + * Return a prefix {@code u} within this branching such that the parameters of the last + * symbol of {@code u} satisfy {@code guard}. + * + * @param guard + * @param solver + * @return an {@code Optional} encasing a prefix matching {@code guard} if one exists, + * or an empty {@code Optional} otherwise + */ default Optional> getPrefix(Expression guard, ConstraintSolver solver) { + // if guard is a value, return the corresponding key Optional> prefix = getBranches().entrySet() .stream() .filter(e -> e.getValue().equals(guard)) @@ -50,6 +60,7 @@ default Optional> getPrefix(Expression guard, Con return prefix; } + // find a guard where the last symbol's values satisfy guard for (Map.Entry, Expression> e : getBranches().entrySet()) { DataValue[] vals = e.getKey().lastSymbol().getParameterValues(); Mapping valuation = new Mapping<>(); @@ -65,6 +76,9 @@ default Optional> getPrefix(Expression guard, Con return Optional.empty(); } + /** + * @return a set of all initial guards in this branching + */ default Set> guardSet() { Set> guards = new LinkedHashSet<>(); guards.addAll(getBranches().values()); diff --git a/src/main/java/de/learnlib/ralib/theory/Theory.java b/src/main/java/de/learnlib/ralib/theory/Theory.java index dfc70ce7..c21dc76b 100644 --- a/src/main/java/de/learnlib/ralib/theory/Theory.java +++ b/src/main/java/de/learnlib/ralib/theory/Theory.java @@ -100,11 +100,21 @@ DataValue instantiate(Word prefix, Constants constants, SDTGuard guard, SuffixValue param, Set oldDvs); + /** + * Instantiate a representative data value for the parameter {@code param} + * of {@code ps} that satisfies {@code guard}. + * + * @param prefix + * @param ps + * @param guard + * @param param + * @param constants + * @param solver + * @return + */ public DataValue instantiate(Word prefix, - ParameterizedSymbol ps, Set pval, - Constants constants, - Expression guard, int param, - ConstraintSolver solver); + ParameterizedSymbol ps, Expression guard, int param, + Constants constants, ConstraintSolver solver); SuffixValueRestriction restrictSuffixValue(SuffixValue suffixValue, Word prefix, Word suffix, Constants consts); diff --git a/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java b/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java index 9aa451b5..69afd6f1 100644 --- a/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java +++ b/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java @@ -413,10 +413,8 @@ private SDT makeRejectingBranch(int nextSufIndex, int maxIndex, DataType type) { @Override public DataValue instantiate(Word prefix, - ParameterizedSymbol ps, Set pval, - Constants constants, - Expression guard, int param, - ConstraintSolver solver) { + ParameterizedSymbol ps, Expression guard, int param, + Constants constants, ConstraintSolver solver) { Parameter p = new Parameter(ps.getPtypes()[param-1], param); Set vals = DataWords.valSet(prefix, p.getDataType()); vals.addAll(vals.stream() diff --git a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java index cc16e6ea..9604a195 100644 --- a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java +++ b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java @@ -611,10 +611,8 @@ public DataValue instantiate( } public DataValue instantiate(Word prefix, - ParameterizedSymbol ps, Set pval, - Constants constants, - Expression guard, int param, - ConstraintSolver solver) { + ParameterizedSymbol ps, Expression guard, int param, + Constants constants, ConstraintSolver solver) { Parameter p = new Parameter(ps.getPtypes()[param-1], param); Set vals = DataWords.valSet(prefix, p.getDataType()); vals.addAll(vals.stream() diff --git a/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java b/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java index 452c7ef5..f2f19c49 100644 --- a/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java +++ b/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java @@ -68,8 +68,9 @@ public Collection getAllNextValues(List vals) { } @Override - public DataValue instantiate(Word prefix, ParameterizedSymbol ps, Set pval, - Constants constants, Expression guard, int param, ConstraintSolver solver) { + public DataValue instantiate(Word prefix, + ParameterizedSymbol ps, Expression guard, int param, + Constants constants, ConstraintSolver solver) { throw new RuntimeException("Not implemented"); } From 943222e5dd6f4d1b51c27eb9f985fc401bf43d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Tue, 11 Nov 2025 14:47:14 +0100 Subject: [PATCH 16/31] apply spotless --- .../ralib/ceanalysis/PrefixFinder.java | 26 ++++---- .../learnlib/ralib/ct/CTAutomatonBuilder.java | 9 ++- .../java/de/learnlib/ralib/ct/CTBranch.java | 6 +- .../de/learnlib/ralib/ct/CTHypothesis.java | 6 +- .../de/learnlib/ralib/ct/CTInnerNode.java | 6 +- .../java/de/learnlib/ralib/ct/CTLeaf.java | 12 ++-- .../java/de/learnlib/ralib/ct/CTNode.java | 8 +-- .../java/de/learnlib/ralib/ct/CTPath.java | 8 +-- .../learnlib/ralib/ct/ClassificationTree.java | 62 +++++++++---------- .../de/learnlib/ralib/ct/MemorableSet.java | 2 +- .../java/de/learnlib/ralib/ct/Prefix.java | 2 +- .../de/learnlib/ralib/ct/ShortPrefix.java | 5 +- .../de/learnlib/ralib/oracles/Branching.java | 2 +- .../java/de/learnlib/ralib/theory/Theory.java | 2 +- .../theories/UniqueIntegerEqualityTheory.java | 1 - 15 files changed, 76 insertions(+), 81 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java index a35be0fc..4730a7e6 100644 --- a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java +++ b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java @@ -41,7 +41,7 @@ /** * Analyzes counterexamples according to the SLλ algorithm. - * + * * @author fredrik */ public class PrefixFinder { @@ -84,7 +84,7 @@ public PrefixFinder(TreeOracle sulOracle, CTHypothesis hyp, ClassificationTree c * Analyze counterexample {@code ce} from right to leaf to find a transition or * location discrepancy. If a discrepancy is found, returns the prefix which reveals * the discrepancy, along with a {@code ResultType} indicating the type of discrepancy. - * + * * @param ce * @return */ @@ -106,11 +106,11 @@ public Result analyzeCounterExample(Word ce) { for (ShortPrefix u : hyp.getLeaf(loc).getShortPrefixes()) { SDT sdt = sulOracle.treeQuery(u, v); - + Set uVals = hyp.getLeaf(loc).getPrefix(u).getRegisters(); Mapping uToRunRenaming = valuationRenaming(u, runValuation); Set> uToRunExtendedRenamings = extendedValuationRenamings(sdt, uVals, run, i); - + Branching branching = sulOracle.getInitialBranching(u, action, sdt); for (Expression gSul : branching.guardSet()) { for (Mapping renaming : uToRunExtendedRenamings) { @@ -158,13 +158,13 @@ private Mapping valuationRenaming(Word u, * Create extensions of the valuation from the hypothesis at index {@code id}, and map * data values from {@code uSDT} to these extended valuations. * The returned remappings do not include parameters present in the valuation at {@code id} - * (which should be mapped to parameters in {@code uVals}, except for duplicate parameters. + * (which should be mapped to parameters in {@code uVals}, except for duplicate parameters. * For example, if the parameters of {@code run} at index {@code id} contain the data values * 5,5,7 and the valuation contains 5, then the 7 and a single 5 will be considered for the * extension of the valuation. Similarly, if {@code uSDT} has data values 0,1,2 with 0 in * {@code uValuation}, then 1,2 will be considered. In this example, this method would * return the mappings {1->5, 2->7} and {1->7, 2->5}. - * + * * @param uSDT sdt for prefix {@code u} * @param uVals memorable data values of {@code u} * @param run @@ -177,7 +177,7 @@ private Set> extendedValuationRenamings(SDT uSDT, if (id < 1) { return empty; } - + // gather data values from uSDT, and remove values from uValuation Set sdtVals = new LinkedHashSet<>(uSDT.getDataValues()); for (DataValue d : uVals) { @@ -195,10 +195,10 @@ private Set> extendedValuationRenamings(SDT uSDT, runVals.add(d); } } - + /* remove data values from valuation. * may have multiple copies of same data value, which may be mapped to different - * data values in uSDT, so only remove one instance of data values in valuation + * data values in uSDT, so only remove one instance of data values in valuation */ for (DataValue d : run.getValuation(id-1).values()) { runVals = removeFirst(runVals, d); @@ -248,7 +248,7 @@ private ArrayList removeFirst(ArrayList list, DataValue d) * Check for a transition discrepancy. This is done by checking whether there exists no * {@code action}-extension of {@code u} in the leaf of {@code loc} that is equivalent * to the {@code (hypGuard && sulGuard)} extension of {@code u} after {@code v}. - * + * * @param loc the source location * @param u short prefix from leaf of {@code loc} * @param action the symbol of the next transition @@ -303,7 +303,7 @@ private Optional checkTransition(RALocation loc, * {@code action}-extension of {@code u} in the leaf of {@code locNext} such that there * does not exist some short prefix in the leaf of {@code locNext} that is equivalent * to the {@code action}-extension of {@code u} after {@code v}. - * + * * @param locNext the destination location * @param u short prefix in leaf prior to {@code locNext} in the run * @param action the symbol of the next transition @@ -345,7 +345,7 @@ private Optional checkLocation(RALocation locNext, /** * Get the guard in the hypothesis corresponding to {@code run} at index {@code idx} - * + * * @param run * @param idx * @return @@ -373,7 +373,7 @@ private Optional> getHypGuard(RARun run, int idx) { /** * Check whether {@code guard} is satisfied by the parameters of {@code symbol}, after renaming * the parameters of {@code guard} according to {@code renaming}. - * + * * @param guard * @param renaming * @param symbol diff --git a/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java index f89f2028..ab6d2ade 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java +++ b/src/main/java/de/learnlib/ralib/ct/CTAutomatonBuilder.java @@ -16,7 +16,6 @@ import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; import de.learnlib.ralib.data.Mapping; -import de.learnlib.ralib.data.ParameterValuation; import de.learnlib.ralib.data.RegisterAssignment; import de.learnlib.ralib.data.SymbolicDataValue; import de.learnlib.ralib.data.SymbolicDataValue.Parameter; @@ -42,13 +41,13 @@ * Builder class for building a {@link CTHypothesis} from a {@link ClassificationTree}. * This class implements similar functionality as {@link AutomatonBuilder} and {@link IOAutomatonBuilder}, * but tailored for the {@link SLLambda} and {@link SLCT} learning algorithms. - * + * * {@code CTAutomatonBuilder} supports construction of automata from an incomplete classification tree, * so long as the classification tree is closed and consistent. * Multiple short prefixes in the same leaf, as well as one-symbol extensions without matching guards, * will be ignored during construction. * The access sequence for each location will be set to the representative prefix of the corresponding leaf. - * + * * @author fredrik */ public class CTAutomatonBuilder { @@ -61,7 +60,7 @@ public class CTAutomatonBuilder { private final CTHypothesis hyp; private final ConstraintSolver solver; - + private final Constants consts; private boolean ioMode; @@ -208,7 +207,7 @@ private Transition createTransition(ParameterizedSymbol action, Expression expr = guard; VarMapping outmap = new VarMapping<>(); diff --git a/src/main/java/de/learnlib/ralib/ct/CTBranch.java b/src/main/java/de/learnlib/ralib/ct/CTBranch.java index 4d422750..0d087902 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTBranch.java +++ b/src/main/java/de/learnlib/ralib/ct/CTBranch.java @@ -11,9 +11,9 @@ * Branch forming an edge between two nodes in a {@link ClassificationTree}. * The branch is labeled by the representative path of the first prefix which * was sifted through the branch. - * + * * @author fredrik - * + * * @see CTNode * @see CTPath */ @@ -39,7 +39,7 @@ public CTNode getChild() { * Check whether the SDTs of {@code other} are equivalent to the SDTs of {@code this}. * under the same {@link Bijection}. If so, returns the {@code Bijection} under which the {@code SDT}s * are equivalent. - * + * * @param other the path to compare for equivalence * @param solver constraint solver to use when comparing for equivalence * @return {@code Bijection} under which the {@code SDT}s of {@code other} are equivalent to those of {@code this}, or {@code null} if the {@code SDT}s are not equivalent. diff --git a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java index 68608a60..53869f7e 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java +++ b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java @@ -25,7 +25,7 @@ * Hypothesis constructed from a {@link ClassificationTree}. Maintains a mapping between * locations in the hypothesis and leaf nodes of the {@code ClassificationTree} from which the * hypothesis was constructed. - * + * * @author fredrik * @see Hypothesis */ @@ -67,7 +67,7 @@ public RALocation getSink() { /** * Get location corresponding to {@code leaf}. - * + * * @param leaf * @return {@link RALocation} corresponding to {@code leaf} */ @@ -78,7 +78,7 @@ public RALocation getLocation(CTLeaf leaf) { /** * Get leaf node of {@link ClassificationTree} from which this hypothesis was constructed. * which corresponds to {@code location}. - * + * * @param location * @return leaf node corresponding to {@code location} * @see CTLeaf diff --git a/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java index d904b458..0ff533a8 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java +++ b/src/main/java/de/learnlib/ralib/ct/CTInnerNode.java @@ -19,7 +19,7 @@ /** * Inner node of a {@link ClassificationTree}, containing a {@link SymbolicSuffix}. * Maintains a set of branches to child nodes. - * + * * @author fredrik * @see CTBranch * @see CTNode @@ -77,7 +77,7 @@ protected CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, * The prefixes in {@code leaf} will be sifted into this new inner node. * If this sifting creates a new {@link CTLeaf}, the first prefix to be sifted * into that leaf node will be made the representative prefix. - * + * * @param leaf * @param suffix * @param oracle @@ -112,7 +112,7 @@ protected Map, CTLeaf> refine(CTLeaf leaf, SymbolicSuffix l = sift(u, oracle, solver, ioMode); leaves.put(u, l); } - + // make sure all short prefixes of leaf are still short for (ShortPrefix u : shorts) { if (!(u instanceof ShortPrefix)) { diff --git a/src/main/java/de/learnlib/ralib/ct/CTLeaf.java b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java index c48bba80..4ad72915 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTLeaf.java +++ b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java @@ -22,7 +22,7 @@ * Leaf node of a {@link ClassificationTree}, containing a number of prefixes. * A leaf node must contain at least one prefix, which is the representative * prefix of the leaf. Any number of prefixes may also be short prefixes. - * + * * @author fredrik * @see Prefix * @see ShortPrefix @@ -60,7 +60,7 @@ public Set getPrefixes() { /** * Helper method for retrieving the {@link Prefix} representation of a {@code Word}. - * + * * @param u * @return the {@code Prefix} form of {@code u} if {@code u} is in this leaf, or {@code null} otherwise */ @@ -98,7 +98,7 @@ public boolean isLeaf() { /** * Returns {@code true} if this leaf is accepting, i.e., if a tree query for this * leaf's representative prefix with the empty suffix (ε) is accepting. - * + * * @return {@code true} if this leaf corresponds to an accepting location */ public boolean isAccepting() { @@ -109,7 +109,7 @@ public boolean isAccepting() { * Adds {@code prefix} to this leaf. If {@code prefix} is a short prefix, this method updates * the branching of {@code prefix} to include initial guards from the conjunction of all SDTs * along its path. - * + * * @param prefix that will be added to this leaf * @param oracle unused * @param solver unused @@ -131,7 +131,7 @@ protected CTLeaf sift(Prefix prefix, TreeOracle oracle, ConstraintSolver solver, * Elevate {@code u} to a short prefix by converting it to a {@link ShortPrefix}. The branching * of {@code u} will be initialized to reflect the initial guards of the conjunction of SDTs * along its path. - * + * * @param u the prefix to elevate * @param oracle tree oracle to use for updating the branching * @param inputs all input symbols @@ -182,7 +182,7 @@ public Bijection getRemapping(PrefixContainer r) { /** * Get the branching for symbol {@code action} of the representative prefix. * Requires that the representative prefix is a {@link ShortPrefix}. - * + * * @param action * @return {@code Branching} of {@code action} for the representative prefix of this leaf */ diff --git a/src/main/java/de/learnlib/ralib/ct/CTNode.java b/src/main/java/de/learnlib/ralib/ct/CTNode.java index bddafdce..ec9c9a39 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTNode.java +++ b/src/main/java/de/learnlib/ralib/ct/CTNode.java @@ -8,7 +8,7 @@ /** * Node of a {@link ClassificationTree}. - * + * * @author fredrik */ public abstract class CTNode { @@ -19,7 +19,7 @@ public CTNode(CTNode parent) { } /** - * + * * @return immediate ancestor of this node */ public CTNode getParent() { @@ -32,7 +32,7 @@ public CTNode getParent() { public abstract List getSuffixes(); /** - * + * * @return {@code true} if this node is a {@link CTLeaf} */ public abstract boolean isLeaf(); @@ -44,7 +44,7 @@ public CTNode getParent() { * matches the tree query, determined with a call to {@link CTBranch#matches(CTPath, ConstraintSolver)}. * If no such child exists, this method creates a new {@code CTLeaf} and adds {@code prefix} * to it as its representative prefix. - * + * * @param prefix the prefix to sift through this node * @param oracle the {@link TreeOracle} to use when making tree queries * @param solver the {@link ConstraintSolver} to use for comparing paths for equivalence diff --git a/src/main/java/de/learnlib/ralib/ct/CTPath.java b/src/main/java/de/learnlib/ralib/ct/CTPath.java index 03bb61f2..3cdf406c 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTPath.java +++ b/src/main/java/de/learnlib/ralib/ct/CTPath.java @@ -18,7 +18,7 @@ * This data structure stores the SDTs from tree queries for a prefix along a path * in a {@link ClassificationTree}. It contains much of the same functionality as * {@link Row}, but adapted for use with classification trees. - * + * * @author fredrik * @author falk * @see Row @@ -60,7 +60,7 @@ public boolean isAccepting() { /** * Checks whether two paths are equivalent under {@code renaming}. - * + * * @param other * @param renaming * @param solver @@ -89,7 +89,7 @@ public boolean isEquivalent(CTPath other, Bijection renaming, Constra /** * Checks whether the SDTs of {@code this} and {@code other} have the same number of * data value types. - * + * * @param other * @return {@code true} if the number of types match for the SDTs of {@code this} and {@code other} */ @@ -127,7 +127,7 @@ private static boolean equalTypeSizes(Set s1, Set s2) { * Computes the path for {@code prefix} by computing SDTs for each suffix in {@code suffixes}. * The SDTs already contained within the path {@code prefix} will be copied to the new path. * Remaining SDTs are computed via tree queries. - * + * * @param oracle the oracle to use for tree queries * @param prefix the prefix for which the new path is to be computed * @param suffixes the suffixes along the path diff --git a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java index 40af6cdf..310c9470 100644 --- a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java +++ b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java @@ -39,7 +39,7 @@ /** * Data structure for a classification tree. Implements methods for sifting new prefixes into the tree * and refining the tree with additional symbolic suffixes, as well as closedness and consistency checks. - * + * * @author fredrik */ public class ClassificationTree { @@ -106,7 +106,7 @@ public Set getShortPrefixes() { /** * Get all one-symbol extensions of prefix {@code u}. - * + * * @param u * @return set of prefixes which are one-symbol extensions of {@code u} */ @@ -125,7 +125,7 @@ public Set getExtensions(Word u) { * Get the sink node of the classification tree (IO mode only). The sink node of an IO classification * tree is the leaf node in the rejecting branch of the tree (i.e., the branch for the empty symbolic suffix * which is rejecting. Note that in IO mode, there should only be one rejecting leaf. - * + * * @return an {@code Optional} containing the sink node if one exists, or an empty {@code Optional} otherwise */ public Optional getSink() { @@ -152,7 +152,7 @@ public Optional getSink() { /** * Get all one-symbol {@code action}-extensions of prefix {@code u}. - * + * * @param u * @param action * @return set of prefixes which are one-symbol extensions of {@code u} with symbol {@code action} @@ -179,7 +179,7 @@ public void initialize() { /** * Sift prefix into the tree. If prefix sifts to a new leaf, it becomes the representative prefix * for that leaf. - * + * * @param u prefix to sift * @return the leaf into which {@code u} has been sifted */ @@ -193,7 +193,7 @@ public CTLeaf sift(Word u) { /** * Expands a prefix by turning it into a short prefix. The new short prefix will have * branching information initialized from the initial guards of the conjunction of all its SDTs. - * + * * @param u the prefix to be expanded */ public void expand(Word u) { @@ -220,7 +220,7 @@ public void expand(Word u) { * all prefixes of {@code leaf} will be sifted into the classification tree with a call to * {@link ClassificationTree#sift(Word)}. Any short prefix in {@code leaf} will have its branching * updated. - * + * * @param leaf the leaf to refine * @param suffix the symbolic suffix to be contained within the new inner node */ @@ -243,12 +243,12 @@ public void refine(CTLeaf leaf, SymbolicSuffix suffix) { /////////////////////// // CLOSEDNESS CHECKS // /////////////////////// - + /** * Checks for output closedness, i.e., whether a symbolic suffix for each output symbol is * present for each leaf. If not output closed, add one missing output suffix as a new inner * node with a call to {@link ClassificationTree#refine(CTLeaf, SymbolicSuffix)}. - * + * * @return {@code true} if output closed */ public boolean checkOutputClosed() { @@ -283,7 +283,7 @@ private boolean checkOutputClosed(CTNode node) { * Checks for location closedness, i.e., whether each leaf has at least one short prefix. If * not location closed, this method expands, with a call to {@link ClassificationTree#expand(Word)}, * the representative prefix of one leaf which does not have a short prefix. - * + * * @return {@code true} if location closed */ public boolean checkLocationClosedness() { @@ -300,7 +300,7 @@ public boolean checkLocationClosedness() { * Checks for transition closedness, i.e., whether each short prefix has a one-symbol extension * for each guard. If not transition closed, one new one-symbol prefix will be sifted for one * short prefix missing an extension. - * + * * @return {@code true} if transition closed */ public boolean checkTransitionClosedness() { @@ -326,7 +326,7 @@ public boolean checkTransitionClosedness() { * symbolic suffix {@code v} which reveals a missing memorable parameter of {@code ua(d)}, will be added to * the leaf of {@code u}. Note that only one new symbolic suffix will be added, even if there are multiple * short prefixes for which a memorable parameter is missing. - * + * * @return {@code true} if register closed */ public boolean checkRegisterClosedness() { @@ -360,7 +360,7 @@ public boolean checkRegisterClosedness() { } return true; } - + //////////////////////// // CONSISTENCY CHECKS // //////////////////////// @@ -372,7 +372,7 @@ public boolean checkRegisterClosedness() { * new symbolic suffix formed by prepending the symbolic suffix of the lowest common ancestor of {@code u} and {@code v} * by the symbol {@code a} of the one-symbol extensions revealing the inconsistency. Note that only one location inconsistency * will be resolved by this method. To resolve multiple inconsistencies, call the method multiple times. - * + * * @return {@code true} if location consistent */ public boolean checkLocationConsistency() { @@ -426,7 +426,7 @@ public boolean checkLocationConsistency() { * revealing the inconsistency by the symbol {@code a} of the one-symbol extension. * Note that only one inconsistency will be resolved. Multiple inconsistencies can be resolved through * multiple calls to this method. - * + * * @return {@code true} if transition consistent */ public boolean checkTransitionConsistency() { @@ -440,7 +440,7 @@ public boolean checkTransitionConsistency() { if (uB.equals(uA)) { continue; } - + // check if guard for uA is satisfiable under mapping of uB Mapping mapping = new Mapping<>(); mapping.putAll(actionValuation(uB)); @@ -487,11 +487,11 @@ private Optional transitionConsistentB(Word uA, if (!SDT.equivalentUnderId(sdtA, sdtB)) { CTLeaf uLeaf = getLeaf(uA.prefix(uA.length() - 1)); assert uLeaf != null; - + // find registers that should not be removed through optimization Register[] regs = inequivalentMapping(rpRegBijection(pA.getRpBijection(), pA), rpRegBijection(pB.getRpBijection(), pB)); DataValue[] regVals = regsToDvs(regs, uA); - + SymbolicSuffix av = extendSuffix(uA, v, regVals); if (suffixRevealsNewGuard(av, getLeaf(uA.prefix(uA.length() - 1)))) { return Optional.of(av); @@ -509,7 +509,7 @@ private Optional transitionConsistentB(Word uA, * formed by prepending the symbolic suffix breaking the symmetry in the one-symbol extension * {@code ua(d)} by the symbol {@code a}. Not that only one inconsistency will be resolved in this * manner. Multiple inconsistencies should be resolved with multiple calls to this method. - * + * * @return {@code true} if register consistent */ public boolean checkRegisterConsistency() { @@ -555,7 +555,7 @@ public boolean checkRegisterConsistency() { //////////////////// /** - * + * * @param n1 * @param n2 * @return lowest common ancestor of {@code n1} and {@code n2} @@ -597,7 +597,7 @@ private int height(CTNode n) { } /** - * + * * @param ua_mem * @param u_mem * @param a_mem @@ -627,7 +627,7 @@ private Set actionRegisters(Word ua) { } /** - * + * * @param s_mem * @param u_mem * @param a_mem @@ -644,7 +644,7 @@ private DataValue[] missingRegisters(Set s_mem, Set u_mem, /** * Form a new symbolic suffix by prepending {@code v} by the last symbol of {@code ua}, * using suffix optimization. - * + * * @param ua * @param v * @param missingRegs the register which should not be removed through suffix optimizations @@ -667,7 +667,7 @@ private SymbolicSuffix extendSuffix(Word ua, SymbolicSuffix v, /** * Perform a tree query for the representative prefix of {@code leaf} with {@code av} to check * whether {@code av} reveals additional guards. - * + * * @param av * @param leaf * @return {@code true} if {@code av} reveals additional guards @@ -689,10 +689,10 @@ private boolean suffixRevealsNewGuard(SymbolicSuffix av, CTLeaf leaf) { /** * Convert {@code Bijection} to {@code Bijection} using the * data values of {@code prefix} to determine register ids. - * + * * @param bijection * @param prefx - * @return + * @return */ private Bijection rpRegBijection(Bijection bijection, Word prefx) { return Bijection.DVtoRegBijection(bijection, prefx, getLeaf(prefx).getRepresentativePrefix()); @@ -701,7 +701,7 @@ private Bijection rpRegBijection(Bijection bijection, Word< /** * Convert array of {@code Register} to array of {@code DataValue} by matching {@link Register#getId()} * values to data value positions in {@code prefix}. - * + * * @param regs * @param prefix * @return @@ -719,7 +719,7 @@ private DataValue[] regsToDvs(Register[] regs, Word prefix) { * Form a {@code SymbolicSuffix} by prepending {@code v} by the last symbol of {@code u1} and {@code u2}. * The new suffix will be optimized for separating {@code u1} and {@code u2}. * Note that {@code u1} and {@code u2} must have the same last symbol. - * + * * @param u1 * @param u2 * @param v @@ -733,7 +733,7 @@ private SymbolicSuffix extendSuffix(Word u1, Word ua) { } /** - * + * * @param a * @param b * @return array of registers in {@code a} and {@code b} which are not mapped the same @@ -796,7 +796,7 @@ private void buildTreeString(StringBuilder builder, CTNode node, String currentI } } } - + private static List outputSuffixes(ParameterizedSymbol[] inputs) { List ret = new ArrayList<>(); for (ParameterizedSymbol ps : inputs) { diff --git a/src/main/java/de/learnlib/ralib/ct/MemorableSet.java b/src/main/java/de/learnlib/ralib/ct/MemorableSet.java index 52074d43..f04dd616 100644 --- a/src/main/java/de/learnlib/ralib/ct/MemorableSet.java +++ b/src/main/java/de/learnlib/ralib/ct/MemorableSet.java @@ -7,7 +7,7 @@ /** * A set of memorable data values - * + * * @author fredrik */ public class MemorableSet extends LinkedHashSet { diff --git a/src/main/java/de/learnlib/ralib/ct/Prefix.java b/src/main/java/de/learnlib/ralib/ct/Prefix.java index 667d4e61..a1cafbf5 100644 --- a/src/main/java/de/learnlib/ralib/ct/Prefix.java +++ b/src/main/java/de/learnlib/ralib/ct/Prefix.java @@ -27,7 +27,7 @@ * the SDTs along the path are equivalent to those of the leaf's representative prefix * (the RP bijection). If this prefix is the representative prefix, the RP bijection * should be the identity mapping. - * + * * @author fredrik * @see CTLeaf * @see CTPath diff --git a/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java b/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java index a165b36b..5af23ae6 100644 --- a/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java +++ b/src/main/java/de/learnlib/ralib/ct/ShortPrefix.java @@ -2,22 +2,19 @@ import java.util.LinkedHashMap; import java.util.Map; -import java.util.Set; import de.learnlib.ralib.data.Bijection; import de.learnlib.ralib.data.DataValue; import de.learnlib.ralib.oracles.Branching; import de.learnlib.ralib.oracles.TreeOracle; import de.learnlib.ralib.theory.SDT; -import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; -import net.automatalib.word.Word; /** * Data structure for storing branching information of a short prefix, * in addition to the SDTs from the suffixes along its path stored * in {@link Prefix}. - * + * * @author fredrik */ public class ShortPrefix extends Prefix { diff --git a/src/main/java/de/learnlib/ralib/oracles/Branching.java b/src/main/java/de/learnlib/ralib/oracles/Branching.java index 9388c89d..a7024614 100644 --- a/src/main/java/de/learnlib/ralib/oracles/Branching.java +++ b/src/main/java/de/learnlib/ralib/oracles/Branching.java @@ -43,7 +43,7 @@ public interface Branching { /** * Return a prefix {@code u} within this branching such that the parameters of the last * symbol of {@code u} satisfy {@code guard}. - * + * * @param guard * @param solver * @return an {@code Optional} encasing a prefix matching {@code guard} if one exists, diff --git a/src/main/java/de/learnlib/ralib/theory/Theory.java b/src/main/java/de/learnlib/ralib/theory/Theory.java index c21dc76b..43789495 100644 --- a/src/main/java/de/learnlib/ralib/theory/Theory.java +++ b/src/main/java/de/learnlib/ralib/theory/Theory.java @@ -103,7 +103,7 @@ DataValue instantiate(Word prefix, /** * Instantiate a representative data value for the parameter {@code param} * of {@code ps} that satisfies {@code guard}. - * + * * @param prefix * @param ps * @param guard diff --git a/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java b/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java index f2f19c49..81d8af26 100644 --- a/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java +++ b/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java @@ -5,7 +5,6 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; From 0d7dbcc7a7518e7651a5cc028e45a865f4a817c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Tue, 11 Nov 2025 15:06:44 +0100 Subject: [PATCH 17/31] fix mistake in ClassificationTree::suffixRevealsNewGuard --- src/main/java/de/learnlib/ralib/ct/CTLeaf.java | 1 - src/main/java/de/learnlib/ralib/ct/ClassificationTree.java | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/ct/CTLeaf.java b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java index 4ad72915..10621ed6 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTLeaf.java +++ b/src/main/java/de/learnlib/ralib/ct/CTLeaf.java @@ -188,7 +188,6 @@ public Bijection getRemapping(PrefixContainer r) { */ @Override public Branching getBranching(ParameterizedSymbol action) { - // FIXME: should get branching from a short prefix if representative prefix is not short assert rp instanceof ShortPrefix : "Representative prefix is not a short prefix"; return ((ShortPrefix) rp).getBranching(action); } diff --git a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java index 310c9470..3f25cb59 100644 --- a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java +++ b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java @@ -673,7 +673,8 @@ private SymbolicSuffix extendSuffix(Word ua, SymbolicSuffix v, * @return {@code true} if {@code av} reveals additional guards */ private boolean suffixRevealsNewGuard(SymbolicSuffix av, CTLeaf leaf) { - Word u = leaf.getRepresentativePrefix(); + assert !leaf.getShortPrefixes().isEmpty() : "No short prefix in leaf " + leaf; + Word u = leaf.getShortPrefixes().iterator().next(); SDT sdt = oracle.treeQuery(u, av); ParameterizedSymbol a = av.getActions().firstSymbol(); Branching branching = leaf.getBranching(a); From 9e4a6619f9bde15710d56b1b8ae9e7556f135d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Wed, 12 Nov 2025 12:19:48 +0100 Subject: [PATCH 18/31] add test case for issue #78 --- .../example/list/ArrayListDataWordOracle.java | 59 ++++++++++++ .../ralib/example/list/ArrayListWrapper.java | 36 ++++++++ .../learning/ralambda/LearnArrayList.java | 90 +++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 src/test/java/de/learnlib/ralib/example/list/ArrayListDataWordOracle.java create mode 100644 src/test/java/de/learnlib/ralib/example/list/ArrayListWrapper.java create mode 100644 src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayList.java diff --git a/src/test/java/de/learnlib/ralib/example/list/ArrayListDataWordOracle.java b/src/test/java/de/learnlib/ralib/example/list/ArrayListDataWordOracle.java new file mode 100644 index 00000000..2b7d0a0a --- /dev/null +++ b/src/test/java/de/learnlib/ralib/example/list/ArrayListDataWordOracle.java @@ -0,0 +1,59 @@ +package de.learnlib.ralib.example.list; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.function.Supplier; + +import de.learnlib.query.Query; +import de.learnlib.ralib.data.DataType; +import de.learnlib.ralib.oracles.DataWordOracle; +import de.learnlib.ralib.words.InputSymbol; +import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import net.automatalib.word.Word; + +public class ArrayListDataWordOracle implements DataWordOracle { + public static final DataType TYPE = new DataType("int"); + + public static final InputSymbol ADD = new InputSymbol("add", TYPE); + public static final InputSymbol REMOVE = new InputSymbol("remove", TYPE); + + private final Supplier factory; + + public ArrayListDataWordOracle(Supplier factory) { + this.factory = factory; + } + + @Override + public void processQueries(Collection> queries) { + for (Query query : queries) { + query.answer(answer(query.getInput())); + } + } + + private boolean answer(Word w) { + ArrayListWrapper list = factory.get(); + for (PSymbolInstance psi : w) { + try { + if (!accepts(psi, list)) { + return false; + } + } catch(Exception ignore) { + return false; + } + } + return true; + } + + private boolean accepts(PSymbolInstance psi, ArrayListWrapper list) { + ParameterizedSymbol ps = psi.getBaseSymbol(); + BigDecimal val = psi.getParameterValues()[0].getValue(); + if (ps.equals(ADD)) { + return list.add(val); + } + if (ps.equals(REMOVE)) { + return list.remove(val); + } + return false; + } +} diff --git a/src/test/java/de/learnlib/ralib/example/list/ArrayListWrapper.java b/src/test/java/de/learnlib/ralib/example/list/ArrayListWrapper.java new file mode 100644 index 00000000..1a96501e --- /dev/null +++ b/src/test/java/de/learnlib/ralib/example/list/ArrayListWrapper.java @@ -0,0 +1,36 @@ +package de.learnlib.ralib.example.list; + +import java.math.BigDecimal; +import java.util.ArrayList; + +public class ArrayListWrapper { + public static final int DEFAULT_MAX_CAPACITY = 3; + + private final ArrayList list; + private final int capacity; + + public ArrayListWrapper(int capacity) { + this.capacity = capacity; + this.list = new ArrayList<>(); + } + + public ArrayListWrapper() { + this(DEFAULT_MAX_CAPACITY); + } + + public boolean add(BigDecimal e) { + if (list.size() < capacity) { + list.add(e); + return true; + } + return false; + } + + public boolean remove(BigDecimal e) { + if (list.contains(e)) { + list.remove(e); + return true; + } + return false; + } +} diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayList.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayList.java new file mode 100644 index 00000000..56b6d6b9 --- /dev/null +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayList.java @@ -0,0 +1,90 @@ +package de.learnlib.ralib.learning.ralambda; + +import static de.learnlib.ralib.example.list.ArrayListDataWordOracle.ADD; +import static de.learnlib.ralib.example.list.ArrayListDataWordOracle.REMOVE; +import static de.learnlib.ralib.example.list.ArrayListDataWordOracle.TYPE; + +import java.math.BigDecimal; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import de.learnlib.query.DefaultQuery; +import de.learnlib.ralib.automata.RegisterAutomaton; +import de.learnlib.ralib.data.Constants; +import de.learnlib.ralib.data.DataType; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.example.list.ArrayListDataWordOracle; +import de.learnlib.ralib.example.list.ArrayListWrapper; +import de.learnlib.ralib.learning.Hypothesis; +import de.learnlib.ralib.oracles.DataWordOracle; +import de.learnlib.ralib.oracles.SDTLogicOracle; +import de.learnlib.ralib.oracles.SimulatorOracle; +import de.learnlib.ralib.oracles.TreeOracleFactory; +import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; +import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; +import de.learnlib.ralib.smt.ConstraintSolver; +import de.learnlib.ralib.theory.Theory; +import de.learnlib.ralib.tools.theories.DoubleInequalityTheory; +import de.learnlib.ralib.words.PSymbolInstance; +import net.automatalib.word.Word; + +public class LearnArrayList { + + @Test + public void testLearnArrayList() { + DataWordOracle oracle = new ArrayListDataWordOracle(() -> new ArrayListWrapper()); + + final Map teachers = new LinkedHashMap<>(); + teachers.put(TYPE, new DoubleInequalityTheory(TYPE)); + + ConstraintSolver solver = new ConstraintSolver(); + Constants consts = new Constants(); + MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(oracle, teachers, consts, solver); + + SDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); + + TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> + new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); + + SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, false, solver, ADD, REMOVE); + learner.learn(); + + // round 1: find all locations + Word ce = Word.fromSymbols( + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.ONE)), + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.valueOf(2))), + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.valueOf(3))), + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.valueOf(4)))); + learner.addCounterexample(new DefaultQuery<>(ce, false)); + learner.learn(); + + // round 2: find remove after three adds + ce = Word.fromSymbols( + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.ONE)), + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.valueOf(2))), + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.valueOf(3))), + new PSymbolInstance(REMOVE, new DataValue(TYPE, BigDecimal.valueOf(3)))); + learner.addCounterexample(new DefaultQuery<>(ce, true)); + learner.learn(); + + // possible round 3: ordering of data values + ce = Word.fromSymbols( + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.valueOf(3))), + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.valueOf(2))), + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.ONE)), + new PSymbolInstance(REMOVE, new DataValue(TYPE, BigDecimal.valueOf(2)))); + Hypothesis hyp = learner.getHypothesis(); + if (!hyp.accepts(ce)) { + learner.addCounterexample(new DefaultQuery<>(ce, true)); + learner.learn(); + hyp = learner.getHypothesis(); + } + + Assert.assertTrue(hyp.accepts(ce)); + + Assert.assertEquals(hyp.getStates().size(), 5); + } +} From 422a5a60a201ecde1dc65d2e0c89fa84296ad133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Wed, 12 Nov 2025 12:30:45 +0100 Subject: [PATCH 19/31] rename test so it runs automatically --- .../ralambda/{LearnArrayList.java => LearnArrayListTest.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/java/de/learnlib/ralib/learning/ralambda/{LearnArrayList.java => LearnArrayListTest.java} (100%) diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayList.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java similarity index 100% rename from src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayList.java rename to src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java From 392c6a2e2ad701b6a172c96cf6c845f2e4a51b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Wed, 12 Nov 2025 12:32:55 +0100 Subject: [PATCH 20/31] attempt number 2 at renaming test --- .../de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java index 56b6d6b9..f06847c2 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java @@ -31,7 +31,7 @@ import de.learnlib.ralib.words.PSymbolInstance; import net.automatalib.word.Word; -public class LearnArrayList { +public class LearnArrayListTest { @Test public void testLearnArrayList() { From 1b5d55be47352650a6a9b09e9ad9c437d24667e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Wed, 12 Nov 2025 13:49:44 +0100 Subject: [PATCH 21/31] fix ineq theory guard merging bug --- .../inequality/InequalityTheoryWithEq.java | 25 ++++++++++++++----- .../theory/inequality/IneqGuardMergeTest.java | 21 ++++++++-------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java index 9604a195..e5083170 100644 --- a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java +++ b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java @@ -201,11 +201,13 @@ private List sort(Collection list) { * @param sdts - a mapping from SDT guards to their corresponding sub-SDTs * @param equivClasses - a mapping from data values to corresponding SDT guards * @param filteredOut - data values removed through suffix optimization + * @param prior - suffix valuation for prior suffix values * @return a mapping from merged SDT guards to their respective sub-trees */ protected Map mergeGuards(Map sdts, Map equivClasses, - Collection filteredOut) { + Collection filteredOut, + SuffixValuation prior) { Map merged = new LinkedHashMap<>(); List ecValuesSorted = sort(equivClasses.keySet()); @@ -244,10 +246,10 @@ protected Map mergeGuards(Map sdts, currSdt = nextSdt; continue; } else { - if (equivalentWithRenaming(currSdt, currGuard, nextSdt, nextGuard)) { + if (equivalentWithRenaming(currSdt, currGuard, nextSdt, nextGuard, prior)) { // if left guard is equality, check for equality with previous guard if (currGuard instanceof SDTGuard.EqualityGuard && prevGuard != null && - !equivalentWithRenaming(prevSdt, prevGuard, nextSdt, nextGuard)) { + !equivalentWithRenaming(prevSdt, prevGuard, nextSdt, nextGuard, prior)) { keepMerging = false; } } else { @@ -301,9 +303,10 @@ protected Map mergeGuards(Map sdts, * @param guard1 * @param sdt2 * @param guard2 + * @param prior * @return true if sdt1 is equivalent to sdt2, or can be under equality guard2, or vice versa */ - private boolean equivalentWithRenaming(SDT sdt1, SDTGuard guard1, SDT sdt2, SDTGuard guard2) { + private boolean equivalentWithRenaming(SDT sdt1, SDTGuard guard1, SDT sdt2, SDTGuard guard2, SuffixValuation prior) { if (guard1 != null && guard1 instanceof SDTGuard.EqualityGuard) { Expression renaming = SDTGuard.toExpr(guard1); return sdt1.isEquivalentUnderCondition(sdt2, renaming); @@ -311,7 +314,17 @@ private boolean equivalentWithRenaming(SDT sdt1, SDTGuard guard1, SDT sdt2, SDTG Expression renaming = SDTGuard.toExpr(guard2); return sdt2.isEquivalentUnderCondition(sdt1, renaming); } - return sdt1.isEquivalent(sdt2, new Bijection<>()); + + // constrain suffix values + Expression guard1Expr = SDTGuard.toExpr(guard1); + Expression guard2Expr = SDTGuard.toExpr(guard2); + Expression condition = ExpressionUtil.or(guard1Expr, guard2Expr); + for (Map.Entry e : prior.entrySet()) { + Expression expr = new NumericBooleanExpression(e.getKey(), NumericComparator.EQ, e.getValue()); + condition = ExpressionUtil.and(condition, expr); + } + + return sdt1.isEquivalentUnderCondition(sdt2, condition); } /** @@ -442,7 +455,7 @@ public SDT treeQuery(Word prefix, Collection filteredOut = new ArrayList<>(); filteredOut.addAll(equivClasses.keySet()); filteredOut.removeAll(filteredEquivClasses.keySet()); - Map merged = mergeGuards(children, equivClasses, filteredOut); + Map merged = mergeGuards(children, equivClasses, filteredOut, suffixValues); Map reversed = new LinkedHashMap<>(); List keys = new ArrayList<>(merged.keySet()); diff --git a/src/test/java/de/learnlib/ralib/theory/inequality/IneqGuardMergeTest.java b/src/test/java/de/learnlib/ralib/theory/inequality/IneqGuardMergeTest.java index 04e5895e..c0fc718c 100644 --- a/src/test/java/de/learnlib/ralib/theory/inequality/IneqGuardMergeTest.java +++ b/src/test/java/de/learnlib/ralib/theory/inequality/IneqGuardMergeTest.java @@ -12,6 +12,7 @@ import de.learnlib.ralib.RaLibTestSuite; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.SuffixValuation; import de.learnlib.ralib.data.SymbolicDataValue.Register; import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.RegisterGenerator; @@ -81,7 +82,7 @@ public void testIntervalMerge() { expected1.put(new SDTGuard.IntervalGuard(s1, r1, r3), SDTLeaf.REJECTING); expected1.put(SDTGuard.IntervalGuard.greaterOrEqualGuard(s1, r3), SDTLeaf.ACCEPTING); - Map actual1 = dit.mergeGuards(sdts1, equivClasses, new ArrayList()); + Map actual1 = dit.mergeGuards(sdts1, equivClasses, new ArrayList(), new SuffixValuation()); Assert.assertEquals(actual1.size(), expected1.size()); Assert.assertTrue(actual1.entrySet().containsAll(expected1.entrySet())); @@ -101,7 +102,7 @@ public void testIntervalMerge() { expected2.put(new SDTGuard.IntervalGuard(s1, r2, r3, true, true), SDTLeaf.REJECTING); expected2.put(g6, SDTLeaf.ACCEPTING); - Map actual2 = dit.mergeGuards(sdts2, equivClasses, new ArrayList()); + Map actual2 = dit.mergeGuards(sdts2, equivClasses, new ArrayList(), new SuffixValuation()); Assert.assertEquals(actual2.size(), expected2.size()); Assert.assertTrue(actual2.entrySet().containsAll(expected2.entrySet())); @@ -122,7 +123,7 @@ public void testIntervalMerge() { expected3.put(new SDTGuard.IntervalGuard(s1, r1, r2, false, true), SDTLeaf.ACCEPTING); expected3.put(SDTGuard.IntervalGuard.greaterGuard(s1, r2), SDTLeaf.REJECTING); - Map actual3 = dit.mergeGuards(sdts3, equivClasses, new ArrayList()); + Map actual3 = dit.mergeGuards(sdts3, equivClasses, new ArrayList(), new SuffixValuation()); Assert.assertEquals(actual3.size(), expected3.size()); Assert.assertTrue(actual3.entrySet().containsAll(expected3.entrySet())); @@ -145,7 +146,7 @@ public void testIntervalMerge() { expected4.put(g5, SDTLeaf.ACCEPTING); expected4.put(g6, SDTLeaf.REJECTING); - Map actual4 = dit.mergeGuards(sdts4, equivClasses, new ArrayList()); + Map actual4 = dit.mergeGuards(sdts4, equivClasses, new ArrayList(), new SuffixValuation()); Assert.assertEquals(actual4.size(), expected4.size()); Assert.assertTrue(actual4.entrySet().containsAll(expected4.entrySet())); @@ -193,7 +194,7 @@ public void testTrueGuard() { sdts1.put(g3, SDTLeaf.ACCEPTING); sdts1.put(g4, SDTLeaf.ACCEPTING); - Map merged = dit.mergeGuards(sdts1, equivClasses, new ArrayList<>()); + Map merged = dit.mergeGuards(sdts1, equivClasses, new ArrayList<>(), new SuffixValuation()); Assert.assertEquals(merged.size(), 1); Assert.assertTrue(merged.containsKey(new SDTGuard.SDTTrueGuard(s1))); @@ -256,7 +257,7 @@ public void testFilteredDataValues() { expected.put(new SDTGuard.IntervalGuard(s1, r1, r2, true, false), SDTLeaf.ACCEPTING); expected.put(g5, SDTLeaf.REJECTING); - Map actual = dit.mergeGuards(sdts, equivClasses, filtered); + Map actual = dit.mergeGuards(sdts, equivClasses, filtered, new SuffixValuation()); Assert.assertEquals(actual.size(), expected.size()); Assert.assertTrue(actual.entrySet().containsAll(expected.entrySet())); @@ -318,7 +319,7 @@ public void testSDTSubtree() { expected.put(new SDTGuard.IntervalGuard(s1, r1, r2, false, true), subSdt2); expected.put(g4, subSdt3); - Map actual = dit.mergeGuards(sdts, equivClasses, new ArrayList<>()); + Map actual = dit.mergeGuards(sdts, equivClasses, new ArrayList<>(), new SuffixValuation()); Assert.assertEquals(actual.size(), expected.size()); Assert.assertTrue(actual.entrySet().containsAll(expected.entrySet())); @@ -372,7 +373,7 @@ public void testDisequalityGuard() { Map expected1 = new LinkedHashMap<>(); expected1.put(new SDTGuard.SDTTrueGuard(s1), SDTLeaf.REJECTING); - Map actual1 = dit.mergeGuards(sdts1, equivClasses, filteredOut); + Map actual1 = dit.mergeGuards(sdts1, equivClasses, filteredOut, new SuffixValuation()); Assert.assertEquals(actual1.size(), expected1.size()); Assert.assertTrue(actual1.entrySet().containsAll(expected1.entrySet())); @@ -383,7 +384,7 @@ public void testDisequalityGuard() { Map expected2 = new LinkedHashMap<>(); expected2.put(new SDTGuard.DisequalityGuard(s1, r1), SDTLeaf.REJECTING); expected2.put(g1, SDTLeaf.ACCEPTING); - Map actual2 = dit.mergeGuards(sdts2, equivClasses, new ArrayList<>()); + Map actual2 = dit.mergeGuards(sdts2, equivClasses, new ArrayList<>(), new SuffixValuation()); Assert.assertEquals(actual2.size(), expected2.size()); Assert.assertTrue(actual2.entrySet().containsAll(expected2.entrySet())); @@ -411,7 +412,7 @@ public void testDisequalityGuard() { expected3.put(new SDTGuard.IntervalGuard(s1, null, r2), sdt1); expected3.put(g3, sdt2); expected3.put(g4, sdt3); - Map actual3 = dit.mergeGuards(sdts3, equivClasses, new ArrayList<>()); + Map actual3 = dit.mergeGuards(sdts3, equivClasses, new ArrayList<>(), new SuffixValuation()); Assert.assertEquals(actual3.size(), expected3.size()); Assert.assertTrue(actual3.entrySet().containsAll(expected3.entrySet())); From 63a02bdb71e45144fbc2cdddbb0a0931b33f20bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Fri, 14 Nov 2025 11:26:08 +0100 Subject: [PATCH 22/31] add test case revealing bug --- .../ralib/theory/TestSDTEquivalence.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/test/java/de/learnlib/ralib/theory/TestSDTEquivalence.java diff --git a/src/test/java/de/learnlib/ralib/theory/TestSDTEquivalence.java b/src/test/java/de/learnlib/ralib/theory/TestSDTEquivalence.java new file mode 100644 index 00000000..48ebb274 --- /dev/null +++ b/src/test/java/de/learnlib/ralib/theory/TestSDTEquivalence.java @@ -0,0 +1,49 @@ +package de.learnlib.ralib.theory; + +import java.math.BigDecimal; +import java.util.Map; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import de.learnlib.ralib.data.Bijection; +import de.learnlib.ralib.data.DataType; +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.SDTRelabeling; +import de.learnlib.ralib.data.SymbolicDataValue.Register; +import de.learnlib.ralib.data.SymbolicDataValue.SuffixValue; +import de.learnlib.ralib.theory.SDTGuard.EqualityGuard; +import de.learnlib.ralib.theory.SDTGuard.IntervalGuard; + +public class TestSDTEquivalence { + + @Test + public void testSelfEquivalenceIneqTheory() { + DataType type = new DataType("double"); + SuffixValue s1 = new SuffixValue(type, 1); + Register r1 = new Register(type, 1); + Register r2 = new Register(type, 2); + + SDT sdt = new SDT(Map.of( + IntervalGuard.greaterGuard(s1, r2), SDTLeaf.REJECTING, + new EqualityGuard(s1, r2), SDTLeaf.ACCEPTING, + new IntervalGuard(s1, r1, r2), SDTLeaf.REJECTING, + new EqualityGuard(s1, r1), SDTLeaf.ACCEPTING, + IntervalGuard.lessGuard(s1, r1), SDTLeaf.REJECTING)); + + Assert.assertTrue(SDT.equivalentUnderId(sdt, sdt)); + + DataValue d0 = new DataValue(type, BigDecimal.ZERO); + DataValue d1 = new DataValue(type, BigDecimal.ONE); + SDTRelabeling relabeling = new SDTRelabeling(); + relabeling.put(r1, d0); + relabeling.put(r2, d1); + Bijection expected = new Bijection<>(); + expected.put(d0, d0); + expected.put(d1, d1); + + SDT sdtDv = sdt.relabel(relabeling); + Bijection actual = SDT.equivalentUnderBijection(sdtDv, sdtDv); + Assert.assertEquals(actual, expected); + } +} From 0519bc892aff88e8a94ff2b623e22ac54b8a6420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Fri, 14 Nov 2025 11:30:24 +0100 Subject: [PATCH 23/31] fix bug with comparing sdts using inequality theory --- src/main/java/de/learnlib/ralib/theory/SDT.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/theory/SDT.java b/src/main/java/de/learnlib/ralib/theory/SDT.java index 371e75e0..4d9bdc37 100644 --- a/src/main/java/de/learnlib/ralib/theory/SDT.java +++ b/src/main/java/de/learnlib/ralib/theory/SDT.java @@ -29,6 +29,7 @@ import de.learnlib.ralib.words.DataWords; import de.learnlib.ralib.words.PSymbolInstance; import gov.nasa.jpf.constraints.api.Expression; +import gov.nasa.jpf.constraints.expressions.Negation; import gov.nasa.jpf.constraints.util.ExpressionUtil; import net.automatalib.word.Word; @@ -438,6 +439,13 @@ public boolean isEquivalentUnderCondition(SDT other, Expression conditi for (Map.Entry, Boolean> entry : expressions.entrySet()) { Expression x = entry.getKey(); Boolean outcome = entry.getValue(); + + Set> guardComplement = new LinkedHashSet<>(expressions.keySet()); + guardComplement.remove(x); + for (Expression g : guardComplement) { + x = ExpressionUtil.and(x, new Negation(g)); + } + for (Map.Entry, Boolean> otherEntry : otherExpressions.entrySet()) { if (outcome != otherEntry.getValue()) { Expression otherX = otherEntry.getKey(); @@ -445,7 +453,6 @@ public boolean isEquivalentUnderCondition(SDT other, Expression conditi Expression con = ExpressionUtil.and(x, renamed); ConstraintSolver solver = new ConstraintSolver(); if (solver.isSatisfiable(con, new Mapping<>())) { - return false; } } @@ -473,10 +480,6 @@ public static Bijection equivalentUnderBijection(SDT sdt1, SDT sdt2, return null; } - if (new HashSet<>(regs1).containsAll(regs2)) { - return sdt1.isEquivalentUnderCondition(sdt2, ExpressionUtil.TRUE) ? bi : null; - } - Set replace = new LinkedHashSet<>(regs1); replace.removeAll(bi.values()); Set by = new LinkedHashSet<>(regs2); From dd2105c9de9dc9fd5939bf17c254b540e4e6a8f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Sat, 15 Nov 2025 12:39:32 +0100 Subject: [PATCH 24/31] add test revealing non-determinacy bug --- .../list/ArrayListIODataWordOracle.java | 88 +++++++++++++++++++ .../learning/ralambda/LearnArrayListTest.java | 63 +++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 src/test/java/de/learnlib/ralib/example/list/ArrayListIODataWordOracle.java diff --git a/src/test/java/de/learnlib/ralib/example/list/ArrayListIODataWordOracle.java b/src/test/java/de/learnlib/ralib/example/list/ArrayListIODataWordOracle.java new file mode 100644 index 00000000..3871b2ed --- /dev/null +++ b/src/test/java/de/learnlib/ralib/example/list/ArrayListIODataWordOracle.java @@ -0,0 +1,88 @@ +package de.learnlib.ralib.example.list; + +import static de.learnlib.ralib.example.list.ArrayListDataWordOracle.ADD; +import static de.learnlib.ralib.example.list.ArrayListDataWordOracle.REMOVE; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Optional; +import java.util.function.Supplier; + +import de.learnlib.query.Query; +import de.learnlib.ralib.oracles.DataWordOracle; +import de.learnlib.ralib.words.InputSymbol; +import de.learnlib.ralib.words.OutputSymbol; +import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import net.automatalib.word.Word; + +public class ArrayListIODataWordOracle implements DataWordOracle { + + public static final OutputSymbol VOID = new OutputSymbol("void"); + public static final OutputSymbol TRUE = new OutputSymbol("true"); + public static final OutputSymbol FALSE = new OutputSymbol("false"); + + private final Supplier factory; + + public ArrayListIODataWordOracle(Supplier factory) { + this.factory = factory; + } + + @Override + public void processQueries(Collection> queries) { + for (Query query : queries) { + query.answer(answer(query.getInput())); + } + } + + private boolean answer(Word query) { + if (query.size() < 1) { + return true; + } + if (!isValid(query)) { + return false; + } + + ArrayListWrapper list = factory.get(); + + Optional expectedOutput = Optional.empty(); + for (PSymbolInstance psi : query) { + if (expectedOutput.isEmpty()) { + expectedOutput = Optional.of(answer(psi, list)); + } else { + if (!psi.getBaseSymbol().equals(expectedOutput.get())) { + return false; + } + expectedOutput = Optional.empty(); + } + } + return true; + } + + private OutputSymbol answer(PSymbolInstance in, ArrayListWrapper list) { + ParameterizedSymbol symbol = in.getBaseSymbol(); + if (!(symbol instanceof InputSymbol || symbol.equals(ADD) || symbol.equals(REMOVE))) { + throw new IllegalArgumentException("Not a valid input symbol: " + symbol); + } + + BigDecimal val = in.getParameterValues()[0].getValue(); + + if (symbol.equals(ADD)) { + list.add(val); + return VOID; + } + return list.remove(val) ? TRUE : FALSE; + } + + private boolean isValid(Word query) { + boolean inExpected = true; + for (PSymbolInstance psi : query) { + ParameterizedSymbol symbol = psi.getBaseSymbol(); + if (inExpected ^ (symbol instanceof InputSymbol)) { + return false; + } + inExpected = !inExpected; + } + return true; + } +} diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java index f06847c2..f11affba 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java @@ -3,6 +3,9 @@ import static de.learnlib.ralib.example.list.ArrayListDataWordOracle.ADD; import static de.learnlib.ralib.example.list.ArrayListDataWordOracle.REMOVE; import static de.learnlib.ralib.example.list.ArrayListDataWordOracle.TYPE; +import static de.learnlib.ralib.example.list.ArrayListIODataWordOracle.FALSE; +import static de.learnlib.ralib.example.list.ArrayListIODataWordOracle.TRUE; +import static de.learnlib.ralib.example.list.ArrayListIODataWordOracle.VOID; import java.math.BigDecimal; import java.util.LinkedHashMap; @@ -17,6 +20,7 @@ import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; import de.learnlib.ralib.example.list.ArrayListDataWordOracle; +import de.learnlib.ralib.example.list.ArrayListIODataWordOracle; import de.learnlib.ralib.example.list.ArrayListWrapper; import de.learnlib.ralib.learning.Hypothesis; import de.learnlib.ralib.oracles.DataWordOracle; @@ -87,4 +91,63 @@ public void testLearnArrayList() { Assert.assertEquals(hyp.getStates().size(), 5); } + + @Test + public void testArrayListNonDeterminacy() { + DataWordOracle oracle = new ArrayListIODataWordOracle(() -> new ArrayListWrapper(4)); + + final Map teachers = new LinkedHashMap<>(); + teachers.put(TYPE, new DoubleInequalityTheory(TYPE)); + ConstraintSolver solver = new ConstraintSolver(); + Constants consts = new Constants(); + MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(oracle, teachers, consts, solver); + SDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); + TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> + new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); + + SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, ADD, REMOVE, VOID, TRUE, FALSE); + learner.learn(); + + Word ce = Word.fromSymbols( + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.ONE)), + new PSymbolInstance(VOID), + new PSymbolInstance(REMOVE, new DataValue(TYPE, BigDecimal.ONE)), + new PSymbolInstance(TRUE)); + learner.addCounterexample(new DefaultQuery<>(ce, true)); + learner.learn(); + + ce = Word.fromSymbols( + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.ONE)), + new PSymbolInstance(VOID), + new PSymbolInstance(REMOVE, new DataValue(TYPE, BigDecimal.valueOf(-1))), + new PSymbolInstance(FALSE), + new PSymbolInstance(REMOVE, new DataValue(TYPE, BigDecimal.ONE)), + new PSymbolInstance(TRUE)); + learner.addCounterexample(new DefaultQuery<>(ce, true)); + learner.learn(); + + ce = Word.fromSymbols( + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.ONE)), + new PSymbolInstance(VOID), + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.valueOf(2))), + new PSymbolInstance(VOID), + new PSymbolInstance(REMOVE, new DataValue(TYPE, BigDecimal.valueOf(2))), + new PSymbolInstance(TRUE), + new PSymbolInstance(REMOVE, new DataValue(TYPE, BigDecimal.ONE)), + new PSymbolInstance(TRUE)); + learner.addCounterexample(new DefaultQuery<>(ce, true)); + learner.learn(); + + ce = Word.fromSymbols( + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.ONE)), + new PSymbolInstance(VOID), + new PSymbolInstance(ADD, new DataValue(TYPE, BigDecimal.ZERO)), + new PSymbolInstance(VOID), + new PSymbolInstance(REMOVE, new DataValue(TYPE, BigDecimal.ZERO)), + new PSymbolInstance(TRUE)); + learner.addCounterexample(new DefaultQuery<>(ce, true)); + learner.learn(); + + Assert.assertTrue(learner.getHypothesis().accepts(ce)); + } } From c65f8f1fa72d6232d4c0df4dcb89ba55fbc1894d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Sat, 15 Nov 2025 12:48:00 +0100 Subject: [PATCH 25/31] include ra transitions in ra run --- .../automata/MutableRegisterAutomaton.java | 38 +------------ .../de/learnlib/ralib/automata/RARun.java | 56 +++++++++++++++---- .../ralib/ceanalysis/PrefixFinder.java | 42 +++----------- .../de/learnlib/ralib/ct/CTHypothesis.java | 44 ++++++++++++++- .../ralib/smt/VarsValuationVisitor.java | 26 +++++++++ .../java/de/learnlib/ralib/theory/Theory.java | 5 +- .../ralib/theory/equality/EqualityTheory.java | 9 +-- .../inequality/InequalityTheoryWithEq.java | 11 ++-- .../theories/UniqueIntegerEqualityTheory.java | 3 +- .../de/learnlib/ralib/automata/RaRunTest.java | 6 +- 10 files changed, 144 insertions(+), 96 deletions(-) create mode 100644 src/main/java/de/learnlib/ralib/smt/VarsValuationVisitor.java diff --git a/src/main/java/de/learnlib/ralib/automata/MutableRegisterAutomaton.java b/src/main/java/de/learnlib/ralib/automata/MutableRegisterAutomaton.java index 74392ab5..797f7fdd 100644 --- a/src/main/java/de/learnlib/ralib/automata/MutableRegisterAutomaton.java +++ b/src/main/java/de/learnlib/ralib/automata/MutableRegisterAutomaton.java @@ -28,7 +28,6 @@ import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; import net.automatalib.automaton.MutableDeterministic; -import net.automatalib.common.util.Pair; import net.automatalib.word.Word; /** @@ -119,39 +118,6 @@ protected List getTransitions(Word dw) { return tseq; } - protected List> getTransitionsAndValuations(Word dw) { - RegisterValuation vars = RegisterValuation.copyOf(getInitialRegisters()); - RALocation current = initial; - List> tvseq = new ArrayList<>(); - for (PSymbolInstance psi : dw) { - - ParameterValuation pars = ParameterValuation.fromPSymbolInstance(psi); - - Collection candidates = - current.getOut(psi.getBaseSymbol()); - - if (candidates == null) { - return null; - } - - boolean found = false; - for (Transition t : candidates) { - if (t.isEnabled(vars, pars, constants)) { - vars = t.execute(vars, pars, constants); - current = t.getDestination(); - tvseq.add(Pair.of(t, RegisterValuation.copyOf(vars))); - found = true; - break; - } - } - - if (!found) { - return null; - } - } - return tvseq; - } - @Override public RALocation getLocation(Word dw) { List tseq = getTransitions(dw); @@ -305,6 +271,7 @@ public RARun getRun(Word word) { RALocation[] locs = new RALocation[n+1]; RegisterValuation[] vals = new RegisterValuation[n+1]; PSymbolInstance[] symbols = new PSymbolInstance[n]; + Transition[] transitions = new Transition[n]; locs[0] = getInitialState(); vals[0] = new RegisterValuation(); @@ -322,6 +289,7 @@ public RARun getRun(Word word) { for (Transition t : candidates) { if (t.isEnabled(vals[i], pars, constants)) { + transitions[i] = t; vals[i+1] = t.execute(vals[i], pars, constants); locs[i+1] = t.getDestination(); found = true; @@ -334,7 +302,7 @@ public RARun getRun(Word word) { } } - return new RARun(locs, vals, symbols); + return new RARun(locs, vals, symbols, transitions); } } diff --git a/src/main/java/de/learnlib/ralib/automata/RARun.java b/src/main/java/de/learnlib/ralib/automata/RARun.java index 3dff5d07..ee7aa9e7 100644 --- a/src/main/java/de/learnlib/ralib/automata/RARun.java +++ b/src/main/java/de/learnlib/ralib/automata/RARun.java @@ -1,20 +1,31 @@ package de.learnlib.ralib.automata; -import java.util.ArrayList; +import java.util.Map; + +import de.learnlib.ralib.automata.output.OutputTransition; import de.learnlib.ralib.data.DataValue; import de.learnlib.ralib.data.RegisterValuation; +import de.learnlib.ralib.data.SymbolicDataValue; +import de.learnlib.ralib.data.SymbolicDataValue.Parameter; +import de.learnlib.ralib.smt.VarsValuationVisitor; import de.learnlib.ralib.words.PSymbolInstance; +import gov.nasa.jpf.constraints.api.Expression; +import gov.nasa.jpf.constraints.expressions.NumericBooleanExpression; +import gov.nasa.jpf.constraints.expressions.NumericComparator; +import gov.nasa.jpf.constraints.util.ExpressionUtil; public class RARun { private final RALocation[] locations; private final RegisterValuation[] valuations; - private final PSymbolInstance[] transitions; + private final PSymbolInstance[] symbols; + private final Transition[] transitions; - public RARun(RALocation[] locations, RegisterValuation[] valuations, PSymbolInstance[] transitions) { + public RARun(RALocation[] locations, RegisterValuation[] valuations, PSymbolInstance[] symbols, Transition[] transitions) { this.locations = locations; this.valuations = valuations; + this.symbols = symbols; this.transitions = transitions; } @@ -26,18 +37,39 @@ public RegisterValuation getValuation(int i) { return valuations[i]; } - public PSymbolInstance getTransition(int i) { + public PSymbolInstance getTransitionSymbol(int i) { + return symbols[i-1]; + } + + public Transition getRATransition(int i) { return transitions[i-1]; } - public DataValue[] getDataValues(int i) { - ArrayList vals = new ArrayList<>(); - for (int id = 0; id < i; id++) { - for (DataValue dv : transitions[id].getParameterValues()) { - vals.add(dv); - } + public Expression getGuard(int i) { + Transition transition = getRATransition(i); + if (transition == null) { + return null; + } + if (transition instanceof OutputTransition) { + return outputGuard((OutputTransition) transition, getTransitionSymbol(i)); + } + VarsValuationVisitor vvv = new VarsValuationVisitor(); + Expression guard = transition.getGuard(); + RegisterValuation val = getValuation(i); + return vvv.apply(guard, val); + } + + private Expression outputGuard(OutputTransition t, PSymbolInstance symbol) { + Expression guard = t.getGuard(); + DataValue[] vals = symbol.getParameterValues(); + for (Map.Entry e : t.getOutput().getOutput().entrySet()) { + Parameter p = e.getKey(); + SymbolicDataValue s = e.getValue(); + DataValue d = vals[p.getId()-1]; + Expression eq = new NumericBooleanExpression(s, NumericComparator.EQ, d); + guard = ExpressionUtil.and(guard, eq); } - return vals.toArray(new DataValue[vals.size()]); + return guard; } @Override @@ -50,7 +82,7 @@ public String toString() { for (int i = 1; i < locations.length; i++) { str = str + " -- " + - transitions[i-1] + + symbols[i-1] + " -- <" + locations[i] + ", " + diff --git a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java index 4730a7e6..01fa896b 100644 --- a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java +++ b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java @@ -93,16 +93,14 @@ public Result analyzeCounterExample(Word ce) { for (int i = ce.length(); i >= 1; i--) { RALocation loc = run.getLocation(i-1); RALocation locNext = run.getLocation(i); - PSymbolInstance symbol = run.getTransition(i); + PSymbolInstance symbol = run.getTransitionSymbol(i); RegisterValuation runValuation = run.getValuation(i-1); ParameterizedSymbol action = symbol.getBaseSymbol(); SymbolicSuffix vNext = new SymbolicSuffix(ce.prefix(i), ce.suffix(ce.length() - i), restrBuilder); SymbolicSuffix v = new SymbolicSuffix(ce.prefix(i-1), ce.suffix(ce.length() - i + 1), restrBuilder); - Optional> gOpt = getHypGuard(run, i); - assert gOpt.isPresent() : "No guard satisfying valuation at index " + i; - Expression gHyp = gOpt.get(); + Expression gHyp = run.getGuard(i); for (ShortPrefix u : hyp.getLeaf(loc).getShortPrefixes()) { SDT sdt = sulOracle.treeQuery(u, v); @@ -191,7 +189,7 @@ private Set> extendedValuationRenamings(SDT uSDT, // gather data values from prefix of run at index id ArrayList runVals = new ArrayList<>(); for (int i = 1; i <= id-1; i++) { - for (DataValue d : run.getTransition(i).getParameterValues()) { + for (DataValue d : run.getTransitionSymbol(i).getParameterValues()) { runVals.add(d); } } @@ -272,7 +270,12 @@ private Optional checkTransition(RALocation loc, DataType[] types = action.getPtypes(); DataValue[] reprDataVals = new DataValue[types.length]; for (int i = 0; i < types.length; i++) { - reprDataVals[i] = teachers.get(types[i]).instantiate(u, action, conjunction, i+1, consts, solver); + Optional reprDataVal = teachers.get(types[i]).instantiate(u, action, conjunction, i+1, consts, solver); + if (reprDataVal.isEmpty()) { + // guard unsat + return Optional.empty(); + } + reprDataVals[i] = reprDataVal.get(); } PSymbolInstance psi = new PSymbolInstance(action, reprDataVals); Word uExtSul = u.append(psi); @@ -343,33 +346,6 @@ private Optional checkLocation(RALocation locNext, return Optional.empty(); } - /** - * Get the guard in the hypothesis corresponding to {@code run} at index {@code idx} - * - * @param run - * @param idx - * @return - */ - private Optional> getHypGuard(RARun run, int idx) { - RALocation locNext = run.getLocation(idx); - RALocation loc = run.getLocation(idx - 1); - CTLeaf leafNext = hyp.getLeaf(locNext); - RegisterValuation hypValuation = run.getValuation(idx-1); - PSymbolInstance action = run.getTransition(idx); - ShortPrefix u = hyp.getLeaf(loc).getShortPrefixes().iterator().next(); - Mapping renaming = valuationRenaming(u, hypValuation); - for (Word ua : ct.getExtensions(u, action.getBaseSymbol())) { - if (leafNext.getPrefixes().contains(ua)) { - for (Expression g : u.getBranching(action.getBaseSymbol()).getBranches().values()) { - if (isGuardSatisfied(g, renaming, action)) { - return Optional.of(g); - } - } - } - } - return Optional.empty(); - } - /** * Check whether {@code guard} is satisfied by the parameters of {@code symbol}, after renaming * the parameters of {@code guard} according to {@code renaming}. diff --git a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java index 53869f7e..e2938965 100644 --- a/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java +++ b/src/main/java/de/learnlib/ralib/ct/CTHypothesis.java @@ -1,6 +1,8 @@ package de.learnlib.ralib.ct; import java.util.Collection; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import com.google.common.collect.BiMap; @@ -8,17 +10,23 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import de.learnlib.ralib.automata.Assignment; +import de.learnlib.ralib.automata.InputTransition; import de.learnlib.ralib.automata.RALocation; import de.learnlib.ralib.automata.RARun; import de.learnlib.ralib.automata.Transition; +import de.learnlib.ralib.automata.output.OutputMapping; import de.learnlib.ralib.automata.output.OutputTransition; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.ParameterValuation; import de.learnlib.ralib.data.RegisterValuation; +import de.learnlib.ralib.data.VarMapping; import de.learnlib.ralib.learning.Hypothesis; +import de.learnlib.ralib.words.InputSymbol; import de.learnlib.ralib.words.OutputSymbol; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; +import gov.nasa.jpf.constraints.util.ExpressionUtil; import net.automatalib.word.Word; /** @@ -88,12 +96,28 @@ public CTLeaf getLeaf(RALocation location) { return leaves.inverse().get(location); } + @Override + protected List getTransitions(Word dw) { + List tseq = new LinkedList<>(); + RARun run = getRun(dw); + for (int i = 1; i <= dw.size(); i++) { + tseq.add(run.getRATransition(i)); + } + return tseq; + } + + @Override + public RALocation getLocation(Word dw) { + return getRun(dw).getLocation(dw.size()); + } + @Override public RARun getRun(Word word) { int n = word.length(); RALocation[] locs = new RALocation[n+1]; RegisterValuation[] vals = new RegisterValuation[n+1]; PSymbolInstance[] symbols = new PSymbolInstance[n]; + Transition[] transitions = new Transition[n]; locs[0] = getInitialState(); vals[0] = new RegisterValuation(); @@ -113,6 +137,7 @@ public RARun getRun(Word word) { for (Transition t : candidates) { if (t.isEnabled(vals[i], pars, constants)) { + transitions[i] = t; vals[i+1] = t.valuation(vals[i], pars, constants); locs[i+1] = t.getDestination(); found = true; @@ -127,6 +152,7 @@ public RARun getRun(Word word) { || locs[i].equals(sink)) { vals[i+1] = new RegisterValuation(); locs[i+1] = getSink(); + transitions[i] = createSinkTransition(locs[i], locs[i+1], symbols[i].getBaseSymbol()); } } else { return null; @@ -134,6 +160,22 @@ public RARun getRun(Word word) { } } - return new RARun(locs, vals, symbols); + return new RARun(locs, vals, symbols, transitions); } + + private Transition createSinkTransition(RALocation src, RALocation dest, ParameterizedSymbol ps) { + if (ps instanceof OutputSymbol) { + return new OutputTransition(new OutputMapping(), + (OutputSymbol) ps, + src, dest, + new Assignment(new VarMapping<>())); + } + if (ps instanceof InputSymbol) { + return new InputTransition(ExpressionUtil.TRUE, + (InputSymbol) ps, + src, dest, + new Assignment(new VarMapping<>())); + } + throw new IllegalArgumentException("Not input or output symbol: " + ps); + } } diff --git a/src/main/java/de/learnlib/ralib/smt/VarsValuationVisitor.java b/src/main/java/de/learnlib/ralib/smt/VarsValuationVisitor.java new file mode 100644 index 00000000..65747c11 --- /dev/null +++ b/src/main/java/de/learnlib/ralib/smt/VarsValuationVisitor.java @@ -0,0 +1,26 @@ +package de.learnlib.ralib.smt; + +import java.util.LinkedHashMap; +import java.util.Map; + +import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.Mapping; +import de.learnlib.ralib.data.SymbolicDataValue; +import gov.nasa.jpf.constraints.api.Expression; +import gov.nasa.jpf.constraints.api.Variable; +import gov.nasa.jpf.constraints.util.DuplicatingVisitor; + +public class VarsValuationVisitor extends DuplicatingVisitor, ? extends Expression>> { + + @Override + public Expression visit(Variable v, Map, ? extends Expression> data) { + Expression val = data.get(v); + return (val != null) ? val.requireAs(v.getType()) : v; + } + + public Expression apply(Expression expr, Mapping valuation) { + Map, Expression> map = new LinkedHashMap<>(); + valuation.forEach((k,v) -> map.put(k, v.asExpression())); + return visit(expr, map).requireAs(expr.getType()); + } +} diff --git a/src/main/java/de/learnlib/ralib/theory/Theory.java b/src/main/java/de/learnlib/ralib/theory/Theory.java index 43789495..bc702328 100644 --- a/src/main/java/de/learnlib/ralib/theory/Theory.java +++ b/src/main/java/de/learnlib/ralib/theory/Theory.java @@ -19,6 +19,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import de.learnlib.ralib.data.Constants; @@ -110,9 +111,9 @@ DataValue instantiate(Word prefix, * @param param * @param constants * @param solver - * @return + * @return an {@code Optional} containing a data value satisfying {@code guard}, or an empty {@code Optional} if {@code guard} is unsatisfiable */ - public DataValue instantiate(Word prefix, + public Optional instantiate(Word prefix, ParameterizedSymbol ps, Expression guard, int param, Constants constants, ConstraintSolver solver); diff --git a/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java b/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java index 69afd6f1..53c6a857 100644 --- a/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java +++ b/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java @@ -26,6 +26,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -412,7 +413,7 @@ private SDT makeRejectingBranch(int nextSufIndex, int maxIndex, DataType type) { } @Override - public DataValue instantiate(Word prefix, + public Optional instantiate(Word prefix, ParameterizedSymbol ps, Expression guard, int param, Constants constants, ConstraintSolver solver) { Parameter p = new Parameter(ps.getPtypes()[param-1], param); @@ -424,16 +425,16 @@ public DataValue instantiate(Word prefix, DataValue fresh = getFreshValue(new LinkedList<>(vals)); if (tryEquality(guard, p, fresh, solver, constants)) { - return fresh; + return Optional.of(fresh); } for (DataValue val : vals) { if (tryEquality(guard, p, val, solver, constants)) { - return val; + return Optional.of(val); } } - throw new IllegalArgumentException("Guard is not equality/disequality: " + guard); + return Optional.empty(); } private boolean tryEquality(Expression guard, Parameter p, DataValue val, ConstraintSolver solver, Constants consts) { diff --git a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java index e5083170..3f89fbd8 100644 --- a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java +++ b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java @@ -623,7 +623,7 @@ public DataValue instantiate( return returnThis; } - public DataValue instantiate(Word prefix, + public Optional instantiate(Word prefix, ParameterizedSymbol ps, Expression guard, int param, Constants constants, ConstraintSolver solver) { Parameter p = new Parameter(ps.getPtypes()[param-1], param); @@ -634,7 +634,7 @@ public DataValue instantiate(Word prefix, DataValue fresh = getFreshValue(new LinkedList<>(vals)); if (tryEquality(guard, p, fresh, solver)) { - return fresh; + return Optional.of(fresh); } List> diseqList = new LinkedList<>(); @@ -645,16 +645,17 @@ public DataValue instantiate(Word prefix, if (valuation.isPresent()) { BigDecimal dv = valuation.get().getValue(p); assert dv != null : "No valuation for " + p + " in " + valuation; - return new DataValue(p.getDataType(), dv); + DataValue ret = new DataValue(p.getDataType(), dv); + return Optional.of(ret); } for (DataValue val : vals) { if (tryEquality(guard, p, val, solver)) { - return val; + return Optional.of(val); } } - throw new IllegalArgumentException("Not a valid guard: " + guard); + return Optional.empty(); } private boolean tryEquality(Expression guard, Parameter p, DataValue val, ConstraintSolver solver) { diff --git a/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java b/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java index 81d8af26..af7fd026 100644 --- a/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java +++ b/src/main/java/de/learnlib/ralib/tools/theories/UniqueIntegerEqualityTheory.java @@ -5,6 +5,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Optional; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; @@ -67,7 +68,7 @@ public Collection getAllNextValues(List vals) { } @Override - public DataValue instantiate(Word prefix, + public Optional instantiate(Word prefix, ParameterizedSymbol ps, Expression guard, int param, Constants constants, ConstraintSolver solver) { throw new RuntimeException("Not implemented"); diff --git a/src/test/java/de/learnlib/ralib/automata/RaRunTest.java b/src/test/java/de/learnlib/ralib/automata/RaRunTest.java index e5dc7b87..e948516c 100644 --- a/src/test/java/de/learnlib/ralib/automata/RaRunTest.java +++ b/src/test/java/de/learnlib/ralib/automata/RaRunTest.java @@ -73,8 +73,8 @@ public void testMutableRARun() { Assert.assertEquals(run.getValuation(1).get(r1), dv1); Assert.assertEquals(run.getValuation(3).get(r1), dv2); - Assert.assertEquals(run.getTransition(1), psi1); - Assert.assertEquals(run.getTransition(2), psi1); - Assert.assertEquals(run.getTransition(3), psi2); + Assert.assertEquals(run.getTransitionSymbol(1), psi1); + Assert.assertEquals(run.getTransitionSymbol(2), psi1); + Assert.assertEquals(run.getTransitionSymbol(3), psi2); } } From 64cc63118b44eebae50eb151db5950ede169224b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Sat, 15 Nov 2025 12:54:14 +0100 Subject: [PATCH 26/31] remove unused methods --- .../learnlib/ralib/learning/Hypothesis.java | 52 ------------------- 1 file changed, 52 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/learning/Hypothesis.java b/src/main/java/de/learnlib/ralib/learning/Hypothesis.java index d62c6aae..a6a1ca78 100644 --- a/src/main/java/de/learnlib/ralib/learning/Hypothesis.java +++ b/src/main/java/de/learnlib/ralib/learning/Hypothesis.java @@ -17,10 +17,8 @@ package de.learnlib.ralib.learning; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; import de.learnlib.AccessSequenceTransformer; import de.learnlib.ralib.automata.MutableRegisterAutomaton; @@ -28,18 +26,7 @@ import de.learnlib.ralib.automata.Transition; import de.learnlib.ralib.automata.TransitionSequenceTransformer; import de.learnlib.ralib.data.Constants; -import de.learnlib.ralib.data.ParameterValuation; -import de.learnlib.ralib.data.RegisterAssignment; -import de.learnlib.ralib.data.RegisterValuation; -import de.learnlib.ralib.data.SymbolicDataValue; -import de.learnlib.ralib.data.SymbolicDataValue.Register; -import de.learnlib.ralib.data.VarMapping; -import de.learnlib.ralib.oracles.Branching; -import de.learnlib.ralib.smt.SMTUtil; import de.learnlib.ralib.words.PSymbolInstance; -import de.learnlib.ralib.words.ParameterizedSymbol; -import gov.nasa.jpf.constraints.api.Expression; -import net.automatalib.common.util.Pair; import net.automatalib.word.Word; /** @@ -79,12 +66,6 @@ public Word transformAccessSequence(Word word) return accessSequences.get(loc); } - public Set> possibleAccessSequences(Word word) { - Set> ret = new LinkedHashSet>(); - ret.add(transformAccessSequence(word)); - return ret; - } - @Override public boolean isAccessSequence(Word word) { return accessSequences.containsValue(word); @@ -93,42 +74,9 @@ public boolean isAccessSequence(Word word) { @Override public Word transformTransitionSequence(Word word) { List tseq = getTransitions(word); - // System.out.println("TSEQ: " + tseq); if (tseq == null) return null; assert tseq.size() == word.length(); Transition last = tseq.get(tseq.size() - 1); return transitionSequences.get(last); } - - public Word transformTransitionSequence(Word word, Word loc) { - return transformTransitionSequence(word); - } - - public Word branchWithSameGuard(Word word, Branching branching) { - ParameterizedSymbol ps = word.lastSymbol().getBaseSymbol(); - - List> tvseq = getTransitionsAndValuations(word); - RegisterValuation vars = tvseq.get(tvseq.size()-1).getSecond(); - ParameterValuation pval = ParameterValuation.fromPSymbolInstance(word.lastSymbol()); - - for (Map.Entry, Expression> e : branching.getBranches().entrySet()) { - if (e.getKey().lastSymbol().getBaseSymbol().equals(ps)) { - Word prefix = e.getKey().prefix(e.getKey().size()-1); - RegisterValuation varsRef = getTransitionsAndValuations(prefix).get(getTransitionsAndValuations(prefix).size()-1).getSecond(); - // System.out.println(varsRef); - RegisterAssignment ra = new RegisterAssignment(); - varsRef.forEach((key, value) -> ra.put(value, key)); - Expression guard = SMTUtil.valsToRegisters(e.getValue(), ra); - if (guard.evaluateSMT(SMTUtil.compose(vars, pval, constants))) { - return e.getKey(); - } - } - } - return null; - } - - public VarMapping getLastTransitionAssignment(Word word) { - List tseq = getTransitions(word); - return tseq.get(tseq.size() - 1).getAssignment().getAssignment(); - } } From 1d1c92c8efb181c879041505b451e3d7dcbdd24d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Sat, 15 Nov 2025 13:00:17 +0100 Subject: [PATCH 27/31] update login test query count --- .../learnlib/ralib/learning/ralambda/LearnLoginTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java index ff5e8a77..b2f817f9 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java @@ -119,13 +119,13 @@ public void testLearnLoginRandom() { Assert.assertEquals(Arrays.toString(measuresLambda), "[{TQ: 88, Resets: 1997, Inputs: 0}," + - " {TQ: 88, Resets: 1984, Inputs: 0}," + + " {TQ: 86, Resets: 1984, Inputs: 0}," + " {TQ: 88, Resets: 1417, Inputs: 0}," + - " {TQ: 88, Resets: 1449, Inputs: 0}," + + " {TQ: 86, Resets: 1449, Inputs: 0}," + " {TQ: 88, Resets: 1403, Inputs: 0}," + - " {TQ: 88, Resets: 2120, Inputs: 0}," + + " {TQ: 86, Resets: 2120, Inputs: 0}," + " {TQ: 88, Resets: 1984, Inputs: 0}," + - " {TQ: 88, Resets: 1263, Inputs: 0}," + + " {TQ: 86, Resets: 1263, Inputs: 0}," + " {TQ: 93, Resets: 1243, Inputs: 0}," + " {TQ: 88, Resets: 1220, Inputs: 0}]"); Assert.assertEquals(Arrays.toString(measuresStar), From 1f918d4d7b86a3b20862a308b197d37d11251b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Mon, 17 Nov 2025 13:21:31 +0100 Subject: [PATCH 28/31] fix error in RARun::getGuard --- .../de/learnlib/ralib/automata/RARun.java | 91 ++++++++++++++++--- .../ralib/ceanalysis/PrefixFinder.java | 2 +- .../de/learnlib/ralib/automata/RaRunTest.java | 54 +++++++++++ 3 files changed, 132 insertions(+), 15 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/automata/RARun.java b/src/main/java/de/learnlib/ralib/automata/RARun.java index ee7aa9e7..8a0e509d 100644 --- a/src/main/java/de/learnlib/ralib/automata/RARun.java +++ b/src/main/java/de/learnlib/ralib/automata/RARun.java @@ -1,10 +1,18 @@ package de.learnlib.ralib.automata; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; +import java.util.Set; +import de.learnlib.ralib.automata.output.OutputMapping; import de.learnlib.ralib.automata.output.OutputTransition; +import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataValue; +import de.learnlib.ralib.data.Mapping; import de.learnlib.ralib.data.RegisterValuation; import de.learnlib.ralib.data.SymbolicDataValue; import de.learnlib.ralib.data.SymbolicDataValue.Parameter; @@ -15,6 +23,12 @@ import gov.nasa.jpf.constraints.expressions.NumericComparator; import gov.nasa.jpf.constraints.util.ExpressionUtil; +/** + * Data structure containing the locations, register valuations, symbol instances + * and transitions at each step of a run of a hypothesis over a data word. + * + * @author fredrik + */ public class RARun { private final RALocation[] locations; @@ -45,31 +59,80 @@ public Transition getRATransition(int i) { return transitions[i-1]; } + /** + * Get the guard of the {@code Transition} at index {@code i}. If the {@code Transition} + * is an {@code OutputTransition}, the guard is computed from the transition's + * {@code OutputMapping}. + * + * @param i + * @return + */ public Expression getGuard(int i) { Transition transition = getRATransition(i); if (transition == null) { return null; } - if (transition instanceof OutputTransition) { - return outputGuard((OutputTransition) transition, getTransitionSymbol(i)); - } + return transition instanceof OutputTransition ? + outputGuard((OutputTransition) transition) : + transition.getGuard(); + } + + /** + * Get the guard of the {@code Transition} at index {@code i}. If the {@code Transition} + * is an {@code OutputTransition}, the guard is computed from the transition's + * {@code OutputMapping}. Registers of the guard will be evaluated according to the + * data values from the register valuation at index {@code i}, and constants will be + * evaluated according to {@code consts}. + * + * @param i + * @return + */ + public Expression getGuard(int i, Constants consts) { + Expression guard = getGuard(i); VarsValuationVisitor vvv = new VarsValuationVisitor(); - Expression guard = transition.getGuard(); - RegisterValuation val = getValuation(i); - return vvv.apply(guard, val); + Mapping vals = new Mapping<>(); + vals.putAll(getValuation(i)); + vals.putAll(consts); + return vvv.apply(guard, vals); } - private Expression outputGuard(OutputTransition t, PSymbolInstance symbol) { - Expression guard = t.getGuard(); - DataValue[] vals = symbol.getParameterValues(); - for (Map.Entry e : t.getOutput().getOutput().entrySet()) { + private Expression outputGuard(OutputTransition t) { + OutputMapping out = t.getOutput(); + + Set params = new LinkedHashSet<>(); + params.addAll(out.getFreshParameters()); + params.addAll(out.getOutput().keySet()); + Set regs = new LinkedHashSet<>(); + regs.addAll(out.getOutput().values()); + + Expression[] expressions = new Expression[params.size()]; + int index = 0; + + // fresh parameters + List prior = new ArrayList<>(); + List fresh = new ArrayList<>(out.getFreshParameters()); + Collections.sort(fresh, (a,b) -> Integer.compare(a.getId(), b.getId())); + for (Parameter p : fresh) { + Expression[] diseq = new Expression[prior.size() + regs.size()]; + int i = 0; + for (Parameter prev : prior) { + diseq[i++] = new NumericBooleanExpression(p, NumericComparator.NE, prev); + } + for (SymbolicDataValue s : regs) { + diseq[i++] = new NumericBooleanExpression(p, NumericComparator.NE, s); + } + expressions[index++] = ExpressionUtil.and(diseq); + prior.add(p); + } + + // mapped parameters + for (Map.Entry e : out.getOutput().entrySet()) { Parameter p = e.getKey(); SymbolicDataValue s = e.getValue(); - DataValue d = vals[p.getId()-1]; - Expression eq = new NumericBooleanExpression(s, NumericComparator.EQ, d); - guard = ExpressionUtil.and(guard, eq); + expressions[index++] = new NumericBooleanExpression(p, NumericComparator.EQ, s); } - return guard; + + return ExpressionUtil.and(expressions); } @Override diff --git a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java index 01fa896b..abdcec08 100644 --- a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java +++ b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java @@ -100,7 +100,7 @@ public Result analyzeCounterExample(Word ce) { SymbolicSuffix vNext = new SymbolicSuffix(ce.prefix(i), ce.suffix(ce.length() - i), restrBuilder); SymbolicSuffix v = new SymbolicSuffix(ce.prefix(i-1), ce.suffix(ce.length() - i + 1), restrBuilder); - Expression gHyp = run.getGuard(i); + Expression gHyp = run.getGuard(i, consts); for (ShortPrefix u : hyp.getLeaf(loc).getShortPrefixes()) { SDT sdt = sulOracle.treeQuery(u, v); diff --git a/src/test/java/de/learnlib/ralib/automata/RaRunTest.java b/src/test/java/de/learnlib/ralib/automata/RaRunTest.java index e948516c..63668150 100644 --- a/src/test/java/de/learnlib/ralib/automata/RaRunTest.java +++ b/src/test/java/de/learnlib/ralib/automata/RaRunTest.java @@ -1,20 +1,27 @@ package de.learnlib.ralib.automata; import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; import org.testng.Assert; import org.testng.annotations.Test; import de.learnlib.ralib.RaLibTestSuite; +import de.learnlib.ralib.automata.output.OutputMapping; +import de.learnlib.ralib.automata.output.OutputTransition; +import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; import de.learnlib.ralib.data.SymbolicDataValue; +import de.learnlib.ralib.data.SymbolicDataValue.Constant; import de.learnlib.ralib.data.SymbolicDataValue.Parameter; import de.learnlib.ralib.data.SymbolicDataValue.Register; import de.learnlib.ralib.data.VarMapping; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.RegisterGenerator; import de.learnlib.ralib.words.InputSymbol; +import de.learnlib.ralib.words.OutputSymbol; import de.learnlib.ralib.words.PSymbolInstance; import gov.nasa.jpf.constraints.api.Expression; import gov.nasa.jpf.constraints.expressions.NumericBooleanExpression; @@ -26,6 +33,7 @@ public class RaRunTest extends RaLibTestSuite { final DataType DT = new DataType("int"); final InputSymbol A = new InputSymbol("a", new DataType[] {DT}); + final OutputSymbol B = new OutputSymbol("b", new DataType[] {DT, DT, DT, DT}); @Test public void testMutableRARun() { @@ -77,4 +85,50 @@ public void testMutableRARun() { Assert.assertEquals(run.getTransitionSymbol(2), psi1); Assert.assertEquals(run.getTransitionSymbol(3), psi2); } + + @Test + public void testGetGuard() { + Parameter p1 = new Parameter(DT, 1); + Parameter p2 = new Parameter(DT, 2); + Parameter p3 = new Parameter(DT, 3); + Parameter p4 = new Parameter(DT, 4); + Register r1 = new Register(DT, 1); + Constant c1 = new Constant(DT, 1); + Constants consts = new Constants(); + consts.put(c1, new DataValue(DT, BigDecimal.valueOf(-1))); + + MutableRegisterAutomaton ra = new MutableRegisterAutomaton(consts); + RALocation l0 = ra.addInitialState(); + RALocation l1 = ra.addState(); + RALocation l2 = ra.addState(); + + VarMapping mapping = new VarMapping<>(); + mapping.put(r1, p1); + Assignment assign = new Assignment(mapping); + Collection fresh = new ArrayList<>(); + fresh.add(p2); + fresh.add(p1); + VarMapping outmap = new VarMapping<>(); + outmap.put(p3, r1); + outmap.put(p4, c1); + OutputMapping out = new OutputMapping(fresh, outmap); + + ra.addTransition(l0, A, new InputTransition(ExpressionUtil.TRUE, A, l0, l1, assign)); + ra.addTransition(l1, B, new OutputTransition(ExpressionUtil.TRUE, out, B, l1, l2, new Assignment(new VarMapping<>()))); + + Word word = Word.fromSymbols( + new PSymbolInstance(A, new DataValue(DT, BigDecimal.ZERO)), + new PSymbolInstance(B, new DataValue(DT, BigDecimal.ONE), + new DataValue(DT, BigDecimal.valueOf(2)), + new DataValue(DT, BigDecimal.ZERO), + new DataValue(DT, consts.get(c1).getValue()))); + + RARun run = ra.getRun(word); + Expression guard = run.getGuard(2, consts); + + Assert.assertEquals(guard.toString(), + "((((('p1' != 0) && ('p1' != -1)) && " + + "((('p2' != 'p1') && ('p2' != 0)) && ('p2' != -1))) && " + + "('p3' == 0)) && ('p4' == -1))"); + } } From fea807642dbb8b8287e88af5aa71ff285480dd8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Tue, 18 Nov 2025 11:43:13 +0100 Subject: [PATCH 29/31] small fixes, tidying up, and removing unused code --- .../ralib/ceanalysis/PrefixFinder.java | 2 +- .../learnlib/ralib/ct/ClassificationTree.java | 8 +- .../de/learnlib/ralib/data/Bijection.java | 2 +- .../de/learnlib/ralib/data/DataValue.java | 1 - .../ralib/learning/ralambda/RaLambda.java | 500 ------------------ .../ralib/learning/ralambda/SLCT.java | 4 +- .../ralib/learning/ralambda/SLLambda.java | 20 +- .../learnlib/ralib/tools/ClassAnalyzer.java | 2 +- .../de/learnlib/ralib/tools/IOSimulator.java | 2 +- .../learnlib/ralib/CacheDataWordOracle.java | 1 - .../ralib/RaLibLearningExperimentRunner.java | 5 +- .../ralib/ceanalysis/PrefixFinderTest.java | 43 -- .../learnlib/ralib/ct/CTConsistencyTest.java | 7 - .../learning/ralambda/IOHandlingTest.java | 21 +- .../learning/ralambda/LearnABPOutputTest.java | 10 +- .../learning/ralambda/LearnArrayListTest.java | 17 +- .../learning/ralambda/LearnEchoTest.java | 10 +- .../learning/ralambda/LearnLoginTest.java | 10 +- .../learning/ralambda/LearnMixedIOTest.java | 9 +- .../learning/ralambda/LearnPQIOTest.java | 10 +- .../ralib/learning/ralambda/LearnPQTest.java | 11 +- .../ralib/learning/ralambda/LearnPadlock.java | 11 +- .../ralambda/LearnPalindromeIOTest.java | 9 +- .../learning/ralambda/LearnRepeaterTest.java | 10 +- .../learning/ralambda/LearnSipIOTest.java | 10 +- .../learning/ralambda/LearnStackTest.java | 18 +- .../TestDistinguishingSuffixOptimization.java | 11 +- .../learning/ralambda/TestQueryCount.java | 13 +- .../ralambda/TestSuffixOptimization.java | 18 +- .../ralib/learning/ralambda/TestSymmetry.java | 30 +- .../ralambda/TestUnknownMemorable.java | 22 +- 31 files changed, 44 insertions(+), 803 deletions(-) delete mode 100644 src/main/java/de/learnlib/ralib/learning/ralambda/RaLambda.java diff --git a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java index abdcec08..0eacb885 100644 --- a/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java +++ b/src/main/java/de/learnlib/ralib/ceanalysis/PrefixFinder.java @@ -287,7 +287,7 @@ private Optional checkTransition(RALocation loc, .filter(w -> leaf.getPrefixes().contains(w)) .iterator(); while (extensions.hasNext()) { - Word uExtHyp = extensions.next(); // u_{i-1}\alpha_i(d_i') + Word uExtHyp = extensions.next(); SDT uExtHypSDT = sulOracle.treeQuery(uExtHyp, v).toRegisterSDT(uExtHyp, consts); SDT uExtSulSDT = sulOracle.treeQuery(uExtSul, v).toRegisterSDT(uExtSul, consts); diff --git a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java index 3f25cb59..d72c7ab8 100644 --- a/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java +++ b/src/main/java/de/learnlib/ralib/ct/ClassificationTree.java @@ -172,9 +172,9 @@ public void initialize() { sift(RaStar.EMPTY_PREFIX); } - ////////////////////////////////////////// - // OPERATION ON THE CLASSIFICATION TREE // - ////////////////////////////////////////// + /////////////////////////////////////////// + // OPERATIONS ON THE CLASSIFICATION TREE // + /////////////////////////////////////////// /** * Sift prefix into the tree. If prefix sifts to a new leaf, it becomes the representative prefix @@ -696,7 +696,7 @@ private boolean suffixRevealsNewGuard(SymbolicSuffix av, CTLeaf leaf) { * @return */ private Bijection rpRegBijection(Bijection bijection, Word prefx) { - return Bijection.DVtoRegBijection(bijection, prefx, getLeaf(prefx).getRepresentativePrefix()); + return Bijection.dvToRegBijection(bijection, prefx, getLeaf(prefx).getRepresentativePrefix()); } /** diff --git a/src/main/java/de/learnlib/ralib/data/Bijection.java b/src/main/java/de/learnlib/ralib/data/Bijection.java index e86af73b..c7b4ee90 100644 --- a/src/main/java/de/learnlib/ralib/data/Bijection.java +++ b/src/main/java/de/learnlib/ralib/data/Bijection.java @@ -154,7 +154,7 @@ private static void putAll(Map in, } } - public static Bijection DVtoRegBijection(Bijection bijection, Word keyWord, Word valueWord) { + public static Bijection dvToRegBijection(Bijection bijection, Word keyWord, Word valueWord) { DataValue[] keyVals = DataWords.valsOf(keyWord); DataValue[] valueVals = DataWords.valsOf(valueWord); Bijection ret = new Bijection<>(); diff --git a/src/main/java/de/learnlib/ralib/data/DataValue.java b/src/main/java/de/learnlib/ralib/data/DataValue.java index 6c69158c..f7449e3f 100644 --- a/src/main/java/de/learnlib/ralib/data/DataValue.java +++ b/src/main/java/de/learnlib/ralib/data/DataValue.java @@ -63,7 +63,6 @@ public boolean equals(Object obj) { if (!Objects.equals(this.type, other.type)) { return false; } -// return this.getValue().equals(other.getValue()); return this.getValue().compareTo(other.getValue()) == 0; } diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/RaLambda.java b/src/main/java/de/learnlib/ralib/learning/ralambda/RaLambda.java deleted file mode 100644 index bcccb8cb..00000000 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/RaLambda.java +++ /dev/null @@ -1,500 +0,0 @@ -//package de.learnlib.ralib.learning.ralambda; -// -//import java.util.ArrayDeque; -//import java.util.Collection; -//import java.util.Collections; -//import java.util.Deque; -//import java.util.Iterator; -//import java.util.LinkedHashMap; -//import java.util.LinkedHashSet; -//import java.util.LinkedList; -//import java.util.List; -//import java.util.Map; -// -//import org.slf4j.Logger; -//import org.slf4j.LoggerFactory; -// -//import de.learnlib.logging.Category; -//import de.learnlib.query.DefaultQuery; -//import de.learnlib.ralib.ceanalysis.PrefixFinder; -//import de.learnlib.ralib.data.*; -//import de.learnlib.ralib.dt.DT; -//import de.learnlib.ralib.dt.DTHyp; -//import de.learnlib.ralib.dt.DTLeaf; -//import de.learnlib.ralib.dt.MappedPrefix; -//import de.learnlib.ralib.dt.ShortPrefix; -//import de.learnlib.ralib.learning.AutomatonBuilder; -//import de.learnlib.ralib.learning.Hypothesis; -//import de.learnlib.ralib.learning.IOAutomatonBuilder; -//import de.learnlib.ralib.learning.LocationComponent; -//import de.learnlib.ralib.learning.QueryStatistics; -//import de.learnlib.ralib.learning.RaLearningAlgorithm; -//import de.learnlib.ralib.learning.RaLearningAlgorithmName; -//import de.learnlib.ralib.learning.SymbolicSuffix; -//import de.learnlib.ralib.learning.rastar.CEAnalysisResult; -//import de.learnlib.ralib.oracles.Branching; -//import de.learnlib.ralib.oracles.SDTLogicOracle; -//import de.learnlib.ralib.oracles.TreeOracle; -//import de.learnlib.ralib.oracles.TreeOracleFactory; -//import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; -//import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; -//import de.learnlib.ralib.smt.ConstraintSolver; -//import de.learnlib.ralib.theory.SDT; -//import de.learnlib.ralib.words.PSymbolInstance; -//import de.learnlib.ralib.words.ParameterizedSymbol; -//import net.automatalib.word.Word; -// -//public class RaLambda implements RaLearningAlgorithm { -// -// public static final Word EMPTY_PREFIX = Word.epsilon(); -// -// public static final SymbolicSuffix EMPTY_SUFFIX = new SymbolicSuffix(Word.epsilon(), -// Word.epsilon()); -// -// private final DT dt; -// -// private final Constants consts; -// -// private final Deque> counterexamples = new LinkedList<>(); -// private final Deque> candidateCEs = new LinkedList<>(); -// -// private DTHyp hyp = null; -// -// private final TreeOracle sulOracle; -// -// private final SDTLogicOracle sdtLogicOracle; -// -// private final TreeOracleFactory hypOracleFactory; -// -// private final OptimizedSymbolicSuffixBuilder suffixBuilder; -// private final SymbolicSuffixRestrictionBuilder restrictionBuilder; -// private ConstraintSolver solver = null; -// -// private QueryStatistics queryStats = null; -// -// private final boolean ioMode; -// -// private static final Logger LOGGER = LoggerFactory.getLogger(RaLambda.class); -// -// private boolean useOldAnalyzer; -// -// private final Map, Boolean> guardPrefixes = new LinkedHashMap, Boolean>(); -// -// private PrefixFinder prefixFinder = null; -// -// public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, -// boolean ioMode, ParameterizedSymbol... inputs) { -// -// this(oracle, hypOracleFactory, sdtLogicOracle, consts, ioMode, false, inputs); -// } -// -// public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, -// boolean ioMode, boolean useOldAnalyzer, ParameterizedSymbol... inputs) { -// -// this(oracle, hypOracleFactory, sdtLogicOracle, consts, ioMode, useOldAnalyzer, false, inputs); -// } -// -// public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, -// boolean ioMode, boolean useOldAnalyzer, boolean thoroughSearch, ParameterizedSymbol... inputs) { -// -// this.ioMode = ioMode; -// this.consts = consts; -// this.sulOracle = oracle; -// this.sdtLogicOracle = sdtLogicOracle; -// this.hypOracleFactory = hypOracleFactory; -// this.useOldAnalyzer = useOldAnalyzer; -// this.restrictionBuilder = oracle.getRestrictionBuilder(); -// this.suffixBuilder = new OptimizedSymbolicSuffixBuilder(consts, restrictionBuilder); -// this.dt = new DT(oracle, ioMode, consts, inputs); -// this.dt.initialize(); -// } -// -// public RaLambda(TreeOracle oracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, Constants consts, -// ParameterizedSymbol... inputs) { -// this(oracle, hypOracleFactory, sdtLogicOracle, consts, false, false, inputs); -// } -// -// @Override -// public void addCounterexample(DefaultQuery ce) { -// LOGGER.info(Category.EVENT, "adding counterexample: {}", ce); -// counterexamples.add(ce); -// } -// -// @Override -// public void learn() { -// -// if (hyp == null) { -// buildNewHypothesis(); -// } -// -// while (analyzeCounterExample()); -// -// if (queryStats != null) -// queryStats.hypothesisConstructed(); -// -// } -// -// private void buildNewHypothesis() { -// -// Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); -// components.putAll(dt.getComponents()); -// AutomatonBuilder ab = new AutomatonBuilder(components, consts, dt); -// -// hyp = (DTHyp) ab.toRegisterAutomaton(); -// if (prefixFinder != null) { -// prefixFinder.setHypothesis(hyp); -// //prefixFinder.setComponents(components); -// prefixFinder.setHypothesisTreeOracle(hypOracleFactory.createTreeOracle(hyp)); -// } -// } -// -// private boolean analyzeCounterExample() { -//// if (useOldAnalyzer) -//// return analyzeCounterExampleOld(); -// LOGGER.info(Category.PHASE, "Analyzing Counterexample"); -// -// if (candidateCEs.isEmpty()) { -// prefixFinder = null; -// if (counterexamples.isEmpty()) { -// assert noShortPrefixes() || !dt.isMissingParameter(); -// return false; -// } -// else { -// DefaultQuery ce = counterexamples.poll(); -// candidateCEs.push(ce); -// } -// } -// -// TreeOracle hypOracle = hypOracleFactory.createTreeOracle(hyp); -// -// if (prefixFinder == null) { -// //Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); -// //components.putAll(dt.getComponents()); -// prefixFinder = new PrefixFinder(sulOracle, hypOracle, hyp, sdtLogicOracle, consts); -// } -// -// boolean foundce = false; -// DefaultQuery ce = null; -// Deque> ces = new ArrayDeque>(); -// ces.addAll(candidateCEs); -// while(!foundce && !ces.isEmpty()) { -// ce = ces.poll(); -// boolean hypce = hyp.accepts(ce.getInput()); -// boolean sulce = ce.getOutput(); -// //System.out.println("ce: " + ce + " - " + sulce + " vs. " + hypce); -// foundce = hypce != sulce; -// } -// -// if (!foundce) { -// candidateCEs.clear(); -// return true; -// } -// -// if (queryStats != null) { -// queryStats.analyzingCounterExample(); -// queryStats.analyzeCE(ce.getInput()); -// } -// Word ceWord = ce.getInput(); -// CEAnalysisResult result = prefixFinder.analyzeCounterexample(ceWord); -// Word transition = result.getPrefix(); // u alpha(d) -// //System.out.println("new prefix: " + transition); -// -// for (DefaultQuery q : prefixFinder.getCounterExamples()) { -// if (!candidateCEs.contains(q)) -// candidateCEs.addLast(q); -// } -// -// if (queryStats != null) -// queryStats.processingCounterExample(); -// -// if (isGuardRefinement(transition)) { -// addPrefix(transition); -// } -// else { -// expand(transition); -// } -// -// while (!dt.checkIOSuffixes()); -// -// boolean consistent = false; -// while (!consistent) { -// -// consistent = checkLocationConsistency(); -// -// if (!checkRegisterClosedness()) { -// consistent = false; -// } -// -// if (!checkGuardConsistency()) { -// consistent = false; -// } -// -// if (!checkRegisterConsistency()) { -// consistent = false; -// } -// } -// -// if (noShortPrefixes() && !dt.isMissingParameter()) { -// buildNewHypothesis(); -// } -// //System.out.println(hyp); -// return true; -// } -// -// private boolean isGuardRefinement(Word word) { -// return dt.getLeaf(word) == null; -// } -// -// private void addPrefix(Word u) { -// dt.sift(u, true); -// } -// -// private void expand(Word u) { -// DTLeaf l = dt.getLeaf(u); -// assert l != null; -// l.elevatePrefix(dt, u, hyp, sdtLogicOracle); -// } -// -// private boolean checkLocationConsistency() { -// -// for (DTLeaf l : dt.getLeaves()) { -// MappedPrefix mp = l.getPrimePrefix(); -// Iterator it = l.getShortPrefixes().iterator(); -// while (it.hasNext()) { -// ShortPrefix sp = (ShortPrefix)it.next(); -// SymbolicSuffix suffix = null; -// for (ParameterizedSymbol psi : dt.getInputs()) { -// Branching access_b = l.getBranching(psi); -// Branching prefix_b = sp.getBranching(psi); -// for (Word ws : prefix_b.getBranches().keySet()) { -// Word wa = DTLeaf.branchWithSameGuard(ws, prefix_b, l.getRemapping(sp), access_b, sdtLogicOracle); -// //System.out.println("wa: " + wa + ", ws: " + ws); -// DTLeaf la = dt.getLeaf(wa); -// DTLeaf ls = dt.getLeaf(ws); -// if (la != ls) { -// SymbolicSuffix v = distinguishingSuffix(wa, la, ws, ls); -// if (suffix == null || suffix.length() > v.length()) { -// suffix = v; -// } -// assert suffix != null; -// } -// } -// } -// if (suffix != null) { -// dt.split(sp.getPrefix(), suffix, l); -// return false; -// } -// } -// } -// return true; -// } -// -// private boolean checkRegisterClosedness() { -// return dt.checkVariableConsistency(suffixBuilder); -// } -// -// private boolean checkRegisterConsistency() { -// return dt.checkRegisterConsistency(suffixBuilder); -// } -// -// private boolean checkGuardConsistency() { -// for (DTLeaf dest_c : dt.getLeaves()) { -// Collection> words = new LinkedHashSet<>(); -// words.add(dest_c.getAccessSequence()); -// words.addAll(dest_c.getPrefixes().getWords()); -// words.addAll(dest_c.getShortPrefixes().getWords()); -// for (Word dest_id : words) { -// if (dest_id.length() == 0) { -// continue; -// } -// Word src_id = dest_id.prefix(dest_id.length() - 1); -// DTLeaf src_c = dt.getLeaf(src_id); -// -// Branching hypBranching = null; -// if (src_c.getAccessSequence().equals(src_id)) { -// hypBranching = src_c.getBranching(dest_id.lastSymbol().getBaseSymbol()); -// } else { -// ShortPrefix sp = (ShortPrefix) src_c.getShortPrefixes().get(src_id); -// assert sp != null; -// hypBranching = sp.getBranching(dest_id.lastSymbol().getBaseSymbol()); -// } -// if (hypBranching.getBranches().get(dest_id) != null) { -// // word already in branching, no guard refinement needed -// continue; -// } -// Word hyp_id = branchWithSameGuard(dest_c.getPrefix(dest_id), hypBranching); -// -// SymbolicSuffix suffix = null; -// -// DTLeaf hyp_c = dt.getLeaf(hyp_id); -// if (hyp_c != dest_c) { -// suffix = distinguishingSuffix(hyp_id, hyp_c, dest_id, dest_c); -// } else { -// List suffixes = new LinkedList<>(); -// Map dest_sdts = new LinkedHashMap<>(); -// Map hyp_sdts = new LinkedHashMap<>(); -// for (Map.Entry e : dest_c.getPrefix(dest_id).getTQRs().entrySet()) { -// SymbolicSuffix s = e.getKey(); -// SDT dest_sdt = e.getValue(); -// SDT hyp_sdt = hyp_c.getPrefix(hyp_id).getTQRs().get(s); -// assert hyp_sdt != null; -// -// if (!SDT.equivalentUnderId(dest_sdt.toRegisterSDT(dest_id, consts), hyp_sdt.toRegisterSDT(hyp_id, consts))) { -// suffixes.add(s); -// dest_sdts.put(s, dest_sdt); -// hyp_sdts.put(s, hyp_sdt); -// } -// } -// -// if (suffixes.isEmpty()) { -// continue; -// } -// -// Collections.sort(suffixes, (sa, sb) -> sa.length() > sb.length() ? 1 : -// sa.length() < sb.length() ? -1 : 0); -// -// for (SymbolicSuffix s : suffixes) { -// SymbolicSuffix testSuffix; -// SDT hyp_sdt = hyp_sdts.get(s); -// -// if (suffixBuilder != null) { -// SDT dest_sdt = dest_sdts.get(s); -// DataValue[] regs = remappedRegisters(dest_sdt, hyp_sdt); -// testSuffix = suffixBuilder.extendSuffix(dest_id, dest_sdt, s, regs); -// } else { -// testSuffix = new SymbolicSuffix(src_id, dest_id.suffix(1), restrictionBuilder); -// testSuffix = testSuffix.concat(s); -// } -// -// SDT testSDT = sulOracle.treeQuery(src_id, testSuffix); -// Branching testBranching = sulOracle.updateBranching(src_id, dest_id.lastSymbol().getBaseSymbol(), hypBranching, testSDT); -// if (testBranching.getBranches().get(dest_id) != null) { -// suffix = testSuffix; -// break; -// } -// } -// } -// -// if (suffix != null) { -// dt.addSuffix(suffix, src_c); -// return false; -// } -// } -// } -// -// return true; -// } -// -// private SymbolicSuffix distinguishingSuffix(Word wa, DTLeaf ca, Word wb, DTLeaf cb) { -// Word sa = wa.suffix(1); -// Word sb = wb.suffix(1); -// -// assert sa.getSymbol(0).getBaseSymbol().equals(sb.getSymbol(0).getBaseSymbol()); -// -// SymbolicSuffix v = dt.findLCA(ca, cb).getSuffix(); -// -// Word prefixA = wa.prefix(wa.length() - 1); -// Word prefixB = wb.prefix(wb.length() - 1); -// -// SDT tqrA = ca.getTQR(wa, v); -// SDT tqrB = cb.getTQR(wb, v); -// -// assert tqrA != null && tqrB != null; -// -// SDT sdtA = tqrA; -// SDT sdtB = tqrB; -// -// if (suffixBuilder != null && solver != null) { -// //return suffixBuilder.extendDistinguishingSuffix(wa, sdtA, wb, sdtB, v); -// SymbolicSuffix suffix = suffixBuilder.distinguishingSuffixFromSDTs(wa, sdtA, wb, sdtB, v.getActions(), solver); -// return suffix; -// } -// -// SymbolicSuffix alpha_a = new SymbolicSuffix(prefixA, sa, restrictionBuilder); -// SymbolicSuffix alpha_b = new SymbolicSuffix(prefixB, sb, restrictionBuilder); -// return alpha_a.getFreeValues().size() > alpha_b.getFreeValues().size() -// ? alpha_a.concat(v) -// : alpha_b.concat(v); -// } -// -// private boolean noShortPrefixes() { -// for (DTLeaf l : dt.getLeaves()) { -// if (!l.getShortPrefixes().isEmpty()) { -// return false; -// } -// } -// return true; -// } -// -// public void setUseOldAnalyzer(boolean useOldAnalyzer) { -// this.useOldAnalyzer = useOldAnalyzer; -// } -// -// private Word branchWithSameGuard(MappedPrefix mp, Branching branching) { -// Word dw = mp.getPrefix(); -// -// return branching.transformPrefix(dw); -// } -// -// private DataValue[] remappedRegisters(SDT sdt1, SDT sdt2) { -// Bijection bijection = SDT.equivalentUnderBijection(sdt1, sdt2); -// assert bijection != null; -// List vals = new LinkedList<>(); -// for (Map.Entry e : bijection.entrySet()) { -// if (!e.getKey().equals(e.getValue())) { -// vals.add(e.getKey()); -// vals.add(e.getValue()); -// } -// } -// return vals.toArray(new DataValue[vals.size()]); -// } -// -// @Override -// public Hypothesis getHypothesis() { -// Map, LocationComponent> components = new LinkedHashMap, LocationComponent>(); -// components.putAll(dt.getComponents()); -// AutomatonBuilder ab; -// if (ioMode) { -// ab = new IOAutomatonBuilder(components, consts); -// } else { -// ab = new AutomatonBuilder(components, consts); -// } -// return ab.toRegisterAutomaton(); -// } -// -// public DT getDT() { -// return dt; -// } -// -// public DTHyp getDTHyp() { -// return hyp; -// } -// -// public Map, LocationComponent> getComponents() { -// return dt.getComponents(); -// } -// -// @Override -// public void setStatisticCounter(QueryStatistics queryStats) { -// this.queryStats = queryStats; -// } -// -// @Override -// public QueryStatistics getQueryStatistics() { -// return queryStats; -// } -// -// public void setSolver(ConstraintSolver solver) { -// this.solver = solver; -// } -// -// @Override -// public RaLearningAlgorithmName getName() { -// return RaLearningAlgorithmName.RALAMBDA; -// } -// -// @Override -// public String toString() { -// return dt.toString(); -// } -//} diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java index 6bfa050f..247f4f0d 100644 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/SLCT.java @@ -78,11 +78,11 @@ public SLCT(TreeOracle sulOracle, TreeOracleFactory hypOracleFactory, SDTLogicOr @Override public void learn() { if (hyp == null) { - while(!checkClosedness()); + while (!checkClosedness()); buildHypothesis(); } - while(analyzeCounterExample()); + while (analyzeCounterExample()); if (queryStats != null) { queryStats.hypothesisConstructed(); diff --git a/src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java b/src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java index 7e2aa535..bfbb618f 100644 --- a/src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java +++ b/src/main/java/de/learnlib/ralib/learning/ralambda/SLLambda.java @@ -16,9 +16,7 @@ import de.learnlib.ralib.learning.QueryStatistics; import de.learnlib.ralib.learning.RaLearningAlgorithm; import de.learnlib.ralib.learning.RaLearningAlgorithmName; -import de.learnlib.ralib.oracles.SDTLogicOracle; import de.learnlib.ralib.oracles.TreeOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.mto.OptimizedSymbolicSuffixBuilder; import de.learnlib.ralib.oracles.mto.SymbolicSuffixRestrictionBuilder; import de.learnlib.ralib.smt.ConstraintSolver; @@ -39,10 +37,6 @@ public class SLLambda implements RaLearningAlgorithm { private final TreeOracle sulOracle; - private final SDTLogicOracle sdtLogicOracle; - - private final TreeOracleFactory hypOracleFactory; - private final OptimizedSymbolicSuffixBuilder suffixBuilder; private final SymbolicSuffixRestrictionBuilder restrictionBuilder; @@ -54,12 +48,10 @@ public class SLLambda implements RaLearningAlgorithm { private final ConstraintSolver solver; - public SLLambda(TreeOracle sulOracle, TreeOracleFactory hypOracleFactory, SDTLogicOracle sdtLogicOracle, - Map teachers, Constants consts, boolean ioMode, ConstraintSolver solver, + public SLLambda(TreeOracle sulOracle, Map teachers, + Constants consts, boolean ioMode, ConstraintSolver solver, ParameterizedSymbol ... inputs) { this.sulOracle = sulOracle; - this.hypOracleFactory = hypOracleFactory; - this.sdtLogicOracle = sdtLogicOracle; this.teachers = teachers; this.consts = consts; this.ioMode = ioMode; @@ -75,11 +67,11 @@ public SLLambda(TreeOracle sulOracle, TreeOracleFactory hypOracleFactory, SDTLog @Override public void learn() { if (hyp == null) { - while(!checkClosedness()); + while (!checkClosedness()); buildHypothesis(); } - while(analyzeCounterExample()); + while (analyzeCounterExample()); if (queryStats != null) { queryStats.hypothesisConstructed(); @@ -158,7 +150,7 @@ private boolean analyzeCounterExample() { if (queryStats != null) queryStats.processingCounterExample(); - switch(res.result()) { + switch (res.result()) { case TRANSITION: assert !ct.getPrefixes().contains(res.prefix()) : "Duplicate prefix: " + res.prefix(); ct.sift(res.prefix()); @@ -170,7 +162,7 @@ private boolean analyzeCounterExample() { } boolean closedAndConsistent = false; - while(!closedAndConsistent) { + while (!closedAndConsistent) { if (checkClosedness()) { if (checkConsistency()) { closedAndConsistent = true; diff --git a/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java b/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java index 2d559546..4af96822 100644 --- a/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java +++ b/src/main/java/de/learnlib/ralib/tools/ClassAnalyzer.java @@ -249,7 +249,7 @@ public TreeOracle createTreeOracle(RegisterAutomaton hyp) { this.rastar = new RaStar(mto, hypFactory, mlo, consts, true, actions); break; case AbstractToolWithRandomWalk.LEARNER_SLLAMBDA: - this.rastar = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + this.rastar = new SLLambda(mto, teachers, consts, true, solver, actions); break; case AbstractToolWithRandomWalk.LEARNER_RADT: this.rastar = new SLCT(mto, hypFactory, mlo, consts, true, solver, actions); diff --git a/src/main/java/de/learnlib/ralib/tools/IOSimulator.java b/src/main/java/de/learnlib/ralib/tools/IOSimulator.java index 6bb4c0cf..603fc45d 100644 --- a/src/main/java/de/learnlib/ralib/tools/IOSimulator.java +++ b/src/main/java/de/learnlib/ralib/tools/IOSimulator.java @@ -218,7 +218,7 @@ public TreeOracle createTreeOracle(RegisterAutomaton hyp) { this.rastar = new RaStar(mto, hypFactory, mlo, consts, true, actions); break; case AbstractToolWithRandomWalk.LEARNER_SLLAMBDA: - this.rastar = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + this.rastar = new SLLambda(mto, teachers, consts, true, solver, actions); break; case AbstractToolWithRandomWalk.LEARNER_RADT: this.rastar = new SLCT(mto, hypFactory, mlo, consts, true, solver, actions); diff --git a/src/test/java/de/learnlib/ralib/CacheDataWordOracle.java b/src/test/java/de/learnlib/ralib/CacheDataWordOracle.java index 9ee97a58..149bd73c 100644 --- a/src/test/java/de/learnlib/ralib/CacheDataWordOracle.java +++ b/src/test/java/de/learnlib/ralib/CacheDataWordOracle.java @@ -40,7 +40,6 @@ public void processQueries(Collection> boolean answer = traceBoolean(query.getInput()); query.answer(answer); } -// countQueries(queries.size()); } private boolean traceBoolean(Word query) { diff --git a/src/test/java/de/learnlib/ralib/RaLibLearningExperimentRunner.java b/src/test/java/de/learnlib/ralib/RaLibLearningExperimentRunner.java index 7458225a..3ba50792 100644 --- a/src/test/java/de/learnlib/ralib/RaLibLearningExperimentRunner.java +++ b/src/test/java/de/learnlib/ralib/RaLibLearningExperimentRunner.java @@ -125,12 +125,9 @@ public Hypothesis run(RaLearningAlgorithmName algorithmName, DataWordOracle data learner = new RaStar(mto, hypFactory, mlo, consts, ioMode, actionSymbols); break; case RALAMBDA: -// learner = new RaLambda(mto, hypFactory, mlo, consts, ioMode, useOldAnalyzer, actionSymbols); -// ((RaLambda)learner).setSolver(solver); - learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, ioMode, solver, actionSymbols); + learner = new SLLambda(mto, teachers, consts, ioMode, solver, actionSymbols); break; case RADT: -// learner = new RaDT(mto, hypFactory, mlo, consts, ioMode, actionSymbols); learner = new SLCT(mto, hypFactory, mlo, consts, ioMode, solver, actionSymbols); break; default: diff --git a/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java b/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java index 5555ae84..85f7a2ad 100644 --- a/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java +++ b/src/test/java/de/learnlib/ralib/ceanalysis/PrefixFinderTest.java @@ -82,14 +82,6 @@ public void testPrefixFinder() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, new Constants(), solver); -// SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); -// -// TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> -// new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, -// new Constants(), solver); - -// RaStar rastar = new RaStar(mto, hypFactory, slo, -// consts, I_LOGIN, I_LOGOUT, I_REGISTER); SymbolicSuffixRestrictionBuilder rb = new SymbolicSuffixRestrictionBuilder(consts, teachers); OptimizedSymbolicSuffixBuilder sb = new OptimizedSymbolicSuffixBuilder(consts, rb); @@ -106,10 +98,6 @@ public void testPrefixFinder() { CTAutomatonBuilder ab = new CTAutomatonBuilder(ct, consts, false, solver); final CTHypothesis hyp = ab.buildHypothesis(); -// rastar.learn(); -// final Hypothesis hyp = rastar.getHypothesis(); - // System.out.println(hyp); - Word ce = Word.fromSymbols( new PSymbolInstance(I_REGISTER, new DataValue(T_UID, BigDecimal.ONE), new DataValue(T_PWD, BigDecimal.ONE)), @@ -118,15 +106,6 @@ public void testPrefixFinder() { PrefixFinder pf = new PrefixFinder(mto, hyp, ct, teachers, rb, solver, consts); -// PrefixFinder pf = new PrefixFinder( -// MTO, -// HYPFACTORY.CREATETREEORACLE(HYP), HYP, -// SLO, -// // RASTAR.GETCOMPONENTS(), -// CONSTS -// ); - -// Word prefix = pf.analyzeCounterexample(ce).getPrefix(); Result res = pf.analyzeCounterExample(ce); Word prefix = res.prefix(); Assert.assertEquals(res.result(), PrefixFinder.ResultType.LOCATION); @@ -146,17 +125,6 @@ public void testPrefixFinderMultipleAccessSequences() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, new Constants(), solver); -// SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); -// -// TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> -// new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, -// new Constants(), solver); -// RaLambda ralambda = new RaLambda(mto, hypFactory, slo, -// consts, I_PUSH, I_POP); -// -// ralambda.learn(); -// final DTHyp hyp = ralambda.getDTHyp(); - // System.out.println(hyp); SymbolicSuffixRestrictionBuilder rb = new SymbolicSuffixRestrictionBuilder(consts, teachers); OptimizedSymbolicSuffixBuilder sb = new OptimizedSymbolicSuffixBuilder(consts, rb); @@ -175,8 +143,6 @@ public void testPrefixFinderMultipleAccessSequences() { Word shortPrefix = Word.fromSymbols( new PSymbolInstance(I_PUSH, new DataValue(T_INT, BigDecimal.ZERO))); -// DTLeaf leaf = ralambda.getDT().getLeaf(shortPrefix); -// leaf.elevatePrefix(ralambda.getDT(), shortPrefix, hyp, slo); ct.expand(shortPrefix); Word ce = Word.fromSymbols( @@ -184,17 +150,8 @@ public void testPrefixFinderMultipleAccessSequences() { new PSymbolInstance(I_POP, new DataValue(T_INT, BigDecimal.ZERO)), new PSymbolInstance(I_PUSH, new DataValue(T_INT, BigDecimal.ONE))); -// PrefixFinder pf = new PrefixFinder( -// mto, -// hypFactory.createTreeOracle(hyp), hyp, -// slo, -// // ralambda.getComponents(), -// consts -// ); - PrefixFinder pf = new PrefixFinder(mto, hyp, ct, teachers, rb, solver, consts); -// Word prefix = pf.analyzeCounterexample(ce).getPrefix(); Result res = pf.analyzeCounterExample(ce); Assert.assertEquals(res.result(), PrefixFinder.ResultType.TRANSITION); Assert.assertEquals(res.prefix().toString(), "push[0[T_int]] pop[0[T_int]]"); diff --git a/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java b/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java index 5ec4420e..e29ab939 100644 --- a/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java +++ b/src/test/java/de/learnlib/ralib/ct/CTConsistencyTest.java @@ -151,16 +151,12 @@ public void testLocationConsistency() { boolean closed = ct.checkLocationClosedness(); Assert.assertFalse(closed); closed = ct.checkLocationClosedness(); -// Assert.assertFalse(closed); -// closed = ct.checkLocationClosedness(); Assert.assertTrue(closed); boolean consistent = ct.checkLocationConsistency(); Assert.assertTrue(consistent); ct.expand(a1); consistent = ct.checkLocationConsistency(); -// Assert.assertFalse(consistent); -// consistent = ct.checkLocationConsistency(); Assert.assertTrue(consistent); ct.expand(a1a2); @@ -194,7 +190,6 @@ private RegisterAutomaton buildLocationConsistencyAutomaton() { RALocation l2 = ra.addState(true); RALocation l3 = ra.addState(true); RALocation l4 = ra.addState(false); -// RALocation l5 = ra.addState(false); Register r1 = new Register(DT, 1); Parameter p1 = new Parameter(DT, 1); @@ -231,8 +226,6 @@ private RegisterAutomaton buildLocationConsistencyAutomaton() { ra.addTransition(l4, A, new InputTransition(gT, A, l4, l4, assNo)); ra.addTransition(l4, B, new InputTransition(gT, B, l4, l4, assNo)); -// ra.addTransition(l5, A, new InputTransition(gT, A, l5, l5, assNo)); -// ra.addTransition(l5, B, new InputTransition(gT, B, l5, l5, assNo)); return ra; } diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java index 6ec65bf6..a7728e41 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/IOHandlingTest.java @@ -33,12 +33,9 @@ import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.RegisterGenerator; import de.learnlib.ralib.equivalence.IOEquivalenceTest; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOCache; import de.learnlib.ralib.oracles.io.IOFilter; import de.learnlib.ralib.oracles.io.IOOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.sul.DataWordSUL; @@ -198,12 +195,8 @@ public void testLearnIORAWithNoOutputParams() { ConstraintSolver solver = new ConstraintSolver(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(ioFilter, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), - teachers, consts, solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, IN, OK, NOK); + SLLambda sllambda = new SLLambda(mto, teachers, consts, true, solver, IN, OK, NOK); sllambda.learn(); @@ -245,12 +238,8 @@ public void testLearnIORAWithEqualOutputParam() { ConstraintSolver solver = new ConstraintSolver(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(ioFilter, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), - teachers, consts, solver); - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, IN, NOK, OUT); + SLLambda sllambda = new SLLambda(mto, teachers, consts, true, solver, IN, NOK, OUT); sllambda.learn(); @@ -293,12 +282,8 @@ public void testLearnIORAWithFreshOutputParam() { ConstraintSolver solver = new ConstraintSolver(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(ioFilter, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), - teachers, consts, solver); - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, IN, NOK, OUT); + SLLambda sllambda = new SLLambda(mto, teachers, consts, true, solver, IN, NOK, OUT); sllambda.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java index 7f04608b..c70c2ba6 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnABPOutputTest.java @@ -21,12 +21,9 @@ import de.learnlib.ralib.equivalence.IOEquivalenceTest; import de.learnlib.ralib.equivalence.IORandomWalk; import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOCache; import de.learnlib.ralib.oracles.io.IOFilter; import de.learnlib.ralib.oracles.io.IOOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.sul.DataWordSUL; @@ -80,13 +77,8 @@ public void testLearnABPOutput() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( ioFilter, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = - new MultiTheorySDTLogicOracle(consts, solver); - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + SLLambda sllambda = new SLLambda(mto, teachers, consts, true, solver, actions); IOEquivalenceTest ioEquiv = new IOEquivalenceTest( model, teachers, consts, true, actions); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java index f11affba..59591859 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnArrayListTest.java @@ -15,7 +15,6 @@ import org.testng.annotations.Test; import de.learnlib.query.DefaultQuery; -import de.learnlib.ralib.automata.RegisterAutomaton; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; @@ -24,10 +23,6 @@ import de.learnlib.ralib.example.list.ArrayListWrapper; import de.learnlib.ralib.learning.Hypothesis; import de.learnlib.ralib.oracles.DataWordOracle; -import de.learnlib.ralib.oracles.SDTLogicOracle; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.Theory; @@ -48,12 +43,7 @@ public void testLearnArrayList() { Constants consts = new Constants(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(oracle, teachers, consts, solver); - SDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - - SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, false, solver, ADD, REMOVE); + SLLambda learner = new SLLambda(mto, teachers, consts, false, solver, ADD, REMOVE); learner.learn(); // round 1: find all locations @@ -101,11 +91,8 @@ public void testArrayListNonDeterminacy() { ConstraintSolver solver = new ConstraintSolver(); Constants consts = new Constants(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(oracle, teachers, consts, solver); - SDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, ADD, REMOVE, VOID, TRUE, FALSE); + SLLambda learner = new SLLambda(mto, teachers, consts, true, solver, ADD, REMOVE, VOID, TRUE, FALSE); learner.learn(); Word ce = Word.fromSymbols( diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java index 3f2dcaba..c7135eed 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnEchoTest.java @@ -14,18 +14,14 @@ import de.learnlib.query.DefaultQuery; import de.learnlib.ralib.RaLibTestSuite; -import de.learnlib.ralib.automata.RegisterAutomaton; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; import de.learnlib.ralib.example.repeater.RepeaterSUL; import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOCache; import de.learnlib.ralib.oracles.io.IOFilter; import de.learnlib.ralib.oracles.io.IOOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.sul.SULOracle; @@ -54,12 +50,8 @@ public void testLearnEcho() { ConstraintSolver solver = new ConstraintSolver(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(oracle, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - - SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, sul.getActionSymbols()); + SLLambda learner = new SLLambda(mto, teachers, consts, true, solver, sul.getActionSymbols()); learner.learn(); Word ce = Word.fromSymbols( diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java index b2f817f9..cc5da395 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnLoginTest.java @@ -27,10 +27,7 @@ import de.learnlib.ralib.learning.Measurements; import de.learnlib.ralib.learning.RaLearningAlgorithmName; import de.learnlib.ralib.oracles.DataWordOracle; -import de.learnlib.ralib.oracles.SDTLogicOracle; import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.Theory; @@ -55,13 +52,8 @@ public void testLearnLogin() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, new Constants(), solver); - SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, - new Constants(), solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, + SLLambda sllambda = new SLLambda(mto, teachers, consts, false, solver, I_LOGIN, I_LOGOUT, I_REGISTER); sllambda.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java index e4b980ef..3f697294 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnMixedIOTest.java @@ -39,10 +39,7 @@ import de.learnlib.ralib.equivalence.IOEquivalenceTest; import de.learnlib.ralib.equivalence.IORandomWalk; import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.sul.DataWordSUL; @@ -101,12 +98,8 @@ public void testLearnMixedIO() { IOOracle ioOracle = new SULOracle(sul, ERROR); MultiTheoryTreeOracle mto = TestUtil.createMTO(ioOracle, teachers, consts, solver, inputs); - MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + SLLambda sllambda = new SLLambda(mto, teachers, consts, true, solver, actions); IORandomWalk iowalk = new IORandomWalk(random, sul, diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java index 3662e089..7882e895 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQIOTest.java @@ -40,10 +40,7 @@ import de.learnlib.ralib.equivalence.IORandomWalk; import de.learnlib.ralib.example.priority.PriorityQueueSUL; import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.sul.SULOracle; @@ -109,12 +106,7 @@ private Hypothesis learnPQ(long seed, Map teachers, Constants MultiTheoryTreeOracle mto = TestUtil.createMTO( ioOracle, teachers, consts, solver, sul.getInputSymbols()); - MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) - -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, + SLLambda sllambda = new SLLambda(mto, teachers, consts, true, solver, sul.getActionSymbols()); IORandomWalk iowalk = new IORandomWalk(random, diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java index 503a38ed..3f6df81c 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPQTest.java @@ -42,10 +42,6 @@ import de.learnlib.ralib.learning.Measurements; import de.learnlib.ralib.learning.RaLearningAlgorithmName; import de.learnlib.ralib.oracles.DataWordOracle; -import de.learnlib.ralib.oracles.SDTLogicOracle; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.Theory; @@ -74,12 +70,7 @@ public void testLearnPQ() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, new Constants(), solver); - SDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, false, solver, OFFER, POLL); + SLLambda sllambda = new SLLambda(mto, teachers, consts, false, solver, OFFER, POLL); sllambda.learn(); RegisterAutomaton hyp = sllambda.getHypothesis(); logger.log(Level.FINE, "HYP1: {0}", hyp); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java index 18b292cd..aa5e5568 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPadlock.java @@ -24,10 +24,7 @@ import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.ParameterGenerator; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator.RegisterGenerator; import de.learnlib.ralib.oracles.DataWordOracle; -import de.learnlib.ralib.oracles.SDTLogicOracle; import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.Theory; @@ -111,13 +108,7 @@ public void testLearnPadlock() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, new Constants(), solver); - SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, - new Constants(), solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, IN); + SLLambda sllambda = new SLLambda(mto, teachers, consts, false, solver, IN); sllambda.learn(); RegisterAutomaton hyp = sllambda.getHypothesis(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java index 01aa9fcb..6433a492 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnPalindromeIOTest.java @@ -16,12 +16,9 @@ import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.equivalence.IOEquivalenceTest; import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOCache; import de.learnlib.ralib.oracles.io.IOFilter; import de.learnlib.ralib.oracles.io.IOOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.sul.DataWordSUL; @@ -67,12 +64,8 @@ public void testLearnPalindromeIO() { IOFilter ioFilter = new IOFilter(ioCache, inputs); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(ioFilter, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + SLLambda sllambda = new SLLambda(mto, teachers, consts, true, solver, actions); IOEquivalenceTest ioEquiv = new IOEquivalenceTest( model, teachers, consts, true, actions); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java index 7efa08e0..35d43924 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnRepeaterTest.java @@ -13,7 +13,6 @@ import de.learnlib.query.DefaultQuery; import de.learnlib.ralib.RaLibTestSuite; -import de.learnlib.ralib.automata.RegisterAutomaton; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; @@ -21,12 +20,9 @@ import de.learnlib.ralib.example.repeater.RepeaterSUL; import de.learnlib.ralib.learning.Measurements; import de.learnlib.ralib.learning.QueryStatistics; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOCache; import de.learnlib.ralib.oracles.io.IOFilter; import de.learnlib.ralib.oracles.io.IOOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.sul.SULOracle; @@ -55,15 +51,11 @@ public void testLearnRepeater() { ConstraintSolver solver = new ConstraintSolver(); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(oracle, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); Measurements measurements = new Measurements(); QueryStatistics stats = new QueryStatistics(measurements, ioOracle); - SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, sul.getActionSymbols()); + SLLambda learner = new SLLambda(mto, teachers, consts, true, solver, sul.getActionSymbols()); learner.setStatisticCounter(stats); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java index aa1ebcbb..c0fdd967 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnSipIOTest.java @@ -20,12 +20,9 @@ import de.learnlib.ralib.equivalence.IOCounterexampleLoopRemover; import de.learnlib.ralib.equivalence.IOEquivalenceTest; import de.learnlib.ralib.learning.Hypothesis; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOCache; import de.learnlib.ralib.oracles.io.IOFilter; import de.learnlib.ralib.oracles.io.IOOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.sul.DataWordSUL; @@ -79,13 +76,8 @@ public void testLearnSipIO() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( ioFilter, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = - new MultiTheorySDTLogicOracle(consts, solver); - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + SLLambda sllambda = new SLLambda(mto, teachers, consts, true, solver, actions); IOEquivalenceTest ioEquiv = new IOEquivalenceTest( model, teachers, consts, true, actions); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java index c897a12f..f0b349f4 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/LearnStackTest.java @@ -63,7 +63,7 @@ public void testLearnStack() { new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, I_PUSH, I_POP); + SLLambda sllambda = new SLLambda(mto, teachers, consts, false, solver, I_PUSH, I_POP); sllambda.learn(); RegisterAutomaton hyp = sllambda.getHypothesis(); @@ -108,13 +108,7 @@ public void testLearnStackSwitchedCE() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, new Constants(), solver); - SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, - new Constants(), solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, I_PUSH, I_POP); + SLLambda sllambda = new SLLambda(mto, teachers, consts, false, solver, I_PUSH, I_POP); sllambda.learn(); RegisterAutomaton hyp = sllambda.getHypothesis(); @@ -170,13 +164,7 @@ public void testLearnStackLongCE() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( dwOracle, teachers, new Constants(), solver); - SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, - new Constants(), solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, I_PUSH, I_POP); + SLLambda sllambda = new SLLambda(mto, teachers, consts, false, solver, I_PUSH, I_POP); sllambda.learn(); RegisterAutomaton hyp = sllambda.getHypothesis(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java index 647058ec..e4fc0a65 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestDistinguishingSuffixOptimization.java @@ -21,10 +21,7 @@ import de.learnlib.ralib.data.VarMapping; import de.learnlib.ralib.learning.SymbolicSuffix; import de.learnlib.ralib.oracles.DataWordOracle; -import de.learnlib.ralib.oracles.SDTLogicOracle; import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.Theory; @@ -85,13 +82,7 @@ public void testDistinguishingSuffixOptimization() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(dwOracle, teachers, new Constants(), solver); - SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, - new Constants(), solver); - - SLLambda learner = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, A, B); + SLLambda learner = new SLLambda(mto, teachers, consts, false, solver, A, B); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java index 3d9a1241..18e886aa 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestQueryCount.java @@ -10,7 +10,6 @@ import de.learnlib.query.DefaultQuery; import de.learnlib.ralib.RaLibTestSuite; import de.learnlib.ralib.TestUtil; -import de.learnlib.ralib.automata.RegisterAutomaton; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; @@ -18,11 +17,7 @@ import de.learnlib.ralib.learning.Measurements; import de.learnlib.ralib.learning.MeasuringOracle; import de.learnlib.ralib.learning.QueryStatistics; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; -import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.sul.SULOracle; import de.learnlib.ralib.theory.Theory; @@ -51,14 +46,8 @@ public void testQueryCount() { ioOracle, teachers, consts, solver, sul.getInputSymbols()), measurements); - MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) - -> new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - QueryStatistics queryStats = new QueryStatistics(measurements, ioOracle); - SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, - consts, true, solver, sul.getActionSymbols()); + SLLambda learner = new SLLambda(mto, teachers, consts, true, solver, sul.getActionSymbols()); learner.setStatisticCounter(queryStats); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java index 849daf29..2e01a0ad 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSuffixOptimization.java @@ -18,7 +18,6 @@ import de.learnlib.ralib.CacheDataWordOracle; import de.learnlib.ralib.RaLibTestSuite; import de.learnlib.ralib.TestUtil; -import de.learnlib.ralib.automata.RegisterAutomaton; import de.learnlib.ralib.data.Constants; import de.learnlib.ralib.data.DataType; import de.learnlib.ralib.data.DataValue; @@ -28,13 +27,9 @@ import de.learnlib.ralib.learning.MeasuringOracle; import de.learnlib.ralib.learning.QueryStatistics; import de.learnlib.ralib.oracles.DataWordOracle; -import de.learnlib.ralib.oracles.SDTLogicOracle; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOCache; import de.learnlib.ralib.oracles.io.IOFilter; import de.learnlib.ralib.oracles.io.IOOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.sul.SULOracle; @@ -65,16 +60,11 @@ public void testLearnRepeaterSuffixOpt() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(oracle, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = - new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); Measurements measurements = new Measurements(); QueryStatistics stats = new QueryStatistics(measurements, sul); - SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, sul.getActionSymbols()); + SLLambda learner = new SLLambda(mto, teachers, consts, true, solver, sul.getActionSymbols()); learner.setStatisticCounter(stats); learner.learn(); @@ -119,12 +109,8 @@ public void testLearnPQSuffixOpt() { ConstraintSolver solver = TestUtil.getZ3Solver(); QueryStatistics stats = new QueryStatistics(m, ioCache); MeasuringOracle mto = new MeasuringOracle(new MultiTheoryTreeOracle(ioCache, teachers, consts, solver), m); - SDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - SLLambda learner = new SLLambda(mto, hypFactory, mlo, teachers, consts, false, solver, OFFER, POLL); + SLLambda learner = new SLLambda(mto, teachers, consts, false, solver, OFFER, POLL); learner.setStatisticCounter(stats); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java index 984f2695..33fa1e58 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestSymmetry.java @@ -23,10 +23,7 @@ import de.learnlib.ralib.data.util.SymbolicDataValueGenerator; import de.learnlib.ralib.learning.Hypothesis; import de.learnlib.ralib.oracles.DataWordOracle; -import de.learnlib.ralib.oracles.SDTLogicOracle; import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.theory.Theory; @@ -59,21 +56,9 @@ public void testLearnSymmetryExampleCT2() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(dwOracle, teachers, new Constants(), solver); - SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - - // System.out.println(sul); - // System.out.println("---------------------------------"); - -// RaLambda learner = new RaLambda(mto, hypFactory, slo, consts, false, false, A, B); -// learner.setSolver(solver); - SLLambda learner = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, A, B); + SLLambda learner = new SLLambda(mto, teachers, consts, false, solver, A, B); learner.learn(); - // System.out.println(learner.getHypothesis().toString()); - Word ce = Word.fromSymbols(new PSymbolInstance(A, new DataValue(T_INT, BigDecimal.ONE)), new PSymbolInstance(A, new DataValue(T_INT, new BigDecimal(2) )), @@ -81,11 +66,7 @@ public void testLearnSymmetryExampleCT2() { learner.addCounterexample(new DefaultQuery<>(ce, true)); learner.learn(); - // System.out.println(learner.getHypothesis().toString()); - Hypothesis hyp = learner.getHypothesis(); - // System.out.println(hyp.toString()); - // System.out.println(learner.getDT()); ce = Word.fromSymbols(new PSymbolInstance(A, new DataValue(T_INT, BigDecimal.ONE)), new PSymbolInstance(A, new DataValue(T_INT, new BigDecimal(2))), @@ -100,8 +81,6 @@ public void testLearnSymmetryExampleCT2() { learner.addCounterexample(new DefaultQuery<>(ce, true)); learner.learn(); - // System.out.println(learner.getHypothesis().toString()); - // System.out.println(learner.getDT()); Assert.assertTrue(learner.getHypothesis().accepts(ce)); } @@ -198,12 +177,7 @@ public void testLearnSymmetryExampleCT1() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(dwOracle, teachers, new Constants(), solver); - SDTLogicOracle slo = new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, new Constants(), solver); - - SLLambda learner = new SLLambda(mto, hypFactory, slo, teachers, consts, false, solver, A, B); + SLLambda learner = new SLLambda(mto, teachers, consts, false, solver, A, B); learner.learn(); diff --git a/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java b/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java index b69be264..a2bdbc04 100644 --- a/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java +++ b/src/test/java/de/learnlib/ralib/learning/ralambda/TestUnknownMemorable.java @@ -32,12 +32,9 @@ import de.learnlib.ralib.data.SymbolicDataValue.Register; import de.learnlib.ralib.data.VarMapping; import de.learnlib.ralib.data.util.SymbolicDataValueGenerator; -import de.learnlib.ralib.oracles.SimulatorOracle; -import de.learnlib.ralib.oracles.TreeOracleFactory; import de.learnlib.ralib.oracles.io.IOCache; import de.learnlib.ralib.oracles.io.IOFilter; import de.learnlib.ralib.oracles.io.IOOracle; -import de.learnlib.ralib.oracles.mto.MultiTheorySDTLogicOracle; import de.learnlib.ralib.oracles.mto.MultiTheoryTreeOracle; import de.learnlib.ralib.smt.ConstraintSolver; import de.learnlib.ralib.sul.DataWordSUL; @@ -189,11 +186,8 @@ public void testUnknownMemorable() { IOFilter oracle = new IOFilter(ioCache, inputSymbols); MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle(oracle, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = new MultiTheorySDTLogicOracle(consts, solver); - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + SLLambda sllambda = new SLLambda(mto, teachers, consts, true, solver, actions); sllambda.learn(); @@ -259,13 +253,8 @@ public void testSkippingMemorable() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( ioFilter, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = - new MultiTheorySDTLogicOracle(consts, solver); - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + SLLambda sllambda = new SLLambda(mto, teachers, consts, true, solver, actions); sllambda.learn(); String[] ces = {"IPRACK[0[int]] Otimeout[] IINVITE[1[int]] Otimeout[] / true", @@ -317,13 +306,8 @@ public void testSkippingMemorable2() { MultiTheoryTreeOracle mto = new MultiTheoryTreeOracle( ioFilter, teachers, consts, solver); - MultiTheorySDTLogicOracle mlo = - new MultiTheorySDTLogicOracle(consts, solver); - - TreeOracleFactory hypFactory = (RegisterAutomaton hyp) -> - new MultiTheoryTreeOracle(new SimulatorOracle(hyp), teachers, consts, solver); - SLLambda sllambda = new SLLambda(mto, hypFactory, mlo, teachers, consts, true, solver, actions); + SLLambda sllambda = new SLLambda(mto, teachers, consts, true, solver, actions); sllambda.learn(); String[] ces = {"IINVITE[0[int]] O100[0[int]] / true", From 51f1a3a3ef690ede29e348d49f83962ed030d2b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Mon, 22 Dec 2025 15:17:21 +0100 Subject: [PATCH 30/31] change name of tryEquality --- .../de/learnlib/ralib/theory/equality/EqualityTheory.java | 6 +++--- .../ralib/theory/inequality/InequalityTheoryWithEq.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java b/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java index 53c6a857..5f24241a 100644 --- a/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java +++ b/src/main/java/de/learnlib/ralib/theory/equality/EqualityTheory.java @@ -424,12 +424,12 @@ public Optional instantiate(Word prefix, vals.addAll(constants.values()); DataValue fresh = getFreshValue(new LinkedList<>(vals)); - if (tryEquality(guard, p, fresh, solver, constants)) { + if (isSatisfiableWithEquality(guard, p, fresh, solver, constants)) { return Optional.of(fresh); } for (DataValue val : vals) { - if (tryEquality(guard, p, val, solver, constants)) { + if (isSatisfiableWithEquality(guard, p, val, solver, constants)) { return Optional.of(val); } } @@ -437,7 +437,7 @@ public Optional instantiate(Word prefix, return Optional.empty(); } - private boolean tryEquality(Expression guard, Parameter p, DataValue val, ConstraintSolver solver, Constants consts) { + private boolean isSatisfiableWithEquality(Expression guard, Parameter p, DataValue val, ConstraintSolver solver, Constants consts) { Mapping valuation = new Mapping<>(); valuation.put(p, val); valuation.putAll(consts); diff --git a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java index 3f89fbd8..f87217cd 100644 --- a/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java +++ b/src/main/java/de/learnlib/ralib/theory/inequality/InequalityTheoryWithEq.java @@ -633,7 +633,7 @@ public Optional instantiate(Word prefix, .collect(Collectors.toSet())); DataValue fresh = getFreshValue(new LinkedList<>(vals)); - if (tryEquality(guard, p, fresh, solver)) { + if (isSatisfiableWithEquality(guard, p, fresh, solver)) { return Optional.of(fresh); } @@ -650,7 +650,7 @@ public Optional instantiate(Word prefix, } for (DataValue val : vals) { - if (tryEquality(guard, p, val, solver)) { + if (isSatisfiableWithEquality(guard, p, val, solver)) { return Optional.of(val); } } @@ -658,7 +658,7 @@ public Optional instantiate(Word prefix, return Optional.empty(); } - private boolean tryEquality(Expression guard, Parameter p, DataValue val, ConstraintSolver solver) { + private boolean isSatisfiableWithEquality(Expression guard, Parameter p, DataValue val, ConstraintSolver solver) { ParameterValuation valuation = new ParameterValuation(); valuation.put(p, val); return solver.isSatisfiable(guard, valuation); From 8f92335624f48200728d95b6d31ea395271e4200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20T=C3=A5quist?= Date: Mon, 22 Dec 2025 15:29:05 +0100 Subject: [PATCH 31/31] add note on deprecated methods --- src/main/java/de/learnlib/ralib/automata/Assignment.java | 4 ++++ src/main/java/de/learnlib/ralib/automata/Transition.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/de/learnlib/ralib/automata/Assignment.java b/src/main/java/de/learnlib/ralib/automata/Assignment.java index 2e469e41..1c777d16 100644 --- a/src/main/java/de/learnlib/ralib/automata/Assignment.java +++ b/src/main/java/de/learnlib/ralib/automata/Assignment.java @@ -62,6 +62,10 @@ public RegisterValuation valuation(RegisterValuation registers, ParameterValuati /* * @deprecated method is unsafe, use {@link #valuation()} instead + * Method is unsafe because it keeps registers that are not given a new assignment, which can cause + * a discrepancy in the number of registers a location has, depending on the path to the location. + * Method is deprecated rather than removed because the functionality is used by XML automata models. + * Removal of method requires refactoring of XML models. */ @Deprecated public RegisterValuation compute(RegisterValuation registers, ParameterValuation parameters, Constants consts) { diff --git a/src/main/java/de/learnlib/ralib/automata/Transition.java b/src/main/java/de/learnlib/ralib/automata/Transition.java index c90ebe1a..190a24b6 100644 --- a/src/main/java/de/learnlib/ralib/automata/Transition.java +++ b/src/main/java/de/learnlib/ralib/automata/Transition.java @@ -59,6 +59,10 @@ public RegisterValuation valuation(RegisterValuation registers, ParameterValuati /* * @deprecated method is unsafe, use {@link #valuation()} instead + * Method is unsafe because it keeps registers that are not given a new assignment, which can cause + * a discrepancy in the number of registers a location has, depending on the path to the location. + * Method is deprecated rather than removed because the functionality is used by XML automata models. + * Removal of method requires refactoring of XML models. */ @Deprecated public RegisterValuation execute(RegisterValuation registers, ParameterValuation parameters, Constants consts) {