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

net.automatalib.util.automata.conformance.IncrementalWMethodTestsIterator Maven / Gradle / Ivy

Go to download

This artifact provides various common utility operations for analyzing and manipulating automata and graphs, such as traversal, minimization and copying.

There is a newer version: 0.11.0
Show newest version
/* Copyright (C) 2013-2019 TU Dortmund
 * This file is part of AutomataLib, http://www.automatalib.net/.
 *
 * 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 net.automatalib.util.automata.conformance;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import net.automatalib.automata.UniversalDeterministicAutomaton;
import net.automatalib.util.automata.Automata;
import net.automatalib.util.automata.cover.Covers;
import net.automatalib.words.Alphabet;
import net.automatalib.words.Word;

/**
 * An iterator that enumerates the test cases as obtained through the W method conformance test in an incremental
 * fashion.
 *
 * @param 
 *         input symbol type
 *
 * @author Malte Isberner
 */
public class IncrementalWMethodTestsIterator implements Iterator> {

    private final Alphabet alphabet;
    private final StrictPriorityQueue> itemQueue;
    private final List> prefixes = new ArrayList<>();
    private final List> suffixes = new ArrayList<>();
    private int maxDepth;

    public IncrementalWMethodTestsIterator(Alphabet alphabet) {
        this.alphabet = alphabet;
        this.itemQueue = new StrictPriorityQueue<>(new ItemComparator<>(alphabet), new ItemMerge<>());
    }

    public int getMaxDepth() {
        return maxDepth;
    }

    public void setMaxDepth(int maxDepth) {
        this.maxDepth = maxDepth;
    }

    public void update(UniversalDeterministicAutomaton automaton) {
        int oldNumPrefixes = prefixes.size();
        boolean newPrefixes = Covers.incrementalTransitionCover(automaton, alphabet, prefixes, prefixes);

        int oldNumSuffixes = suffixes.size();
        boolean newSuffixes = Automata.incrementalCharacterizingSet(automaton, alphabet, suffixes, suffixes);

        // old prefixes with all *new* suffixes
        if (newSuffixes && oldNumPrefixes > 0) {
            Item item = new Item<>();
            item.prefixIdx = 0;
            item.minPrefix = 0;
            item.maxPrefix = oldNumPrefixes;
            item.suffixIdx = oldNumSuffixes;
            item.minSuffix = oldNumSuffixes;
            item.middle = startMiddleWord();
            itemQueue.insert(item);
        }
        // new prefixes with *all* suffixes
        if (newPrefixes) {
            Item item = new Item<>();
            item.prefixIdx = oldNumPrefixes;
            item.minPrefix = oldNumPrefixes;
            item.maxPrefix = prefixes.size();
            item.suffixIdx = 0;
            item.minSuffix = 0;
            item.middle = startMiddleWord();
            itemQueue.insert(item);
        }
    }

    private Word startMiddleWord() {
        return Word.epsilon();
    }

    @Override
    public boolean hasNext() {
        return !itemQueue.isEmpty();
    }

    @Override
    public Word next() {
        Item nextItem = itemQueue.extractMin();

        Word result = assembleWord(nextItem);
        Item inc = increment(nextItem);
        if (inc != null) {
            itemQueue.insert(inc);
        }
        return result;
    }

    private Word assembleWord(Item item) {
        Word prefix = prefixes.get(item.prefixIdx);
        Word suffix = suffixes.get(item.suffixIdx);
        return prefix.concat(item.middle, suffix);
    }

    private Item increment(Item item) {
        item.suffixIdx++;
        if (item.suffixIdx >= suffixes.size()) {
            item.suffixIdx = item.minSuffix;

            item.prefixIdx++;
            if (item.prefixIdx >= item.maxPrefix) {
                item.prefixIdx = item.minPrefix;

                item.middle = item.middle.canonicalNext(alphabet);
                if (item.middle.length() > maxDepth) {
                    return null;
                }
            }
        }

        return item;
    }

    private static final class Item {

        private int prefixIdx;
        private int suffixIdx;
        private Word middle;

        private int minSuffix;
        private int minPrefix;
        private int maxPrefix;

        @Override
        public String toString() {
            return Integer.toString(prefixIdx) + " | " + middle + " | " + Integer.toString(suffixIdx);
        }
    }

    private static final class ItemMerge implements StrictPriorityQueue.MergeOperation> {

        @Override
        public Item merge(Item oldObject, Item newObject) {
            oldObject.minSuffix = Math.min(oldObject.minSuffix, newObject.minSuffix);
            oldObject.minPrefix = Math.min(oldObject.minPrefix, newObject.minPrefix);
            oldObject.maxPrefix = Math.max(oldObject.maxPrefix, newObject.maxPrefix);
            return oldObject;
        }

    }

    private static final class ItemComparator implements Comparator> {

        private final Comparator> canonicalCmp;

        ItemComparator(Comparator symComparator) {
            this.canonicalCmp = Word.canonicalComparator(symComparator);
        }

        @Override
        public int compare(Item o1, Item o2) {
            int cmp = canonicalCmp.compare(o1.middle, o2.middle);
            if (cmp != 0) {
                return cmp;
            }

            cmp = o1.prefixIdx - o2.prefixIdx;
            if (cmp != 0) {
                return cmp;
            }

            return o1.suffixIdx - o2.suffixIdx;
        }
    }

}