de.learnlib.algorithms.lstargeneric.AbstractAutomatonLStar Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of learnlib-lstar-generic Show documentation
Show all versions of learnlib-lstar-generic Show documentation
A flexible, optimized version of Dana Angluin's L* algorithm
/* Copyright (C) 2013 TU Dortmund
* This file is part of LearnLib, http://www.learnlib.de/.
*
* LearnLib is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 3.0 as published by the Free Software Foundation.
*
* LearnLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with LearnLib; if not, see
* .
*/
package de.learnlib.algorithms.lstargeneric;
import java.util.ArrayList;
import net.automatalib.automata.MutableDeterministic;
import net.automatalib.commons.util.collections.CollectionsUtil;
import net.automatalib.words.Alphabet;
import de.learnlib.algorithms.lstargeneric.table.Row;
import de.learnlib.api.MembershipOracle;
/**
* Abstract base class for algorithms that produce (subclasses of) {@link MutableDeterministic}
* automata.
*
* This class provides the L*-style hypothesis construction. Implementing classes solely have
* to specify how state and transition properties should be derived.
*
* @author Malte Isberner
*
* @param automaton class, must be a subclass of {@link MutableDeterministic}
* @param input symbol class
* @param output class
* @param state property class
* @param transition property class
*/
public abstract class AbstractAutomatonLStar> extends
AbstractLStar {
private static final class StateInfo {
private final Row row;
private final S state;
public StateInfo(Row row, S state) {
this.row = row;
this.state = state;
}
public Row getRow() {
return row;
}
public S getState() {
return state;
}
// IDENTITY SEMANTICS!
}
protected final AI internalHyp;
protected final ArrayList> stateInfos
= new ArrayList<>();
/**
* Constructor.
* @param alphabet the learning alphabet
* @param oracle the learning oracle
*/
public AbstractAutomatonLStar(Alphabet alphabet,
MembershipOracle oracle,
AI internalHyp) {
super(alphabet, oracle);
this.internalHyp = internalHyp;
internalHyp.clear();
}
/**
* Derives a state property from the corresponding row.
* @param stateRow the row for which the state is created
* @return the state property of the corresponding state
*/
protected abstract SP stateProperty(Row stateRow);
/**
* Derives a transition property from the corresponding transition.
* N.B.: Not the transition row is passed to this method, but the
* row for the outgoing state. The transition row can be retrieved
* by stateRow.getSuccessor(inputIdx)
.
* @param stateRow the row for the source state
* @param inputIdx the index of the input symbol to consider
* @return the transition property of the corresponding transition
*/
protected abstract TP transitionProperty(Row stateRow, int inputIdx);
protected abstract A exposeInternalHypothesis();
/**
* Performs the L*-style hypothesis construction.
* For creating states and transitions, the {@link #stateProperty(Row)} and
* {@link #transitionProperty(Row, int)} methods are used to derive the
* respective properties.
* @param model the model to output
*/
protected void updateInternalHypothesis() {
if(!table.isInitialized())
throw new IllegalStateException("Cannot update internal hypothesis: not initialized");
int oldStates = internalHyp.size();
int numDistinct = table.numDistinctRows();
int newStates = numDistinct - oldStates;
if(newStates <= 0)
return;
stateInfos.addAll(CollectionsUtil.>nullList(newStates));
// TODO: Is there a quicker way than iterating over *all* rows?
// FIRST PASS: Create new hypothesis states
for(Row sp : table.getShortPrefixRows()) {
int id = sp.getRowContentId();
StateInfo info = stateInfos.get(id);
if(info != null) {
// State from previous hypothesis, property might have changed
if(info.getRow() == sp)
internalHyp.setStateProperty(info.getState(), stateProperty(sp));
continue;
}
S state = createState((id == 0), sp);
stateInfos.set(id, new StateInfo<>(sp, state));
}
// SECOND PASS: Create hypothesis transitions
for(StateInfo info : stateInfos) {
Row sp = info.getRow();
int rowId = sp.getRowContentId();
S state = info.getState();
for(int i = 0; i < alphabet.size(); i++) {
I input = alphabet.getSymbol(i);
Row succ = sp.getSuccessor(i);
int succId = succ.getRowContentId();
if(rowId < oldStates && succId < oldStates)
continue;
S succState = stateInfos.get(succId).getState();
setTransition(state, input, succState, sp, i, succ);
}
}
}
protected S createState(boolean initial, Row row) {
SP prop = stateProperty(row);
if(initial)
return internalHyp.addInitialState(prop);
return internalHyp.addState(prop);
}
protected void setTransition(S from, I input, S to, Row fromRow, int inputIdx, Row toRow) {
TP prop = transitionProperty(fromRow, inputIdx);
internalHyp.setTransition(from, input, to, prop);
}
@Override
public A getHypothesisModel() {
updateInternalHypothesis();
return exposeInternalHypothesis();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy