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

de.learnlib.oracle.equivalence.AbstractTestWordEQOracle Maven / Gradle / Ivy

There is a newer version: 0.17.0
Show newest version
/* 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.oracle.equivalence;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

import com.google.common.base.Preconditions;
import com.google.common.collect.Iterators;
import com.google.common.collect.Streams;
import de.learnlib.api.oracle.EquivalenceOracle;
import de.learnlib.api.oracle.MembershipOracle;
import de.learnlib.api.query.DefaultQuery;
import net.automatalib.automata.concepts.Output;
import net.automatalib.words.Word;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An abstract equivalence oracle that takes care of query batching and hypothesis checking and allows extending classes
 * to solely focus on test word generation by implementing {@link #generateTestWords(Output, Collection)}.
 * 

* Being {@link Stream stream}-based, this oracle encourages the lazy computation of counterexamples, so that all * counterexamples do not have to be computed upfront, but only until the first valid counterexample is found. * * @param * hypothesis type * @param * input symbol type * @param * output (domain) type * * @author frohme */ public abstract class AbstractTestWordEQOracle, I, D> implements EquivalenceOracle { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractTestWordEQOracle.class); private final MembershipOracle membershipOracle; private final int batchSize; public AbstractTestWordEQOracle(MembershipOracle membershipOracle) { this(membershipOracle, 1); } public AbstractTestWordEQOracle(MembershipOracle membershipOracle, int batchSize) { Preconditions.checkArgument(batchSize > 0); this.membershipOracle = membershipOracle; this.batchSize = batchSize; } @Override public @Nullable DefaultQuery findCounterExample(A hypothesis, Collection inputs) { // Fail fast on empty inputs if (inputs.isEmpty()) { LOGGER.warn("Passed empty set of inputs to equivalence oracle; no counterexample can be found!"); return null; } final Stream> testWordStream = generateTestWords(hypothesis, inputs); final Stream> queryStream = testWordStream.map(DefaultQuery::new); final Stream> answeredQueryStream = answerQueries(queryStream); final Stream> ceStream = answeredQueryStream.filter(query -> { D hypOutput = hypothesis.computeOutput(query.getInput()); return !Objects.equals(hypOutput, query.getOutput()); }); return ceStream.findFirst().orElse(null); } /** * Generate the stream of test words that should be used for the current equivalence check cycle. * * @param hypothesis * the current hypothesis of the learning algorithm * @param inputs * the collection of inputs to consider * * @return the stream of test words used for equivalence testing * * @see EquivalenceOracle#findCounterExample(Object, Collection) */ protected abstract Stream> generateTestWords(A hypothesis, Collection inputs); private Stream> answerQueries(final Stream> stream) { if (isBatched()) { /* * FIXME: currently necessary because of a bug in the JDK * see https://bugs.openjdk.java.net/browse/JDK-8075939 */ return Streams.stream(Streams.stream(Iterators.partition(stream.iterator(), this.batchSize)) .peek(membershipOracle::processQueries) .flatMap(List::stream) .iterator()); } else { return stream.peek(membershipOracle::processQuery); } } private boolean isBatched() { return this.batchSize > 1; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy