/*______________________________________________________________________________
*
* Copyright 2005 Arnaud Bailly - NORSYS/LIFL
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* (1) Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* (2) Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* (3) The name of the author may not be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Created on 30 mars 2005
*
*/
package rationals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
/**
* Instances of this class are random automata. A RandomAutomaton is generated
* according to following parameters :
* <ul>
* <li>The number of states in the automaton</li>
* <li>The number of terminal states</li>
* <li>The alphabet : if the alphabet contains a <code>null</code> element,
* it will be used and the resulting automaton will contain epsilon-transitions
* </li>
* <li>The mean transition density which is the number of transitions in the
* automaton divided by the square of the number of states times the size of the
* alphabet</li>
* <li>The standard deviation of the transition density</li>
* <li>A flag indicating if the automaton should be deterministic or not. Note
* that if the alphabet contains epsilon, then the resulting automaton will most
* probably be non-deterministic even if this flag is set.</li>
* </ul>
* The result is an - non reduced - automaton with a single start state and
* random transitions following a normal distribution according to preceding
* parameters over the alphabet.
*
* @author nono
* @version $Id: RandomAutomaton.java 2 2006-08-24 14:41:48Z oqube $
*/
public class RandomAutomaton extends Automaton {
private static final Random rand = new Random();
private int nstate;
private int fstate;
private Object[] alph;
private double density;
private double deviation;
/**
* Construct a RandomAutomaton according to the given parameters.
*
* @param nstate
* number of total states
* @param fstate
* number of final states
* @param alphabet
* alphabet
* @param density
* mean transition density
* @param deviation
* transition density standard deviation
* @param det
* is the result deterministic
*/
public RandomAutomaton(int nstate, int fstate, Object[] alph,
double density, double deviation, boolean det) {
this.nstate = nstate;
this.fstate = fstate;
this.alph = alph;
this.density = density;
this.deviation = deviation;
if (det)
makeDFA();
else
makeNFA();
}
/**
*
*/
private void makeNFA() {
/* create initial state and other states */
State init = addState(true, false);
for (int i = 0; i < fstate; i++)
addState(false, true);
for (int i = fstate; i < nstate; i++)
addState(false, false);
State[] sts = (State[]) states().toArray(new State[nstate + 1]);
/* create transitions */
Iterator it = states().iterator();
while (it.hasNext()) {
State from = (State) it.next();
int c = alph.length * sts.length * sts.length;
/* number of transitions from this state to other state */
int nt = (int) (c * (deviation * rand.nextGaussian() + density));
for (int i = 0; i < nt; i++) {
State to = sts[rand.nextInt(sts.length)];
Object lbl = alph[rand.nextInt(alph.length)];
try {
/* create transition */
addTransition(new Transition(from, lbl, to));
} catch (NoSuchStateException e1) {
}
}
}
}
/**
*
*/
private void makeDFA() {
/* create initial state and other states */
State init = addState(true, false);
List todo = new ArrayList();
List done = new ArrayList();
int fs = fstate;
int ns = nstate;
todo.add(init);
while (ns > 0) {
/* pop state */
State from = (State) todo.remove(0);
done.add(from);
/* list for alph */
List l = new ArrayList(Arrays.asList(alph));
int c = alph.length * nstate;
/* number of transitions from this state to other state */
int nt = (int) (deviation * rand.nextGaussian() + density);
for (int i = 0; i < nt && !l.isEmpty(); i++) {
/*
* select a state : this an already visited state with
* probability (done.size() / nstate)
*/
State to = null;
double r = rand.nextDouble() * (nstate - 1);
if ((int) r < done.size()) {
to = (State) done.get((int) r);
} else {
/*
* state is final with probability fs / ns
*/
r = rand.nextDouble() * ns;
to = addState(false, r < fs);
todo.add(to);
ns--;
if (r < fs)
fs--;
}
Object lbl = l.remove(rand.nextInt(l.size()));
try {
/* create transition */
addTransition(new Transition(from, lbl, to));
} catch (NoSuchStateException e1) {
}
}
}
}
}