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

de.learnlib.examples.example3.Example 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.examples.example3;

import com.google.common.base.Supplier;
import de.learnlib.algorithms.lstargeneric.mealy.ExtensibleLStarMealyBuilder;
import de.learnlib.api.LearningAlgorithm.MealyLearner;
import de.learnlib.api.MembershipOracle.MealyMembershipOracle;
import de.learnlib.api.Query;
import de.learnlib.examples.example2.Example.BoundedStringQueue;
import de.learnlib.filters.reuse.ReuseCapableOracle;
import de.learnlib.filters.reuse.ReuseOracle;
import de.learnlib.filters.reuse.ReuseOracle.ReuseOracleBuilder;
import de.learnlib.filters.reuse.tree.SystemStateHandler;
import net.automatalib.automata.transout.MealyMachine;
import net.automatalib.util.automata.Automata;
import net.automatalib.words.Alphabet;
import net.automatalib.words.Word;
import net.automatalib.words.WordBuilder;
import net.automatalib.words.impl.SimpleAlphabet;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * This example shows how to use the reuse filter on the
 * {@link BoundedStringQueue} of {@link de.learnlib.examples.example2.Example}.
 * 
 * Please note that there is no equivalence oracle used in this example so the
 * resulting mealy machines are only first "guesses".
 * 
 * @author Oliver Bauer 
 */
public class Example {
	public static void main(String[] args) throws Exception {
		Example example = new Example();
		System.out.println("--");
		System.out.println("Run experiment 1 (ReuseOracle):");
		MealyMachine result1 = example.runExperiment1();
		System.out.println("--");
		System.out.println("Run experiment 2:");
		MealyMachine result2 = example.runExperiment2();
		System.out.println("--");
		System.out.println("Model 1: " + result1.size() + " states");
		System.out.println("Model 2: " + result2.size() + " states");

		Word sepWord = null;
		sepWord = Automata.findSeparatingWord(result1, result2, example.sigma);

		System.out.println("Difference (separating word)? " + sepWord);

		/*
		 * Background knowledge: L^* creates an observation table with
		 * |S|=3,|SA|=7,|E|=3 so 30 MQs should be sufficient. The reuse filter
		 * should sink system states from S*E to SA*E so the upper part is the
		 * number of saved resets (=9).
		 * 
		 * If the numbers don't match:
		 * https://github.com/LearnLib/learnlib/issues/5 (9 queries will be
		 * pumped by the reuse filter)
		 */
	}

	private String offer1 = "offer_1";
	private String offer2 = "offer_2";
	private String poll = "poll";
	private Alphabet sigma;
	private List> initialSuffixes;

	public Example() {
		sigma = new SimpleAlphabet<>();
		sigma.add(offer1);
		sigma.add(offer2);
		sigma.add(poll);

		initialSuffixes = new ArrayList<>();
		for (String symbol : sigma) {
			initialSuffixes.add(Word.fromLetter(symbol));
		}
	}

	/*
	 * A "normal" scenario without reuse filter technique.
	 */
	public MealyMachine runExperiment1() throws Exception {
		// For each membership query a new instance of BoundedStringQueue will
		// be created (normal learning scenario without filters)
		FullMembershipQueryOracle oracle = new FullMembershipQueryOracle();

		// construct L* instance (almost classic Mealy version)
		// almost: we use words (Word) in cells of the table
		// instead of single outputs.
		MealyLearner lstar = null;
		lstar = new ExtensibleLStarMealyBuilder()
				.withAlphabet(sigma).withInitialSuffixes(initialSuffixes)
				.withOracle(oracle).create();

		lstar.startLearning();
		MealyMachine result = null;
		result = lstar.getHypothesisModel();

		System.out.println("Resets:  " + oracle.resets);
		System.out.println("Symbols: " + oracle.symbols);

		return result;
	}

