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

net.automatalib.util.minimizer.OneSEVPAMinimizer 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.minimizer;

import net.automatalib.automata.vpda.DefaultOneSEVPA;
import net.automatalib.automata.vpda.Location;
import net.automatalib.automata.vpda.OneSEVPA;
import net.automatalib.commons.smartcollections.ArrayStorage;
import net.automatalib.util.partitionrefinement.Block;
import net.automatalib.util.partitionrefinement.PaigeTarjan;
import net.automatalib.util.partitionrefinement.PaigeTarjanInitializers;
import net.automatalib.words.VPDAlphabet;

/**
 * A Paige/Tarjan partition refinement based minimizer for {@link OneSEVPA}s.
 *
 * @author Malte Isberner
 */
public final class OneSEVPAMinimizer {

    private OneSEVPAMinimizer() {
    }

    public static  DefaultOneSEVPA minimize(final OneSEVPA sevpa, final VPDAlphabet alphabet) {
        final PaigeTarjan pt = new PaigeTarjan();
        initPaigeTarjan(pt, sevpa, alphabet);
        pt.initWorklist(false);
        pt.computeCoarsestStablePartition();

        return fromPaigeTarjan(pt, sevpa, alphabet);
    }

    private static  void initPaigeTarjan(PaigeTarjan pt, OneSEVPA sevpa, VPDAlphabet alphabet) {
        final int numStates = sevpa.size();
        final int numInputs =
                alphabet.getNumInternals() + alphabet.getNumCalls() * alphabet.getNumReturns() * sevpa.size() * 2;

        final int posDataLow = numStates;
        final int predOfsDataLow = posDataLow + numStates;
        final int numTransitions = numStates * numInputs;
        final int predDataLow = predOfsDataLow + numTransitions + 1;
        final int dataSize = predDataLow + numTransitions;

        final int[] data = new int[dataSize];
        final Block[] blockForState = new Block[numStates];

        final Block[] initBlocks = new Block[2];

        for (int i = 0; i < numStates; i++) {
            final L loc = sevpa.getLocation(i);
            final int initBlockIdx = sevpa.isAcceptingLocation(loc) ? 1 : 0;
            Block block = initBlocks[initBlockIdx];
            if (block == null) {
                block = pt.createBlock();
                block.high = 0;
                initBlocks[initBlockIdx] = block;
            }
            block.high++;
            blockForState[i] = block;

            int predCountBase = predOfsDataLow;

            for (I intSym : alphabet.getInternalSymbols()) {
                final L succ = sevpa.getInternalSuccessor(loc, intSym);
                if (succ == null) {
                    throw new IllegalArgumentException();
                }

                final int succId = sevpa.getLocationId(succ);
                data[predCountBase + succId]++;
                predCountBase += numStates;
            }
            for (I callSym : alphabet.getCallSymbols()) {
                for (I retSym : alphabet.getReturnSymbols()) {
                    for (L src : sevpa.getLocations()) {
                        int stackSym = sevpa.encodeStackSym(src, callSym);
                        L succ = sevpa.getReturnSuccessor(loc, retSym, stackSym);
                        int succId = sevpa.getLocationId(succ);
                        data[predCountBase + succId]++;
                        predCountBase += numStates;

                        stackSym = sevpa.encodeStackSym(loc, callSym);
                        succ = sevpa.getReturnSuccessor(src, retSym, stackSym);
                        succId = sevpa.getLocationId(succ);
                        data[predCountBase + succId]++;
                        predCountBase += numStates;
                    }
                }
            }
        }

        int curr = 0;
        for (Block b : pt.blockList()) {
            curr += b.high;
            b.high = curr;
            b.low = curr;
        }

        data[predOfsDataLow] += predDataLow;
        PaigeTarjanInitializers.prefixSum(data, predOfsDataLow, predDataLow);

        for (int i = 0; i < numStates; i++) {
            final Block b = blockForState[i];
            final int pos = --b.low;
            data[pos] = i;
            data[posDataLow + i] = pos;
            int predOfsBase = predOfsDataLow;

            final L loc = sevpa.getLocation(i);
            for (I intSym : alphabet.getInternalSymbols()) {
                final L succ = sevpa.getInternalSuccessor(loc, intSym);
                if (succ == null) {
                    throw new IllegalArgumentException();
                }

                final int succId = sevpa.getLocationId(succ);
                data[--data[predOfsBase + succId]] = i;
                predOfsBase += numStates;
            }
            for (I callSym : alphabet.getCallSymbols()) {
                for (I retSym : alphabet.getReturnSymbols()) {
                    for (L src : sevpa.getLocations()) {
                        int stackSym = sevpa.encodeStackSym(src, callSym);
                        L succ = sevpa.getReturnSuccessor(loc, retSym, stackSym);
                        int succId = sevpa.getLocationId(succ);
                        data[--data[predOfsBase + succId]] = i;
                        predOfsBase += numStates;

                        stackSym = sevpa.encodeStackSym(loc, callSym);
                        succ = sevpa.getReturnSuccessor(src, retSym, stackSym);
                        succId = sevpa.getLocationId(succ);
                        data[--data[predOfsBase + succId]] = i;
                        predOfsBase += numStates;
                    }
                }
            }
        }

        pt.setBlockData(data);
        pt.setPosData(data, posDataLow);
        pt.setPredOfsData(data, predOfsDataLow);
        pt.setPredData(data);
        pt.setBlockForState(blockForState);
        pt.setSize(numStates, numInputs);
    }

