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

com.github.dakusui.jcunit.fsm.StateRouter Maven / Gradle / Ivy

package com.github.dakusui.jcunit.fsm;

import com.github.dakusui.jcunit.core.utils.Utils;

import java.util.*;

import static com.github.dakusui.jcunit.core.utils.Checks.*;

public interface StateRouter {
  ScenarioSequence routeTo(State state);

  class Base implements StateRouter {
    private final Map, List>>  adjacents;
    private final Map, FSM.Edge> links;
    private final State                         initialState;


    public Base(FSM fsm) {
      this.adjacents = buildAdjacents(fsm);
      this.links = buildLinks(fsm);
      this.initialState = fsm.initialState();
    }

    @Override
    public ScenarioSequence routeTo(State state) {
      if (this.initialState.equals(state))
        return ScenarioSequence.Empty.getInstance();
      List> route = Utils.newList();
      checktest(
          route(this.initialState, state, route, Utils.>newSet()),
          "The state '%s' can't be reached from the initial state of the given FSM.",
          state,
          this.initialState
      );
      return buildScenarioSequenceFromTransitions(route);
    }

    private ScenarioSequence buildScenarioSequenceFromTransitions(final List> route) {
      return new ScenarioSequence.Base() {
        @Override
        public int size() {
          return route.size();
        }

        @Override
        public State state(int i) {
          checkcond(i >= 0 && i < size());
          State ret = StateRouter.Base.this.initialState;
          for (int c = 0; c < i; c++) {
            ret = next(ret, new FSM.Edge(action(c), args(c)));
          }
          return ret;
        }

        @Override
        public Action action(int i) {
          return route.get(i).action;
        }

        @Override
        public Object arg(int i, int j) {
          return this.args(i).values()[j];
        }

        @Override
        public boolean hasArg(int i, int j) {
          checkcond(j >= 0);
          return args(i).size() > j;
        }

        @Override
        public Args args(int i) {
          return route.get(i).args;
        }

        @Override
        public String toString() {
          return PrivateUtils.toString(this);
        }

      };
    }

    boolean route(State cur, State to, List> route, Set> visited) {
      if (!this.adjacents.containsKey(cur))
        return false;
      for (State each : checknotnull(this.adjacents.get(cur))) {
        route.add(this.links.get(new StatePair(cur, each)));
        if (each.equals(to)) {
          return true;
        } else {
          if (!visited.contains(each)) {
            visited.add(each);
            if (route(each, to, route, visited)) {
              return true;
            }
          }
        }
        if (!route.isEmpty()) {
          route.remove(route.size() - 1);
        }
      }
      return false;
    }

    Map, List>> buildAdjacents(FSM fsm) {
      // from -> tos
      final Map, List>> ret = Utils.newMap();
      for (State eachFromState : fsm.states()) {
        for (Action eachAction : fsm.actions()) {
          for (Args eachArgs : FSMUtils.possibleArgsList(eachAction)) {
            State eachToState = eachFromState.expectation(eachAction, eachArgs).state;
            if (State.Void.getInstance().equals(eachToState))
              continue;
            List> toStates = getToStates(ret, eachFromState);
            if (!toStates.contains(eachToState))
              toStates.add(eachToState);
          }
        }
      }
      return ret;
    }

    private List> getToStates(Map, List>> ret, State eachFromState) {
      if (!ret.containsKey(eachFromState))
        ret.put(eachFromState, Utils.>newList());
      return ret.get(eachFromState);
    }

    Map, FSM.Edge> buildLinks(FSM fsm) {
      final Map, FSM.Edge> edges = Utils.newMap();
      for (State fromState : fsm.states()) {
        for (Action eachAction : fsm.actions()) {
          for (Args eachArgs : FSMUtils.possibleArgsList(eachAction)) {
            State toState = fromState.expectation(eachAction, eachArgs).state;
            if (State.Void.getInstance().equals(toState))
              continue;
            StatePair link = new StatePair(fromState, toState);
            if (edges.containsKey(link))
              continue;
            edges.put(link, new FSM.Edge(eachAction, eachArgs));
          }
        }
      }
      return edges;
    }


    static class StatePair {
      State from;
      State to;

      StatePair(State from, State to) {
        this.from = checknotnull(from);
        this.to = checknotnull(to);
      }

      public int hashCode() {
        return this.from.hashCode();
      }

      public boolean equals(Object anotherObject) {
        if (!(anotherObject instanceof StatePair))
          return false;
        StatePair another = (StatePair) anotherObject;
        return this.from.equals(another.from) && this.to.equals(another.to);
      }
    }

    private static  State next(State state, FSM.Edge t) {
      return state.expectation(t.action, t.args).state;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy