specminers.smartic.MergingBlock.java Source code

Java tutorial

Introduction

Here is the source code for specminers.smartic.MergingBlock.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package specminers.smartic;

import cz.cuni.mff.ksi.jinfer.base.automaton.Automaton;
import cz.cuni.mff.ksi.jinfer.base.automaton.State;
import cz.cuni.mff.ksi.jinfer.base.automaton.Step;
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.stream.Collectors;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.tuple.Pair;

/**
 *
 * @author otmarpereira
 */
public class MergingBlock {

    public static final String EPSILON_TRANSITION_SYMBOL = "";

    Automaton<String> X;
    Automaton<String> Y;

    public MergingBlock() {
    }

    public boolean sourceNodesShareSuffixProbabilities(Step<String> s1, Step<String> s2) {
        return false;
    }

    public boolean transitionsAreEquivalent(Step<String> s1, Step<String> s2) {
        return false;
    }

    public Set<List<Step<String>>> getPrefixes(Automaton<String> aut, State<String> n) {
        Set<List<Step<String>>> prefixes = new HashSet<>();

        boolean containsSelfLoop = false;

        for (Step<String> t : aut.getReverseDelta().get(n)) {
            if (!t.getSource().equals(t.getDestination())) {
                Set<List<Step<String>>> preprefixes;
                preprefixes = getPrefixes(aut, t.getSource());

                if (!preprefixes.isEmpty()) {
                    for (List<Step<String>> pp : preprefixes) {
                        List<Step<String>> prefix;
                        prefix = new LinkedList<>(pp);
                        prefix.add(t);
                        prefixes.add(prefix);
                    }
                } else {

                    prefixes.add(new LinkedList<Step<String>>() {
                        {
                            add(t);
                        }
                    });
                }
            } else {
                containsSelfLoop = true;
            }
        }

        if (containsSelfLoop) { // Create one path using the loop once and another path not using the self loop.
            Step<String> selfLoop = aut.getFirstStep(n, n);

            Set<List<Step<String>>> prefixesWithSelfLoop = new HashSet<>();

            for (List<Step<String>> prefix : prefixes) {
                List<Step<String>> prefixWithSelfLoop = new LinkedList<>(prefix);
                prefixWithSelfLoop.add(selfLoop);
                prefixesWithSelfLoop.add(prefixWithSelfLoop);
            }

            prefixes.addAll(prefixesWithSelfLoop);

        }
        return prefixes;
    }

    public boolean pairIsUnifiable(Automaton<String> x, State<String> nodeX, Automaton<String> y,
            State<String> nodeY) {
        Set<List<Step<String>>> prefixesX = this.getPrefixes(x, nodeX);
        Set<List<Step<String>>> prefixesY = this.getPrefixes(y, nodeY);

        return prefixesX.containsAll(prefixesY) && prefixesY.containsAll(prefixesX);
    }

    public boolean pairIsMergeable(Automaton<String> x, State<String> nodeX, Automaton<String> y,
            State<String> nodeY) {
        Set<List<Step<String>>> suffixesX = this.getSuffixes(x, nodeX);
        Set<List<Step<String>>> suffixesY = this.getSuffixes(y, nodeY);

        return suffixesX.containsAll(suffixesY) && suffixesY.containsAll(suffixesX);
    }