    private static  DefaultOneSEVPA fromPaigeTarjan(final PaigeTarjan pt,
                                                             final OneSEVPA original,
                                                             final VPDAlphabet alphabet) {

        final int numBlocks = pt.getNumBlocks();
        final DefaultOneSEVPA result = new DefaultOneSEVPA<>(alphabet, numBlocks);

        final ArrayStorage resultLocs =
                new ArrayStorage<>(numBlocks, () -> result.addLocation(false));

        for (Block curr : pt.blockList()) {
            final int blockId = curr.id;
            final int rep = pt.getRepresentative(curr);
            final L repLoc = original.getLocation(rep);

            final Location resultLoc = resultLocs.get(blockId);
            resultLoc.setAccepting(original.isAcceptingLocation(repLoc));

            for (I intSym : alphabet.getInternalSymbols()) {
                final L origSucc = original.getInternalSuccessor(repLoc, intSym);
                final int origSuccId = original.getLocationId(origSucc);
                final int resSuccId = pt.getBlockForState(origSuccId).id;
                final Location resSucc = resultLocs.get(resSuccId);
                result.setInternalSuccessor(resultLoc, intSym, resSucc);
            }
            for (I callSym : alphabet.getCallSymbols()) {
                for (I retSym : alphabet.getReturnSymbols()) {
                    for (Block b : pt.blockList()) {
                        final int stackRepId = pt.getRepresentative(b);
                        final L stackRep = original.getLocation(stackRepId);
                        final Location resultStackRep = resultLocs.get(b.id);

                        final int origStackSym = original.encodeStackSym(stackRep, callSym);
                        final L origSucc = original.getReturnSuccessor(repLoc, retSym, origStackSym);
                        final int origSuccId = original.getLocationId(origSucc);
                        final int resSuccId = pt.getBlockForState(origSuccId).id;
                        final Location resSucc = resultLocs.get(resSuccId);

                        final int stackSym = result.encodeStackSym(resultStackRep, callSym);
                        result.setReturnSuccessor(resultLoc, retSym, stackSym, resSucc);
                    }
                }
            }
        }

        final int origInit = original.getLocationId(original.getInitialLocation());
        result.setInitialLocation(resultLocs.get(pt.getBlockForState(origInit).id));

        return result;
    }

}