![JAR search and dependency download from the Maven repository](/logo.png)
de.learnlib.api.Query Maven / Gradle / Ivy
Show all versions of learnlib-core Show documentation
/* Copyright (C) 2013-2015 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.api;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import de.learnlib.oracles.DefaultQuery;
import net.automatalib.automata.fsa.DFA;
import net.automatalib.automata.transout.MealyMachine;
import net.automatalib.words.Word;
/**
* A query is the basic form of interaction between a {@link LearningAlgorithm learner} and a
* {@link MembershipOracle (membership) oracle}, or teacher.
*
* In LearnLib, queries are performed in a callback-like fashion: an oracle does not return
* the responses to the queries, but rather invokes the {@link #answer(Object)} method on the query
* objects it was provided with. This allows for implementing queries which directly react to an answered
* query (e.g., by modifying some internal data structure), without the need for buffering answers.
* It also allows for a more efficient parallel processing of queries, as there is no need for maintaining
* a common (synchronized) result data structure such as a map. However, this means that a learner
* cannot rely on the {@link #answer(Object)} method of a query being called from the same thread which
* invoked {@link MembershipOracle#processQueries(java.util.Collection)}. If this causes concurrency
* issues, a safe choice is to use queries of class {@link DefaultQuery}, which simply store the response
* and make it accessible via {@link DefaultQuery#getOutput()} for processing after the
* {@link MembershipOracle#processQueries(java.util.Collection)} call returns, guaranteeing thread-safety.
*
* Conceptually, a query is divided into a {@link #getPrefix() prefix} and a {@link #getSuffix()}
* suffix. The prefix part of a query identifies a state in the (unknown) target system, whereas
* the suffix is the "experiment" which is conducted on the system starting from the state to which
* it was transferred by the prefix. While the prefix influences the response of the target system
* to a query, the answer is the directly observable reaction to executing the suffix.
*
* Example 1: when learning {@link MealyMachine Mealy machines}, the prefix transfers the target
* system to a certain state. The outputs produced by the system while executing the prefix are
* not part of the answer, as the role of the prefix is limited to reaching a certain state.
* The reaction of the target system consists of the output word produced while executing the suffix.
* Therefore, in the setting of Mealy machine learning, a valid oracle will call the {@link #answer(Object)}
* method with a word of the same length as the suffix.
*
* Example 2: when learning {@link DFA}s, the reaction of the target system is fully determined
* by the state reached by an input word. Since both prefix and suffix have the same effect on producing
* this output (by transferring the system to a certain state), the response will always be a single
* {@link Boolean}, and, furthermore, for every input word {@code w}, the response to a query will
* always be the same regardless of the subdivision of {@code w = uv} into prefix {@code u} and
* suffix {@code v} (including the corner cases u = ε
and
* v = ε
).
*
* @author Malte Isberner
*
* @param input symbol type
* @param output domain type
*/
public abstract class Query {
private int hashCode = 0;
/**
* Returns the prefix part of this query. The prefix of a query is responsible
* for transferring the system into a certain state, but (apart from that) does
* not directly influence the output.
* @return the prefix of this query
*/
@Nonnull
public abstract Word getPrefix();
/**
* Returns the suffix part of this query. The suffix of a query is the experiment
* performed on the system when in the state it was transferred into by the prefix,
* and thus directly influences the output.
* @return the suffix of this query
*/
@Nonnull
public abstract Word getSuffix();
/**
* Answers the query. This method should be called by a {@link MembershipOracle}, and only
* once per query to process. Calling this method more than once may result in undefined
* behavior, possibly (but not necessarily) throwing an exception.
*
* @param output the output, i.e., the response to the query
*/
public abstract void answer(@Nullable D output);
/**
* Retrieves the input word of this query. The input word corresponding to a query
* is the concatenation of its prefix and suffix.
* @return the input word of this query
*/
@Nonnull
public Word getInput() {
return getPrefix().concat(getSuffix());
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public final boolean equals(Object o) {
if(o == null)
return false;
if(this == o)
return true;
if(!(o instanceof Query))
return false;
Query,?> other = (Query,?>)o;
Word thisPref = getPrefix();
Word thisSuff = getSuffix();
Word> otherPref = other.getPrefix();
Word> otherSuff = other.getSuffix();
if(thisPref != otherPref && !thisPref.equals(otherPref))
return false;
if(thisSuff != otherSuff && !thisSuff.equals(otherSuff))
return false;
return true;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public final int hashCode() {
if(hashCode != 0)
return hashCode;
Word prefix = getPrefix(), suffix = getSuffix();
hashCode = 5;
hashCode = 89 * hashCode + prefix.hashCode();
hashCode = 89 * hashCode + suffix.hashCode();
return hashCode;
}
/**
* Returns the string representation of this query.
*
* @return A string of the form {@code "Query[|]"} for queries not containing
* an answer or {@code "Query[| / ]"} if an answer may be specified.
*/
@Override
public String toString() {
return "Query[" + getPrefix() + '|' + getSuffix() + ']';
}
}