All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.learnlib.algorithms.adt.config.LeafSplitters Maven / Gradle / Ivy

/* Copyright (C) 2013-2018 TU Dortmund
 * This file is part of LearnLib, http://www.learnlib.de/.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.learnlib.algorithms.adt.config;

import java.util.Iterator;
import java.util.Map;

import de.learnlib.algorithms.adt.adt.ADTLeafNode;
import de.learnlib.algorithms.adt.adt.ADTNode;
import de.learnlib.algorithms.adt.adt.ADTResetNode;
import de.learnlib.algorithms.adt.adt.ADTSymbolNode;
import de.learnlib.algorithms.adt.api.LeafSplitter;
import de.learnlib.algorithms.adt.util.ADTUtil;
import net.automatalib.commons.util.Pair;
import net.automatalib.words.Word;

/**
 * A collection of default {@link LeafSplitter} configurations.
 *
 * @author frohme
 */
public final class LeafSplitters {

    public static final LeafSplitter DEFAULT_SPLITTER = LeafSplitters::splitIntoNewADS;

    public static final LeafSplitter EXTEND_PARENT = new LeafSplitter() {

        @Override
        public  ADTNode split(ADTNode nodeToSplit,
                                                Word distinguishingSuffix,
                                                Word oldOutput,
                                                Word newOutput) {

            if (canSplitParent(nodeToSplit, distinguishingSuffix, oldOutput, newOutput)) {
                return splitParent(nodeToSplit, distinguishingSuffix, oldOutput, newOutput);
            }

            return splitIntoNewADS(nodeToSplit, distinguishingSuffix, oldOutput, newOutput);
        }
    };

    private LeafSplitters() {
        // prevent instantiation
    }

    private static  boolean canSplitParent(final ADTNode nodeToSplit,
                                                    final Word distinguishingSuffix,
                                                    final Word hypothesisOutput,
                                                    final Word newOutput) {

        // initial split
        if (nodeToSplit.getParent() == null) {
            return false;
        }

        final Pair, Word> trace = ADTUtil.buildTraceForNode(nodeToSplit);
        final Word traceInput = trace.getFirst();
        final Word traceOutput = trace.getSecond();

        return traceInput.isPrefixOf(distinguishingSuffix) && traceOutput.isPrefixOf(newOutput) &&
               traceOutput.isPrefixOf(hypothesisOutput);
    }

    private static  ADTNode splitIntoNewADS(final ADTNode nodeToSplit,
                                                              final Word distinguishingSuffix,
                                                              final Word oldOutput,
                                                              final Word newOutput) {

        final Iterator suffixIter = distinguishingSuffix.iterator();

        // Replace old final state
        final ADTNode parent = nodeToSplit.getParent();
        final ADTNode newADS = new ADTSymbolNode<>(null, suffixIter.next());

        if (parent != null) { // if parent == null, we split the initial node
            boolean foundSuccessor = false;
            for (Map.Entry> entry : parent.getChildren().entrySet()) {
                if (entry.getValue().equals(nodeToSplit)) {
                    final ADTNode reset = new ADTResetNode<>(newADS);

                    reset.setParent(parent);
                    parent.getChildren().put(entry.getKey(), reset);
                    newADS.setParent(reset);

                    foundSuccessor = true;
                    break;
                }
            }

            if (!foundSuccessor) {
                throw new IllegalStateException();
            }
        }

        return finalizeSplit(nodeToSplit, newADS, suffixIter, oldOutput.iterator(), newOutput.iterator());
    }

    private static  ADTNode finalizeSplit(final ADTNode nodeToSplit,
                                                            final ADTNode adtRoot,
                                                            final Iterator suffixIter,
                                                            final Iterator oldIter,
                                                            final Iterator newIter) {

        ADTNode previous = adtRoot;
        O oldOut = oldIter.next();
        O newOut = newIter.next();

        while (oldOut.equals(newOut)) {
            final ADTNode next = new ADTSymbolNode<>(previous, suffixIter.next());

            previous.getChildren().put(oldOut, next);

            oldOut = oldIter.next();
            newOut = newIter.next();
            previous = next;
        }

        final ADTNode oldFinalNode = nodeToSplit;
        final ADTNode newFinalNode = new ADTLeafNode<>(previous, null);

        oldFinalNode.setParent(previous);
        newFinalNode.setParent(previous);

        previous.getChildren().put(oldOut, oldFinalNode);
        previous.getChildren().put(newOut, newFinalNode);

        return newFinalNode;
    }

    public static  ADTNode splitParent(final ADTNode nodeToSplit,
                                                         final Word distinguishingSuffix,
                                                         final Word oldOutput,
                                                         final Word newOutput) {

        final ADTNode previousADS = ADTUtil.getStartOfADS(nodeToSplit);

        final Iterator suffixIter = distinguishingSuffix.iterator();
        final Iterator oldIter = oldOutput.iterator();
        final Iterator newIter = newOutput.iterator();
        ADTNode adsIter = previousADS;
        O newSuffixOutput = null;

        while (!ADTUtil.isLeafNode(adsIter)) {

            // Forward other iterators
            suffixIter.next();
            newIter.next();
            newSuffixOutput = oldIter.next();

            adsIter = adsIter.getChildren().get(newSuffixOutput);
        }

        final ADTNode continuedADS = new ADTSymbolNode<>(adsIter.getParent(), suffixIter.next());

        adsIter.getParent().getChildren().put(newSuffixOutput, continuedADS);

        return finalizeSplit(nodeToSplit, continuedADS, suffixIter, oldIter, newIter);
    }
}