net.automatalib.util.automata.conformance.WpMethodTestsIterator.java Source code

Java tutorial

Introduction

Here is the source code for net.automatalib.util.automata.conformance.WpMethodTestsIterator.java

Source

/* Copyright (C) 2013-2018 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.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.annotation.ParametersAreNonnullByDefault;

import com.google.common.collect.Sets;
import net.automatalib.automata.UniversalDeterministicAutomaton;
import net.automatalib.commons.util.collections.AbstractThreeLevelIterator;
import net.automatalib.commons.util.collections.CollectionsUtil;
import net.automatalib.commons.util.collections.ConcatIterator;
import net.automatalib.commons.util.collections.ReusableIterator;
import net.automatalib.commons.util.mappings.MutableMapping;
import net.automatalib.util.automata.Automata;
import net.automatalib.util.automata.cover.Covers;
import net.automatalib.util.automata.equivalence.CharacterizingSets;
import net.automatalib.words.Word;
import net.automatalib.words.WordBuilder;

/**
 * Iterator that returns test words generated by the partial W Method.
 * <p>
 * See "Test selection based on finite state models" by S. Fujiwara et al.
 *
 * @param <I>
 *         input symbol type
 *
 * @author frohme
 */
@ParametersAreNonnullByDefault
public class WpMethodTestsIterator<I> extends ConcatIterator<Word<I>> {

    public WpMethodTestsIterator(UniversalDeterministicAutomaton<?, I, ?, ?, ?> automaton,
            Collection<? extends I> alphabet, int maxDepth) {
        super(buildIterators(automaton, alphabet, maxDepth));
    }

    @SuppressWarnings("unchecked")
    private static <I> Iterator<Word<I>>[] buildIterators(UniversalDeterministicAutomaton<?, I, ?, ?, ?> automaton,
            Collection<? extends I> inputs, int maxDepth) {

        final Set<Word<I>> stateCover = Sets.newHashSetWithExpectedSize(automaton.size());
        final Set<Word<I>> transitionCover = Sets.newHashSetWithExpectedSize(automaton.size() * inputs.size());

        Covers.cover(automaton, inputs, stateCover, transitionCover);

        final Iterable<Word<I>> characterizingSet;
        final Iterator<Word<I>> characterizingIter = CharacterizingSets.characterizingSetIterator(automaton,
                inputs);

        // Special case: List of characterizing suffixes may be empty,
        // but in this case we still need to iterate over the prefixes!
        if (!characterizingIter.hasNext()) {
            characterizingSet = Collections.singletonList(Word.epsilon());
        } else {
            characterizingSet = new ReusableIterator<>(characterizingIter);
        }

        // Phase 1: state cover * middle part * global suffixes
        final Iterator<Word<I>> firstIterator = new FirstPhaseIterator<>(stateCover,
                CollectionsUtil.allTuples(inputs, 0, maxDepth), characterizingSet);

        // Phase 2: transitions (not in state cover) * middle part * local suffixes
        transitionCover.removeAll(stateCover);
        final Iterator<Word<I>> secondIterator = new SecondPhaseIterator<>(automaton, inputs, transitionCover,
                CollectionsUtil.allTuples(inputs, 0, maxDepth));

        return new Iterator[] { firstIterator, secondIterator };
    }

    private static class FirstPhaseIterator<I>
            extends AbstractThreeLevelIterator<List<I>, Word<I>, Word<I>, Word<I>> {

        private final Iterable<Word<I>> prefixes;
        private final Iterable<Word<I>> suffixes;

        private final WordBuilder<I> wordBuilder = new WordBuilder<>();

        FirstPhaseIterator(Iterable<Word<I>> prefixes, Iterable<List<I>> middleParts, Iterable<Word<I>> suffixes) {
            super(middleParts.iterator());

            this.prefixes = prefixes;
            this.suffixes = suffixes;
        }

        @Override
        protected Iterator<Word<I>> l2Iterator(List<I> l1Object) {
            return prefixes.iterator();
        }

        @Override
        protected Iterator<Word<I>> l3Iterator(List<I> l1Object, Word<I> l2Object) {
            return suffixes.iterator();
        }

        @Override
        protected Word<I> combine(List<I> middle, Word<I> prefix, Word<I> suffix) {
            Word<I> word = wordBuilder.append(prefix).append(middle).append(suffix).toWord();
            wordBuilder.clear();
            return word;
        }
    }

    private static class SecondPhaseIterator<S, I>
            extends AbstractThreeLevelIterator<List<I>, Word<I>, Word<I>, Word<I>> {

        private final UniversalDeterministicAutomaton<S, I, ?, ?, ?> automaton;
        private final Collection<? extends I> inputs;

        private final MutableMapping<S, List<Word<I>>> localSuffixSets;
        private final Iterable<Word<I>> prefixes;

        private final WordBuilder<I> wordBuilder = new WordBuilder<>();

        SecondPhaseIterator(UniversalDeterministicAutomaton<S, I, ?, ?, ?> automaton,
                Collection<? extends I> inputs, Iterable<Word<I>> prefixes, Iterable<List<I>> middleParts) {
            super(middleParts.iterator());

            this.automaton = automaton;
            this.inputs = inputs;
            this.localSuffixSets = automaton.createStaticStateMapping();
            this.prefixes = prefixes;
        }

        @Override
        protected Iterator<Word<I>> l2Iterator(List<I> l1Object) {
            return prefixes.iterator();
        }

        @Override
        protected Iterator<Word<I>> l3Iterator(List<I> middle, Word<I> prefix) {

            final S tmp = automaton.getState(prefix);
            final S state = automaton.getSuccessor(tmp, middle);

            List<Word<I>> localSuffixes = localSuffixSets.get(state);

            if (localSuffixes == null) {
                localSuffixes = Automata.stateCharacterizingSet(automaton, inputs, state);
                if (localSuffixes.isEmpty()) {
                    localSuffixes = Collections.singletonList(Word.epsilon());
                }
                localSuffixSets.put(state, localSuffixes);
            }

            return localSuffixes.iterator();
        }

        @Override
        protected Word<I> combine(List<I> middle, Word<I> prefix, Word<I> suffix) {
            Word<I> word = wordBuilder.append(prefix).append(middle).append(suffix).toWord();
            wordBuilder.clear();
            return word;
        }
    }
}