/*
* File name: GrammarMaster.java (package eas.users.lukas.demos.grammar)
* Author(s): lko
* Java version: 7.0
* Generation date: 26.07.2012 (17:35:55)
*
* (c) This file and the EAS (Easy Agent Simulation) framework containing it
* is protected by Creative Commons by-nc-sa license. Any altered or
* further developed versions of this file have to meet the agreements
* stated by the license conditions.
*
* In a nutshell
* -------------
* You are free:
* - to Share -- to copy, distribute and transmit the work
* - to Remix -- to adapt the work
*
* Under the following conditions:
* - Attribution -- You must attribute the work in the manner specified by the
* author or licensor (but not in any way that suggests that they endorse
* you or your use of the work).
* - Noncommercial -- You may not use this work for commercial purposes.
* - Share Alike -- If you alter, transform, or build upon this work, you may
* distribute the resulting work only under the same or a similar license to
* this one.
*
* + Detailed license conditions (Germany):
* http://creativecommons.org/licenses/by-nc-sa/3.0/de/
* + Detailed license conditions (unported):
* http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
*
* This header must be placed in the beginning of any version of this file.
*/
package eas.users.demos.grammar;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import eas.math.fundamentalAlgorithms.graphBased.algorithms.type0grammars.Grammar;
import eas.math.fundamentalAlgorithms.graphBased.algorithms.type0grammars.Nonterminal;
import eas.math.fundamentalAlgorithms.graphBased.algorithms.type0grammars.Rule;
import eas.math.fundamentalAlgorithms.graphBased.algorithms.type0grammars.Symbol;
import eas.math.fundamentalAlgorithms.graphBased.algorithms.type0grammars.Word;
import eas.math.geometry.Vector2D;
import eas.plugins.masterScheduler.AbstractDefaultMaster;
import eas.simulation.ConstantsSimulation;
import eas.simulation.Wink;
import eas.startSetup.GlobalVariables;
import eas.startSetup.ParCollection;
import eas.startSetup.SingleParameter;
import eas.startSetup.parameterDatatypes.Datatypes;
/**
* @author lko
*/
public class GrammarScheduler extends AbstractDefaultMaster<GrammarEnvironment>
implements ListSelectionListener {
/**
*
*/
private static final long serialVersionUID = 7821703685729989073L;
private Random rand = new Random(0);
private int maxNumTerminals;
private int maxNumWords;
private boolean storeDerivation;
private boolean paused = false;
@Override
public List<SingleParameter> getParameters() {
List<SingleParameter> list = super.getParameters();
list.add(new SingleParameter("MaxNumTerminals", Datatypes.INTEGER, 100000, "", this.id().toUpperCase()));
list.add(new SingleParameter("MaxNumWords", Datatypes.INTEGER, 100000, "Removes random words if too many words generated.", this.id().toUpperCase()));
list.add(new SingleParameter("StoreDerivation?", Datatypes.BOOLEAN, true, "", this.id().toUpperCase()));
return list;
}
@Override
public GrammarEnvironment[] generateRunnables(ParCollection params) {
GrammarEnvironment env = new GrammarEnvironment(0, params);
return new GrammarEnvironment[] {env};
}
private Grammar grammar;
public Grammar getGrammar() {
return this.grammar;
}
@Override
public void runBeforeSimulation(GrammarEnvironment env, ParCollection params) {
super.runBeforeSimulation(env, params);
this.maxNumTerminals = params.getParValueInt("MaxNumTerminals");
this.maxNumWords = params.getParValueInt("MaxNumWords");
this.storeDerivation = params.getParValueBoolean("StoreDerivation?");
FileDialog dia = new FileDialog((Dialog) null, "Select grammar to load.", FileDialog.LOAD);
dia.setVisible(true);
if (dia.getDirectory() == null || dia.getFile() == null) {
env.getSimTime().timeTerminate();
System.exit(0);
}
grammar = new Grammar(new File(dia.getDirectory() + File.separator + dia.getFile()), new Nonterminal(new StringBuffer("S")));
env.addAgent(
new GrammarAgent(
env.getFirstFreeID(),
env,
params,
grammar),
new Vector2D(0, 0),
180,
new Vector2D(1.2, 1.2));
ArrayList<Word> start = new ArrayList<Word>(50);
start.add(new Word(new Symbol[] {this.grammar.getStartSymbol()}));
addWords.add(start);
frame = new GrammarFrame("Non-final words in temp. storage", this);
frame.setSize(600, 600);
frame.setVisible(true);
JPanel panel = new JPanel();
frame.addComponent(panel);
JScrollPane scroll = new JScrollPane(wordList);
scroll.setPreferredSize(new Dimension(300, 300));
panel.add(scroll);
this.refreshWordList();
wordList.addListSelectionListener(this);
// System.out.println("\nGenerating Words:\n");
}
public boolean continueWithSelectedWords() {
if (this.wordList.getSelectedValuesList().size() == 0) {
return false;
}
GlobalVariables.getPrematureParameters().logWarning(
"Removing "
+ (words.size() - this.wordList.getSelectedValuesList().size())
+ " words from storage. Results may be incomplete!");
while (this.blocked) {
try {Thread.sleep(50);} catch (InterruptedException e) {}
}
this.blocked = true;
this.words.clear();
this.addWords.clear();
it = null;
for (ListItemDerivation der : this.wordList.getSelectedValuesList()) {
this.addWords.add(der.getDerivation());
}
words = addWords;
this.blocked = false;
return true;
}
public int refreshWordList() {
wordListData = new DefaultListModel<ListItemDerivation>();
while (this.blocked) {
try {Thread.sleep(50);} catch (InterruptedException e) {}
}
this.blocked = true;
for (ArrayList<Word> w : words) {
wordListData.addElement(new ListItemDerivation(w));
}
this.blocked = false;
wordList.setModel(wordListData);
return words.size();
}
private DefaultListModel<ListItemDerivation> wordListData;
private JList<ListItemDerivation> wordList = new JList<ListItemDerivation>();
private GrammarFrame frame;
private List<Word> match(Word w, Rule r) {
LinkedList<Word> words = new LinkedList<Word>();
for (int i = 0; i < w.getWord().size(); i++) {
int skip = this.matchInternal(w, r, i);
if (skip > 0) {
Word newWord = new Word(w.replace(i, r.getLeftSide().getWord().size(), r.getRightSide()));
words.add(newWord);
}
i += Math.abs(skip) - 1;
}
return words;
}
/**
* Checks if rule r can be applied to word w on position i.
*
* @param w The word.
* @param r The rule.
* @param i The position to match.
*
* @return Positive number if match, negative otherwise. Absolute value
* is number of symbols in w after position i which are not equal
* to the first symbol of the left side of r. This means that
* this number of symbols may be skipped when testing for the
* next possible match in w.
*/
private int matchInternal(Word w, Rule r, int i) {
int skip = 1;
try {
for (int j = i; j < i + r.getLeftSide().getWord().size(); j++) {
if (j > i && !r.getLeftSide().getWord().get(0).equals(w.getWord().get(j))) {
skip++;
}
if (!r.getLeftSide().getWord().get(j - i).equals(w.getWord().get(j))) {
return -skip;
}
}
} catch (Exception e) {
return -skip;
}
return skip;
}
private LinkedList<Word> imported = new LinkedList<Word>();
private HashSet<ArrayList<Word>> words = new HashSet<ArrayList<Word>>(10000);
private HashSet<ArrayList<Word>> addWords = new HashSet<ArrayList<Word>>(10000);
private LinkedList<ArrayList<Word>> generatedWords = new LinkedList<ArrayList<Word>>();
private Iterator<ArrayList<Word>> it;
private boolean allGenerated = false;
private boolean blocked = false;
@Override
public synchronized void runDuringSimulation(GrammarEnvironment env,
Wink simZyk, ParCollection params) {
super.runDuringSimulation(env, simZyk, params);
if (simZyk.getLastTick() == 0) {
this.frame.setAreaText(this.grammar.toString());
frame.setAlwaysOnTop(true);
frame.setAlwaysOnTop(false);
}
// if (simZyk.getLastTick() % 100 == 0) {
// this.refreshWordList();
// }
if (env.getAgents().size() >= this.maxNumTerminals || allGenerated || paused) {
return;
}
while (this.blocked) {
try {Thread.sleep(50);} catch (InterruptedException e) {}
}
blocked = true;
if (it == null || !it.hasNext()) {
words = addWords;
// words.addAll(addWords);
// words.removeAll(removeWords);
addWords = new HashSet<ArrayList<Word>>(10000);
if (words.size() > this.maxNumWords) {
params.logWarning(
"Removing "
+ (words.size() - this.maxNumWords)
+ " random words from storage. Results will be incomplete!");
ArrayList<ArrayList<Word>> wordsCopy = new ArrayList<ArrayList<Word>>(words);
Collections.shuffle(wordsCopy);
int i = 0;
while (words.size() > this.maxNumWords) {
words.remove(wordsCopy.get(i));
i++;
}
params.logInfo("Removed.");
}
it = words.iterator();
}
if (!it.hasNext()) {
params.logInfo("No more terminals to generate.");
allGenerated = true;
blocked = false;
return;
}
// Generate new words.
generateAllDerivationsWithCurrentAndMoveToNextWord();
for (int i = 0; i < generatedWords.size(); i++) {
if (!imported.contains(generatedWords.get(i).get(generatedWords.get(i).size() - 1))) {
env.addAgent(new TerminalAgent(env.getFirstFreeID(), env, params, rand, generatedWords.get(i)),
new Vector2D(0, 0), rand.nextDouble() * 360, new Vector2D(
1, 1));
imported.add(generatedWords.get(i).get(generatedWords.get(i).size() - 1));
}
}
if (env.getAgents().size() >= this.maxNumTerminals) {
params.logInfo(this.maxNumTerminals + " words have been produced. Stopping word production.");
}
if (simZyk.getLastTick() % 50 == 0) {
Word minWord = null;
Word maxWord = null;
ArrayList<Word> minDer = null;
ArrayList<Word> maxDer = null;
for (ArrayList<Word> ww : words) {
if (minWord == null || ww.get(ww.size() - 1).compareTo(minWord) < 0) {
minWord = ww.get(ww.size() - 1);
minDer = ww;
}
if (maxWord == null || ww.get(ww.size() - 1).compareTo(maxWord) > 0) {
maxWord = ww.get(ww.size() - 1);
maxDer = ww;
}
}
if (!imported.contains(minWord)) {
env.addAgent(new SemiTerminalAgent(env.getFirstFreeID(), env, params, rand, minDer),
new Vector2D(0, 0), rand.nextDouble() * 360, new Vector2D(
1.1, 1.1));
imported.add(minWord);
} else if (!imported.contains(maxWord)) {
env.addAgent(new SemiTerminalAgent(env.getFirstFreeID(), env, params, rand, maxDer),
new Vector2D(0, 0), rand.nextDouble() * 360, new Vector2D(
1.1, 1.1));
imported.add(maxWord);
}
}
blocked = false;
}
/**
* Generates all derivations possible with the current word
* and moves the iterator to the next word in the list.
*/
private void generateAllDerivationsWithCurrentAndMoveToNextWord() {
ArrayList<Word> derivation = it.next();
Word w = derivation.get(derivation.size() - 1);
if (w.isTerminal()) {
generatedWords.add(derivation);
} else {
for (Rule r : this.grammar.getRules()) {
for (Word newWord : this.match(w, r)) {
ArrayList<Word> newDerivation;
if (this.storeDerivation) {
newDerivation = new ArrayList<Word>(derivation);
} else {
newDerivation = new ArrayList<Word>();
}
newDerivation.add(newWord);
if (newWord.isTerminal()) {
generatedWords.add(newDerivation);
} else {
addWords.add(newDerivation);
}
}
}
}
}
// private void gc() {
// for (ArrayList<Word> der : this.words) {
// if (der.get(der.size() - 1).countNonTerminals() > 0) {
// while (der.size() > 1) {
// der.remove(0);
// }
// }
// }
// }
@Override
public String id() {
return ConstantsSimulation.DEFAULT_MASTER_SCHEDULER_ID + "-grammar";
}
@Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
if (this.wordList.getSelectedValue() != null) {
this.frame.setAreaText(
this.wordList.getSelectedValue().getDerivation().toString()
.replace("],", "]\n")
.replace("]", "")
.replace("[", "")
.replace(" ", "")
.replace("\n", " =>\n"));
} else {
this.frame.setAreaText(this.grammar.toString());
}
}
}
public void setPaused(boolean paused) {
this.paused = paused;
}
}