    public Set<Pair<State<String>, State<String>>> getUnifiablePairs(Automaton<String> x, Automaton<String> y) {
        Set<Pair<State<String>, State<String>>> pairs = new HashSet<>();

        Set<List<Step<String>>> allPathsForX = getSuffixes(x, x.getInitialState());
        Set<List<Step<String>>> allPathsForY = getSuffixes(y, y.getInitialState());

        for (List<Step<String>> pathX : allPathsForX) {
            for (List<Step<String>> pathY : allPathsForY) {
                for (Step<String> tx : pathX) {
                    for (Step<String> ty : pathY) {
                        if (pairIsUnifiable(x, tx.getSource(), y, ty.getSource())) {
                            pairs.add(Pair.of(tx.getSource(), ty.getSource()));
                        }

                        if (pairIsUnifiable(x, tx.getSource(), y, ty.getDestination())) {
                            pairs.add(Pair.of(tx.getSource(), ty.getDestination()));
                        }

                        if (pairIsUnifiable(x, tx.getDestination(), y, ty.getSource())) {
                            pairs.add(Pair.of(tx.getDestination(), ty.getSource()));
                        }

                        if (pairIsUnifiable(x, tx.getDestination(), y, ty.getDestination())) {
                            pairs.add(Pair.of(tx.getDestination(), ty.getDestination()));
                        }
                    }
                }
            }
        }
        return pairs;
    }

    public Set<Pair<State<String>, State<String>>> getMergeablePairs(Automaton<String> x, Automaton<String> y) {
        Set<Pair<State<String>, State<String>>> pairs = new HashSet<>();

        State<String> acceptingX = x.getDelta().keySet().stream().filter(s -> s.getFinalCount() > 0).findFirst()
                .get();
        State<String> acceptingY = y.getDelta().keySet().stream().filter(s -> s.getFinalCount() > 0).findFirst()
                .get();

        Set<List<Step<String>>> allPathsForX = getPrefixes(x, acceptingX);
        Set<List<Step<String>>> allPathsForY = getPrefixes(y, acceptingY);

        for (List<Step<String>> pathX : allPathsForX) {
            for (List<Step<String>> pathY : allPathsForY) {
                for (Step<String> tx : pathX) {
                    for (Step<String> ty : pathY) {
                        if (pairIsMergeable(x, tx.getSource(), y, ty.getSource())) {
                            pairs.add(Pair.of(tx.getSource(), ty.getSource()));
                        }

                        if (pairIsMergeable(x, tx.getSource(), y, ty.getDestination())) {
                            pairs.add(Pair.of(tx.getSource(), ty.getDestination()));
                        }

                        if (pairIsMergeable(x, tx.getDestination(), y, ty.getSource())) {
                            pairs.add(Pair.of(tx.getDestination(), ty.getSource()));
                        }

                        if (pairIsMergeable(x, tx.getDestination(), y, ty.getDestination())) {
                            pairs.add(Pair.of(tx.getDestination(), ty.getDestination()));
                        }
                    }
                }
            }
        }

        return pairs;
    }

    public Automaton<String> getTopPartiallyMergedAutomaton(Set<Pair<State<String>, State<String>>> unifiableList,
            Automaton<String> x, Automaton<String> y) {
        Automaton<String> aut = new Automaton<>(0, false);

        Map<Pair<State<String>, State<String>>, State<String>> pairNewStates;
        pairNewStates = new HashMap<>();

        // create states
        for (Pair<State<String>, State<String>> pair : unifiableList) {
            State<String> s = aut.createNewState();
            pairNewStates.put(pair, s);
        }

        Map<State<String>, Set<Pair<State<String>, State<String>>>> xStatesInUnifiableList = new HashMap<>();
        Map<State<String>, Set<Pair<State<String>, State<String>>>> yStatesInUnifiableList = new HashMap<>();

        for (Pair<State<String>, State<String>> pair : unifiableList) {
            State<String> xState = pair.getLeft();
            State<String> yState = pair.getRight();

            if (xStatesInUnifiableList.containsKey(xState)) {
                xStatesInUnifiableList.get(xState).add(pair);
            } else {
                xStatesInUnifiableList.put(xState, new HashSet<>());
                xStatesInUnifiableList.get(xState).add(pair);
            }

            if (yStatesInUnifiableList.containsKey(yState)) {
                yStatesInUnifiableList.get(yState).add(pair);
            } else {
                yStatesInUnifiableList.put(yState, new HashSet<>());
                yStatesInUnifiableList.get(yState).add(pair);
            }
        }

        for (Pair<State<String>, State<String>> pair : pairNewStates.keySet()) {
            // Create transitions to states from X present in unifiable list.
            State<String> xState = pair.getLeft();
            State<String> newState = pairNewStates.get(pair);

            for (Step<String> tx : x.getDelta().get(xState)) {
                if (xStatesInUnifiableList.containsKey(tx.getDestination())) {
                    for (Pair<State<String>, State<String>> p2 : xStatesInUnifiableList.get(xState)) {
                        State<String> newStateP2 = pairNewStates.get(p2);

                        aut.createNewStep(tx.getAcceptSymbol(), newState, newStateP2);
                    }
                }
            }

            State<String> yState = pair.getRight();

            for (Step<String> ty : y.getDelta().get(yState)) {
                if (yStatesInUnifiableList.containsKey(ty.getDestination())) {
                    for (Pair<State<String>, State<String>> p2 : yStatesInUnifiableList.get(yState)) {
                        State<String> newStateP2 = pairNewStates.get(p2);

                        aut.createNewStep(ty.getAcceptSymbol(), newState, newStateP2);
                    }
                }
            }
        }

        return aut;
    }