	/*
	 * Scenario with reuse filter technique.
	 */
	public MealyMachine runExperiment2() throws Exception {
		MySystemStateHandler ssh = new MySystemStateHandler();

		// This time we use the reuse filter to avoid some resets and
		// save execution of symbols
		ReuseCapableImplFactory factory = new ReuseCapableImplFactory();
		ReuseOracle reuseOracle;
		reuseOracle = new ReuseOracleBuilder<>(sigma, factory)
				.withSystemStateHandler(ssh)
				.build();

		// construct L* instance (almost classic Mealy version)
		// almost: we use words (Word) in cells of the table
		// instead of single outputs.

		MealyLearner lstar = null;
		lstar = new ExtensibleLStarMealyBuilder()
				.withAlphabet(sigma)
				.withInitialSuffixes(initialSuffixes)
				.withOracle(reuseOracle).create();

		lstar.startLearning();

		// get learned model
		MealyMachine result = lstar.getHypothesisModel();

		// now invalidate all system states and count the number of disposed
		// queues (equals number of resets)
		reuseOracle.getReuseTree().disposeSystemstates();
		ReuseCapableImpl reuseCapableOracle = (ReuseCapableImpl) reuseOracle.getReuseCapableOracle();
		System.out.println("Resets:   " + reuseCapableOracle.fullQueries);
		System.out.println("Reused:   " + reuseCapableOracle.reused);
		System.out.println("Symbols:  " + reuseCapableOracle.symbols);
		// disposed = resets
		System.out.println("Disposed: " + ssh.disposed);

		return result;
	}

	/**
	 * For running the example this class could also be removed/ignored. It is
	 * only here for documentation purposes.
	 */
	class MySystemStateHandler implements
			SystemStateHandler {
		private int disposed = 0;

		@Override
		public void dispose(BoundedStringQueue state) {
			/*
			 * When learning e.g. examples that involve databases, here would be
			 * a good point to remove database entities. In this example we just
			 * count the number of disposed (garbage collection inside the reuse
			 * tree) objects.
			 */
			disposed++;
		}
	}

	/**
	 * An oracle that also does the reset by creating a new instance of the
	 * {@link BoundedStringQueue}.
	 */
	class FullMembershipQueryOracle implements
			MealyMembershipOracle {
		private int resets = 0;
		private int symbols = 0;

		@Override
		public void processQueries(
				Collection>> queries) {
			for (Query> query : queries) {
				resets++;
				symbols += query.getInput().size();

				BoundedStringQueue s = new BoundedStringQueue();

				WordBuilder output = new WordBuilder<>();
				for (String input : query.getInput()) {
					output.add(exec(s, input));
				}

				query.answer(output.toWord().suffix(query.getSuffix().size()));
			}
		}
	}

	class ReuseCapableImplFactory implements Supplier> {

		@Override
		public ReuseCapableOracle get() {
			return new ReuseCapableImpl();
		}
	}

	/**
	 * An implementation of the {@link ReuseCapableOracle} needed for the
	 * {@link ReuseOracle}. It only does resets (by means of creating a new
	 * {@link BoundedStringQueue} instance in
	 * {@link ReuseCapableOracle#processQuery(Word)}.
	 */
	class ReuseCapableImpl implements
			ReuseCapableOracle {

		private int reused = 0;
		private int fullQueries = 0;
		private int symbols = 0;

		@Override
		public QueryResult continueQuery(
				Word trace, BoundedStringQueue s) {

			reused++;
			symbols += trace.size();

			WordBuilder output = new WordBuilder<>();

			for (String input : trace) {
				output.add(exec(s, input));
			}

			QueryResult result;
			result = new QueryResult<>(output.toWord(), s);

			return result;
		}

		@Override
		public QueryResult processQuery(
				Word trace) {
			fullQueries++;
			symbols += trace.size();

			/* Suppose the reset would be a time consuming operation */
			BoundedStringQueue s = new BoundedStringQueue();

			WordBuilder output = new WordBuilder<>();

			for (String input : trace) {
				output.add(exec(s, input));
			}

			QueryResult result;
			result = new QueryResult<>(output.toWord(), s);

			return result;
		}
	}

	private String exec(BoundedStringQueue s, String input) {
		if (input.equals(offer1) || input.equals(offer2)) {
			s.offer(input);
			return "void";
		} else if (input.equals(poll)) {
			return s.poll();
		} else {
			throw new RuntimeException("unknown input symbol");
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy