/*
* (C) Copyright 2013 Arnaud Bailly (arnaud.oqube@gmail.com),
* Yves Roos (yroos@lifl.fr) and others.
*
* 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 rationals.transformations;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import rationals.Automaton;
import rationals.Transition;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
/**
Randomly walk an {@link rationals.Automaton} until some condition is met.
<p>A random walk start from the initial(s) state of the given automaton and repeatedly builds a word that, firing a
transition, moving to given state, until the accumulated word matches some predicate. The condition is given as a
parameter of the random walk.</p>
*/
public class RandomWalk {
private final Random random = new Random();
public List<Object> walk(Automaton a, Matcher<List<Object>> condition) {
Set states = a.initials();
List<Object> word = new ArrayList<Object>();
while (true) {
Object l = selectALetter(a, states);
word.add(l);
states = a.step(states, l);
if (condition.matches(word)) {
break;
}
}
return word;
}
private Object selectALetter(Automaton a, Set states) {
Set<Transition> delta = a.delta(states);
if (delta.isEmpty()) {
throw new IllegalStateException("cannot find a transition");
}
Object selected = null;
int ln = random.nextInt(delta.size());
for (Transition transition : delta) {
if (ln-- == 0) {
selected = transition.label();
break;
}
}
return selected;
}
public static Matcher<List<Object>> hasLength(final int length) {
return new TypeSafeMatcher<List<Object>>() {
@Override
protected boolean matchesSafely(List<Object> objects) {
return objects.size() == length;
}
@Override
public void describeTo(Description description) {
description.appendText("a word of length " + length);
}
};
}
}