net.automatalib.serialization.saf.SAFInput Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of automata-serialization-saf Show documentation
Show all versions of automata-serialization-saf Show documentation
(De-)Serializers for the Simple Automaton Format
The newest version!
/* Copyright (C) 2013-2023 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.serialization.saf;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import net.automatalib.alphabet.Alphabet;
import net.automatalib.alphabet.Alphabets;
import net.automatalib.automaton.AutomatonCreator;
import net.automatalib.automaton.MutableAutomaton;
import net.automatalib.automaton.fsa.CompactDFA;
import net.automatalib.automaton.fsa.CompactNFA;
import net.automatalib.common.util.IOUtil;
import net.automatalib.serialization.FormatException;
/**
* Deserializer for the SAF (simple automaton format).
*/
class SAFInput {
private static final AutomatonType[] TYPES = AutomatonType.values();
private final DataInput in;
SAFInput(byte[] data) {
this(new ByteArrayInputStream(data));
}
SAFInput(InputStream is) {
this((DataInput) new DataInputStream(is));
}
SAFInput(DataInput in) {
this.in = in;
}
SAFInput(File file) throws IOException {
this(IOUtil.asBufferedInputStream(file));
}
public CompactDFA readDFA(Alphabet alphabet) throws IOException {
return readAutomaton(AutomatonType.DFA,
alphabet,
new CompactDFA.Creator<>(),
new AcceptanceDecoder(),
SinglePropertyDecoder.nullDecoder());
}
public > A readAutomaton(AutomatonType expectedType,
Alphabet alphabet,
AutomatonCreator extends A, I> creator,
BlockPropertyDecoder extends SP> spDecoder,
SinglePropertyDecoder extends TP> tpDecoder)
throws IOException {
AutomatonType type = readHeader();
if (type != expectedType) {
throw new FormatException();
}
int alphabetSize = in.readInt();
if (alphabetSize != alphabet.size()) {
throw new FormatException();
}
return readAutomatonBody(alphabet, type.isDeterministic(), creator, spDecoder, tpDecoder);
}
private AutomatonType readHeader() throws IOException {
final int headerSize = 4;
byte[] header = new byte[headerSize];
in.readFully(header);
if (header[0] != 'S' || header[1] != 'A' || header[2] != 'F') {
throw new FormatException();
}
byte type = header[3];
if (type < 0 || type >= TYPES.length) {
throw new FormatException();
}
return TYPES[type];
}
private > A readAutomatonBody(Alphabet alphabet,
boolean deterministic,
AutomatonCreator extends A, I> creator,
BlockPropertyDecoder extends SP> spDecoder,
SinglePropertyDecoder extends TP> tpDecoder)
throws IOException {
int numStates = in.readInt();
A result = creator.createAutomaton(alphabet, numStates);
if (deterministic) {
decodeBodyDet((MutableAutomaton, I, ?, SP, TP>) result, alphabet, numStates, spDecoder, tpDecoder);
} else {
decodeBodyNondet((MutableAutomaton, I, ?, SP, TP>) result, alphabet, numStates, spDecoder, tpDecoder);
}
return result;
}
private List decodeBodyDet(MutableAutomaton result,
Alphabet alphabet,
int numStates,
BlockPropertyDecoder extends SP> spDecoder,
SinglePropertyDecoder extends TP> tpDecoder) throws IOException {
List stateList = decodeStatesDet(result, numStates, spDecoder);
decodeTransitionsDet(result, stateList, alphabet, tpDecoder);
return stateList;
}
private List decodeBodyNondet(MutableAutomaton result,
Alphabet alphabet,
int numStates,
BlockPropertyDecoder extends SP> spDecoder,
SinglePropertyDecoder extends TP> tpDecoder) throws IOException {
List stateList = decodeStatesNondet(result, numStates, spDecoder);
decodeTransitionsNondet(result, stateList, alphabet, tpDecoder);
return stateList;
}
private List decodeStatesDet(MutableAutomaton result,
int numStates,
BlockPropertyDecoder extends SP> decoder) throws IOException {
int initStateId = in.readInt();
List stateList = decodeStateProperties(result, numStates, decoder);
S initState = stateList.get(initStateId);
result.setInitial(initState, true);
return stateList;
}
private void decodeTransitionsDet(MutableAutomaton result,
List stateList,
Alphabet alphabet,
SinglePropertyDecoder extends TP> tpDecoder) throws IOException {
int numStates = stateList.size();
assert result.size() == numStates;
int numInputs = alphabet.size();
for (S state : stateList) {
for (int j = 0; j < numInputs; j++) {
int tgt = in.readInt();
if (tgt != -1) {
I sym = alphabet.getSymbol(j);
S tgtState = stateList.get(tgt);
TP prop = tpDecoder.readProperty(in);
result.addTransition(state, sym, tgtState, prop);
}
}
}
}
private List decodeStatesNondet(MutableAutomaton result,
int numStates,
BlockPropertyDecoder extends SP> decoder) throws IOException {
int[] initStates = readInts(in);
List stateList = decodeStateProperties(result, numStates, decoder);
for (int initId : initStates) {
S initState = stateList.get(initId);
result.setInitial(initState, true);
}
return stateList;
}
private void decodeTransitionsNondet(MutableAutomaton result,
List stateList,
Alphabet alphabet,
SinglePropertyDecoder extends TP> tpDecoder) throws IOException {
int numStates = stateList.size();
assert result.size() == numStates;
int numInputs = alphabet.size();
for (S state : stateList) {
for (int j = 0; j < numInputs; j++) {
int numTgts = in.readInt();
I sym = alphabet.getSymbol(j);
for (int k = 0; k < numTgts; k++) {
int tgt = in.readInt();
TP prop = tpDecoder.readProperty(in);
S tgtState = stateList.get(tgt);
result.addTransition(state, sym, tgtState, prop);
}
}
}
}
private List decodeStateProperties(MutableAutomaton result,
int numStates,
BlockPropertyDecoder extends SP> decoder) throws IOException {
List stateList = new ArrayList<>(numStates);
decoder.start(in);
for (int i = 0; i < numStates; i++) {
SP prop = decoder.readProperty(in);
S state = result.addState(prop);
stateList.add(state);
}
decoder.finish(in);
return stateList;
}
private static int[] readInts(DataInput in) throws IOException {
int n = in.readInt();
int[] result = new int[n];
for (int i = 0; i < n; i++) {
result[i] = in.readInt();
}
return result;
}
public CompactDFA readNativeDFA() throws IOException {
return readNativeAutomaton(AutomatonType.DFA,
new CompactDFA.Creator<>(),
new AcceptanceDecoder(),
SinglePropertyDecoder.nullDecoder());
}
public > A readNativeAutomaton(AutomatonType expectedType,
AutomatonCreator extends A, Integer> creator,
BlockPropertyDecoder extends SP> spDecoder,
SinglePropertyDecoder extends TP> tpDecoder)
throws IOException {
AutomatonType type = readHeader();
if (type != expectedType) {
throw new FormatException();
}
int alphabetSize = in.readInt();
if (alphabetSize <= 0) {
throw new FormatException();
}
Alphabet alphabet = Alphabets.integers(0, alphabetSize - 1);
return readAutomatonBody(alphabet, type.isDeterministic(), creator, spDecoder, tpDecoder);
}
public CompactNFA readNFA(Alphabet alphabet) throws IOException {
return readAutomaton(AutomatonType.NFA,
alphabet,
new CompactNFA.Creator<>(),
new AcceptanceDecoder(),
SinglePropertyDecoder.nullDecoder());
}
public CompactNFA readNativeNFA() throws IOException {
return readNativeAutomaton(AutomatonType.NFA,
new CompactNFA.Creator<>(),
new AcceptanceDecoder(),
SinglePropertyDecoder.nullDecoder());
}
}