    public Automaton<String> getBottomPartiallyMergedAutomaton(Set<Pair<State<String>, State<String>>> mergeable,
            Automaton<String> x, Automaton<String> y) {
        Automaton<String> aut = new Automaton<>(0, false);

        Map<Pair<State<String>, State<String>>, State<String>> pairNewStates;
        pairNewStates = new HashMap<>();

        // create states
        for (Pair<State<String>, State<String>> pair : mergeable) {
            State<String> s = aut.createNewState();
            pairNewStates.put(pair, s);
        }

        Map<State<String>, Set<Pair<State<String>, State<String>>>> xStatesInMergeableList = new HashMap<>();
        Map<State<String>, Set<Pair<State<String>, State<String>>>> yStatesInMergeableList = new HashMap<>();

        for (Pair<State<String>, State<String>> pair : mergeable) {
            State<String> xState = pair.getLeft();
            State<String> yState = pair.getRight();

            if (xStatesInMergeableList.containsKey(xState)) {
                xStatesInMergeableList.get(xState).add(pair);
            } else {
                xStatesInMergeableList.put(xState, new HashSet<>());
                xStatesInMergeableList.get(xState).add(pair);
            }

            if (yStatesInMergeableList.containsKey(yState)) {
                yStatesInMergeableList.get(yState).add(pair);
            } else {
                yStatesInMergeableList.put(yState, new HashSet<>());
                yStatesInMergeableList.get(yState).add(pair);
            }
        }

        for (Pair<State<String>, State<String>> pair : pairNewStates.keySet()) {
            // Create transitions to states from X present in unifiable list.
            State<String> xState = pair.getLeft();
            State<String> newState = pairNewStates.get(pair);

            for (Step<String> tx : x.getDelta().get(xState)) {
                if (xStatesInMergeableList.containsKey(tx.getDestination())) {
                    for (Pair<State<String>, State<String>> p2 : xStatesInMergeableList.get(xState)) {
                        State<String> newStateP2 = pairNewStates.get(p2);

                        aut.createNewStep(tx.getAcceptSymbol(), newState, newStateP2);
                    }
                }
            }

            State<String> yState = pair.getRight();

            for (Step<String> ty : y.getDelta().get(yState)) {
                if (yStatesInMergeableList.containsKey(ty.getDestination())) {
                    for (Pair<State<String>, State<String>> p2 : yStatesInMergeableList.get(yState)) {
                        State<String> newStateP2 = pairNewStates.get(p2);

                        aut.createNewStep(ty.getAcceptSymbol(), newState, newStateP2);
                    }
                }
            }
        }

        return aut;
    }

    public Automaton<String> mergeAutomatons(Automaton<String> x, Automaton<String> y, Automaton<String> top,
            Automaton<String> bottom) {
        Automaton<String> aut = new Automaton<String>();

        Set<State<String>> initialStates = new HashSet<>();

        initialStates.add(x.getInitialState());
        initialStates.add(y.getInitialState());
        initialStates.add(top.getInitialState());
        initialStates.add(bottom.getInitialState());

        return aut;
    }

