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

de.learnlib.algorithms.lstargeneric.AbstractAutomatonLStar Maven / Gradle / Ivy

There is a newer version: 0.12.0
Show newest version
/* 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();
	}

}