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

net.automatalib.util.automata.vpda.OneSEVPAUtil 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.vpda;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

import net.automatalib.automata.vpda.OneSEVPA;
import net.automatalib.commons.smartcollections.ArrayStorage;
import net.automatalib.words.VPDAlphabet;
import net.automatalib.words.Word;

/**
 * Utility class revolving around 1-SEVPAs.
 *
 * @author Malte Isberner
 */
public final class OneSEVPAUtil {

    private OneSEVPAUtil() {
    }

    public static  List findReachableLocations(final OneSEVPA sevpa, final VPDAlphabet alphabet) {
        return computeAccessSequences(sevpa, alphabet, false, l -> false).reachableLocs;
    }

    public static  ReachResult computeAccessSequences(final OneSEVPA sevpa,
                                                                  final VPDAlphabet alphabet,
                                                                  final boolean computeAs,
                                                                  final Predicate terminatePred) {
        final ArrayStorage> result = new ArrayStorage<>(sevpa.size());

        final L initLoc = sevpa.getInitialLocation();
        final List reachable = new ArrayList<>();
        reachable.add(initLoc);
        result.set(sevpa.getLocationId(initLoc), Word.epsilon());

        if (terminatePred.test(initLoc)) {
            return new ReachResult<>(initLoc, reachable, result);
        }

        int queuePtr = 0;
        while (queuePtr < reachable.size()) {
            final L curr = reachable.get(queuePtr++);
            final Word currAs = result.get(sevpa.getLocationId(curr));

            for (I intSym : alphabet.getInternalSymbols()) {
                final L succ = sevpa.getInternalSuccessor(curr, intSym);
                final int succIdx = sevpa.getLocationId(succ);
                if (result.get(succIdx) != null) {
                    continue;
                }
                final Word succAs = computeAs ? currAs.append(intSym) : Word.epsilon();
                result.set(succIdx, succAs);
                if (terminatePred.test(succ)) {
                    return new ReachResult<>(succ, reachable, result);
                }
                reachable.add(succ);
            }

            for (I callSym : alphabet.getCallSymbols()) {
                for (I returnSym : alphabet.getReturnSymbols()) {
                    for (int i = 0; i < queuePtr; i++) {
                        final L src = reachable.get(i);
                        int stackSym = sevpa.encodeStackSym(src, callSym);
                        L succ = sevpa.getReturnSuccessor(curr, returnSym, stackSym);
                        int succIdx = sevpa.getLocationId(succ);
                        if (result.get(succIdx) == null) {
                            Word succAs = computeAs ?
                                    result.get(sevpa.getLocationId(src))
                                          .append(callSym)
                                          .concat(currAs.append(returnSym)) :
                                    Word.epsilon();
                            result.set(succIdx, succAs);
                            if (terminatePred.test(succ)) {
                                return new ReachResult<>(succ, reachable, result);
                            }
                            reachable.add(succ);
                        }

                        if (src != curr) {
                            stackSym = sevpa.encodeStackSym(curr, callSym);
                            succ = sevpa.getReturnSuccessor(src, returnSym, stackSym);
                            succIdx = sevpa.getLocationId(succ);
                            if (result.get(succIdx) == null) {
                                final Word succAs = computeAs ?
                                        currAs.append(callSym)
                                              .concat(result.get(sevpa.getLocationId(src)).append(returnSym)) :
                                        Word.epsilon();
                                result.set(succIdx, succAs);
                                if (terminatePred.test(succ)) {
                                    return new ReachResult<>(succ, reachable, result);
                                }
                                reachable.add(succ);
                            }
                        }
                    }
                }
            }
        }

        return new ReachResult<>(null, reachable, result);
    }

    public static  ArrayStorage> computeAccessSequences(final OneSEVPA sevpa,
                                                                      final VPDAlphabet alphabet) {
        return computeAccessSequences(sevpa, alphabet, true, l -> false).accessSequences;
    }

    public static  Word findRejectedWord(final OneSEVPA sevpa, final VPDAlphabet alphabet) {
        return computeAccessSequence(sevpa, alphabet, l -> !sevpa.isAcceptingLocation(l));
    }

    public static  Word computeAccessSequence(final OneSEVPA sevpa,
                                                       final VPDAlphabet alphabet,
                                                       final Predicate predicate) {
        final ReachResult result = computeAccessSequences(sevpa, alphabet, true, predicate);
        L resultLoc = result.terminateLoc;
        if (resultLoc != null) {
            return result.accessSequences.get(sevpa.getLocationId(resultLoc));
        }
        return null;
    }

    public static  boolean testEquivalence(final OneSEVPA sevpa1,
                                              final OneSEVPA sevpa2,
                                              final VPDAlphabet alphabet) {
        return findSeparatingWord(sevpa1, sevpa2, alphabet) == null;
    }

    public static  Word findSeparatingWord(final OneSEVPA sevpa1,
                                                 final OneSEVPA sevpa2,
                                                 final VPDAlphabet alphabet) {
        final OneSEVPA prod = OneSEVPAs.xor(sevpa1, sevpa2, alphabet);
        return findAcceptedWord(prod, alphabet);
    }

    public static  Word findAcceptedWord(final OneSEVPA sevpa, final VPDAlphabet alphabet) {
        return computeAccessSequence(sevpa, alphabet, sevpa::isAcceptingLocation);
    }

    public static class ReachResult {

        public final L terminateLoc;
        public final List reachableLocs;
        public final ArrayStorage> accessSequences;

        public ReachResult(final L terminateLoc,
                           final List reachableLocs,
                           final ArrayStorage> accessSequences) {
            this.terminateLoc = terminateLoc;
            this.reachableLocs = reachableLocs;
            this.accessSequences = accessSequences;
        }
    }

}