    public Set<List<Step<String>>> getSuffixes(Automaton<String> aut, State<String> n) {
        Set<List<Step<String>>> suffixes = new HashSet<>();
        boolean addedSelfLoop = false;
        boolean anyOutwardTransitionAfterSelfLoop = false;

        for (Step<String> t : aut.getDelta().get(n)) {
            if (!t.getSource().equals(t.getDestination())) {
                anyOutwardTransitionAfterSelfLoop = true;
                Set<List<Step<String>>> susufixes;
                susufixes = getSuffixes(aut, t.getDestination());

                Set<List<Step<String>>> susuffixesWithSelfLoop = susufixes.stream().filter(suf -> {
                    Step<String> lastStep = suf.get(suf.size() - 1);
                    return lastStep.getSource().equals(lastStep.getDestination());
                }).collect(Collectors.toSet());

                for (List<Step<String>> susufWithSelfLoop : susuffixesWithSelfLoop) {
                    List<Step<String>> susufWithoutSelfLoop = susufWithSelfLoop.stream()
                            .limit(susufWithSelfLoop.size() - 1).collect(Collectors.toList());

                    susufixes.add(susufWithoutSelfLoop);
                }

                if (!susufixes.isEmpty()) {
                    for (List<Step<String>> pp : susufixes) {
                        List<Step<String>> sufix;
                        sufix = new LinkedList<>(pp);
                        sufix.add(0, t);
                        suffixes.add(sufix);
                    }
                } else {

                    suffixes.add(new LinkedList<Step<String>>() {
                        {
                            add(t);
                        }
                    });
                }
            } else {
                if (!addedSelfLoop) {
                    if (t.getDestination().isFinal()) {
                        suffixes.add(new LinkedList<Step<String>>() {
                            {
                                add(t);
                            }
                        });
                    }
                    addedSelfLoop = true;
                }
            }
        }

        if (anyOutwardTransitionAfterSelfLoop && addedSelfLoop) {
            Step<String> selfLoop = aut.getFirstStep(n, n);

            Set<List<Step<String>>> suffixesWithSelfLoop = new HashSet<>();

            for (List<Step<String>> suffix : suffixes) {
                List<Step<String>> suffixWithSelfLoop = new LinkedList<>(suffix);
                suffixWithSelfLoop.add(0, selfLoop);
                suffixesWithSelfLoop.add(suffixWithSelfLoop);
            }

            suffixes.addAll(suffixesWithSelfLoop);
        }

        return suffixes;
    }

    public void handleExceptionalCases(Automaton<String> automaton) {
        State startNode = automaton.getInitialState();

        Map<State<String>, Set<Step<String>>> d = automaton.getDelta();

        boolean startNodeIsSinkOfATransition = d.keySet().stream()
                .anyMatch(s -> d.get(s).stream().anyMatch(t -> t.getDestination().equals(startNode)));

        if (startNodeIsSinkOfATransition) {
            automaton.createNewDummyInitialState(EPSILON_TRANSITION_SYMBOL);
        }
    }

    public List<List<String>> getAllStringsAcceptedByAutomaton(List<Trace> traces, Automaton<String> automaton) {
        List<List<String>> accepted = new LinkedList<>();
        Set<List<String>> rejected = new HashSet<>();

        for (Trace t : traces) {
            List<String> events = t.getEvents();
            if (events.isEmpty()) {
                continue;
            }
            State<String> currentState = automaton.getInitialState();
            boolean recognized = true;

            for (String e : events) {
                Step<String> next = automaton.getOutStepOnSymbol(currentState, e);

                if (next != null) {
                    currentState = next.getDestination();
                } else {
                    recognized = false;
                    break;
                }
            }

            if (recognized && currentState.getFinalCount() > 0) {
                accepted.add(events);
            } else {
                rejected.add(events);
            }
        }

        return accepted;
    }

