de.learnlib.algorithms.nlstar.ObservationTable Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of learnlib-nlstar Show documentation
Show all versions of learnlib-nlstar Show documentation
This artifact provides the implementation of the NL* learning algorithm as described in the paper "Angluin-Style
Learning of NFA" (http://ijcai.org/Proceedings/09/Papers/170.pdf) by Benedikt Bollig, Peter Habermehl,
Carsten Kern, and Martin Leucker.
/* Copyright (C) 2013-2020 TU Dortmund
* This file is part of LearnLib, http://www.learnlib.de/.
*
* 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 de.learnlib.algorithms.nlstar;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import de.learnlib.api.oracle.MembershipOracle;
import de.learnlib.api.query.DefaultQuery;
import net.automatalib.words.Alphabet;
import net.automatalib.words.Word;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* The observation table implementation for the {@link NLStarLearner NL* algorithm}.
*
* @param
* input symbol type
*
* @author Malte Isberner
*/
public class ObservationTable {
private final Alphabet alphabet;
private final MembershipOracle oracle;
private final List> upperRows = new ArrayList<>();
private final List> allRows = new ArrayList<>();
private final List> newUppers = new ArrayList<>();
private final List> newRows = new ArrayList<>();
private final List> suffixes = new ArrayList<>();
private final Set> suffixSet = new HashSet<>();
private final List> upperPrimes = new ArrayList<>();
public ObservationTable(Alphabet alphabet, MembershipOracle oracle) {
this.alphabet = alphabet;
this.oracle = oracle;
}
public List>> initialize() {
if (!suffixes.isEmpty()) {
throw new IllegalStateException();
}
Row row = createRow(Word.epsilon());
makeUpper(row);
return addSuffix(Word.epsilon());
}
private Row createRow(Word prefix) {
Row row = new Row<>(prefix);
allRows.add(row);
newRows.add(row);
return row;
}
public List>> addSuffix(Word suffixToAdd) {
return addSuffixes(Collections.singletonList(suffixToAdd));
}
private void makeUpper(Row row) {
makeUpper(Collections.singletonList(row));
}
public List>> makeUpper(List> rows) {
List> newRows = new ArrayList<>(rows.size() * alphabet.size());
for (Row row : rows) {
makeShort(row);
Word prefix = row.getPrefix();
for (int i = 0; i < alphabet.size(); i++) {
I sym = alphabet.getSymbol(i);
Word newPrefix = prefix.append(sym);
Row newRow = createRow(newPrefix);
row.setSuccessorRow(i, newRow);
newRows.add(newRow);
}
}
if (suffixes.isEmpty()) {
return Collections.emptyList();
}
int numSuffixes = suffixes.size();
List> queries = new ArrayList<>(newRows.size() * numSuffixes);
for (Row newRow : newRows) {
for (Word suffix : suffixes) {
queries.add(new DefaultQuery<>(newRow.getPrefix(), suffix));
}
}
oracle.processQueries(queries);
Iterator> queryIt = queries.iterator();
for (Row newRow : newRows) {
newRow.fetchContents(queryIt, 0, numSuffixes);
}
return updateMetadata();
}
public List>> addSuffixes(List extends Word> suffixesToAdd) {
List> newSuffixes = new ArrayList<>();
int oldNumSuffixes = suffixes.size();
for (Word suffix : suffixesToAdd) {
if (suffixSet.add(suffix)) {
suffixes.add(suffix);
newSuffixes.add(suffix);
}
}
if (newSuffixes.isEmpty()) {
return Collections.emptyList();
}
int numNewSuffixes = newSuffixes.size();
List> queries = new ArrayList<>(allRows.size() * numNewSuffixes);
for (Row row : allRows) {
Word prefix = row.getPrefix();
for (Word suffix : newSuffixes) {
queries.add(new DefaultQuery<>(prefix, suffix));
}
}
oracle.processQueries(queries);
Iterator> queryIt = queries.iterator();
for (Row row : allRows) {
row.fetchContents(queryIt, oldNumSuffixes, numNewSuffixes);
}
return updateMetadata();
}
private void makeShort(Row row) {
row.makeShort(upperRows.size(), alphabet.size());
upperRows.add(row);
newUppers.add(row);
}
private List>> updateMetadata() {
// Update coverage information
for (Row row : allRows) {
if (row.isShortPrefixRow()) {
if (row.isNew()) {
row.updateCovered(upperRows);
} else {
row.updateCovered(newUppers);
}
} else {
if (row.isNew()) {
row.updateCovered(allRows);
} else {
row.updateCovered(newRows);
}
}
}
newRows.clear();
newUppers.clear();
upperPrimes.clear();
Map>> primeContents = new HashMap<>();
List>> allUnclosed = new ArrayList<>();
for (Row row : allRows) {
boolean prime = row.checkPrime();
if (prime) {
if (row.isShortPrefixRow()) {
upperPrimes.add(row);
} else {
List> unclosedClass = primeContents.get(row.getContents());
if (unclosedClass == null) {
unclosedClass = new ArrayList<>();
allUnclosed.add(unclosedClass);
primeContents.put(row.getContents(), unclosedClass);
}
unclosedClass.add(row);
}
}
}
return allUnclosed;
}
public Word getSuffix(int suffixIdx) {
return suffixes.get(suffixIdx);
}
public List> getCoveredRows(Row coveringRow) {
return coveringRow.getCoveredRows();
}
public Row getUpperRow(int index) {
return upperRows.get(index);
}
public List> getUpperRows() {
return upperRows;
}
public List> getUpperPrimes() {
return upperPrimes;
}
public int getNumUpperRows() {
return upperRows.size();
}
public @Nullable Inconsistency findInconsistency() {
for (Row row1 : upperRows) {
for (Row row2 : row1.getCoveredRows()) {
assert row2.isShortPrefixRow();
for (int i = 0; i < alphabet.size(); i++) {
Row row1succ = row1.getSuccessorRow(i);
Row row2succ = row2.getSuccessorRow(i);
for (int j = 0; j < suffixes.size(); j++) {
if (!row1succ.getContent(j) && row2succ.getContent(j)) {
return new Inconsistency<>(row1, row2, i, j);
}
}
}
}
}
return null;
}
}