    public Automaton<String> getMergedAutomaton(Automaton<String> x, Automaton<String> y, List<Trace> trainSetX,
            List<Trace> trainSetY) {
        Automaton<String> merged = null;

        double weightX = 1.0 * trainSetX.size() / (trainSetX.size() + trainSetY.size());
        double weightY = 1.0 * trainSetY.size() / (trainSetX.size() + trainSetY.size());

        handleExceptionalCases(x);
        handleExceptionalCases(y);

        Set<Pair<State<String>, State<String>>> unifiableList = createUnifiableList(x, y, true);
        Set<Pair<State<String>, State<String>>> mergeableList = createUnifiableList(x, y, false);

        return merged;
    }

    public ECDataStructure createEquivalenceClass(Set<Pair<State<String>, State<String>>> mergeableNodes,
            Set<State<String>> representativeObjects) {

        Automaton<String> bottom = new Automaton<String>(0, false);

        for (Pair<State<String>, State<String>> pair : mergeableNodes) {
            State<String> nx = pair.getLeft();

            State<String> equivY = pair.getRight();
        }

        ECDataStructure DS = null;

        return DS;
    }

    public List<State<String>> getNodesByBreadthFirstSearch(Automaton<String> automaton) {
        LinkedList<State<String>> V = new LinkedList<>();
        Queue<State<String>> Q = new LinkedBlockingDeque<>();

        V.add(automaton.getInitialState());
        Q.add(automaton.getInitialState());

        while (!Q.isEmpty()) {
            State<String> t = Q.poll();

            for (Step<String> delta : automaton.getDelta().get(t)) {
                State<String> u = delta.getDestination();

                if (!V.contains(u)) {
                    V.add(u);
                    Q.add(u);
                }
            }
        }

        return V;
    }

    public boolean checkUnifiable(State<String> nx, State<String> ny, boolean isTopDown, Automaton<String> x,
            Automaton<String> y) {

        Set<List<Step<String>>> txS = new HashSet<>();
        Set<List<Step<String>>> tyS = new HashSet<>();

        if (!isTopDown) {
            txS = getSuffixes(x, nx);
            tyS = getSuffixes(y, ny);
        } else {
            txS = getPrefixes(x, nx);
            tyS = getPrefixes(y, ny);
        }

        boolean isUnifiable = false;

        Set<List<TransitionString>> xTransitionList = txS.stream().map(lx -> {
            List<TransitionString> trx = lx.stream().map(sx -> new TransitionString(sx, x))
                    .collect(Collectors.toList());
            return trx;
        }).collect(Collectors.toSet());

        Set<List<TransitionString>> yTransitionList = tyS.stream().map(ly -> {
            List<TransitionString> trx = ly.stream().map(sy -> new TransitionString(sy, y))
                    .collect(Collectors.toList());
            return trx;
        }).collect(Collectors.toSet());

        isUnifiable = yTransitionList.equals(xTransitionList);

        return isUnifiable;
    }

    public Set<Pair<State<String>, State<String>>> createUnifiableList(Automaton<String> x, Automaton<String> y,
            boolean isTopDown) {
        List<State<String>> nodesX = getNodesByBreadthFirstSearch(x);
        List<State<String>> nodesY = getNodesByBreadthFirstSearch(y);

        Set<Pair<State<String>, State<String>>> uni = new HashSet<>();

        if (!isTopDown) {
            Collections.reverse(nodesX);
            Collections.reverse(nodesY);
        }
        Set<Pair<State<String>, State<String>>> pairSet = new HashSet<>();

        nodesX.forEach(xNode -> nodesY.forEach(yNode -> pairSet.add(Pair.of(xNode, yNode))));

        pairSet.stream()
                .filter((pairNxNy) -> (checkUnifiable(pairNxNy.getLeft(), pairNxNy.getRight(), isTopDown, x, y)))
                .forEach((pairNxNy) -> {
                    uni.add(pairNxNy);
                });

        return uni;
    }
}