Log in Help
Print
HomegatepluginsJAPE_Plussrccomontotextjapepda 〉 FSMPDA.java
 
/*
 *  FSMPDA.java
 *
 *  Copyright (c) 2010-2011, Ontotext (www.ontotext.com).
 *
 *  This file is part of GATE (see http://gate.ac.uk/), and is free
 *  software, licenced under the GNU Library General Public License,
 *  Version 2, June 1991 (in the distribution as file licence.html,
 *  and also available at http://gate.ac.uk/gate/licence.html).
 *
 *
 *  $Id$
 */
package com.ontotext.jape.pda;

import static gate.jape.KleeneOperator.Type.OPTIONAL;
import static gate.jape.KleeneOperator.Type.PLUS;
import static gate.jape.KleeneOperator.Type.RANGE;
import static gate.jape.KleeneOperator.Type.STAR;
import gate.fsm.FSM;
import gate.jape.BasicPatternElement;
import gate.jape.ComplexPatternElement;
import gate.jape.ConstraintGroup;
import gate.jape.KleeneOperator;
import gate.jape.LeftHandSide;
import gate.jape.PatternElement;
import gate.jape.PrioritisedRuleList;
import gate.jape.Rule;
import gate.jape.SinglePhaseTransducer;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import com.ontotext.jape.automaton.Automaton;
import com.ontotext.jape.automaton.AutomatonBuildHelp;
import com.ontotext.jape.automaton.ClosedHashOfStrings;
import com.ontotext.jape.automaton.Constants;
import com.ontotext.jape.automaton.GenericWholeArrray;
import com.ontotext.jape.automaton.TripleTransitions;

public class FSMPDA extends FSM {
	
  private static final long serialVersionUID = 5672459102751022260L;
  
  private transient ClosedHashOfStrings setOfBindingNames;
	private transient TripleTransitions tripleTransitions;
	private String[] arrayOfBindingNames;
	private StatePDA initialState;

	public String[] getBindingNames() {
		return arrayOfBindingNames;
	}

	public FSMPDA(SinglePhaseTransducer spt) {
		this();
		setOfBindingNames = new ClosedHashOfStrings();
		tripleTransitions = new TripleTransitions();
		addRules(spt.getRules());
	}
	
	@Override
	public StatePDA getInitialState(){
		return initialState;
	}

	protected FSMPDA() {
		initialState = new StatePDA();
	}

	@Override
	protected void addRules(PrioritisedRuleList rules) {
		Iterator<Rule> rulesEnum = rules.iterator();

		while (rulesEnum.hasNext()) {
			FSMPDA ruleFSM = spawn(rulesEnum.next());
			initialState.addTransition(new TransitionPDA(null, ruleFSM.initialState), tripleTransitions);
		}
		arrayOfBindingNames = setOfBindingNames.getCopyOfStrings();
		setOfBindingNames = null;
		AutomatonBuildHelp help = new AutomatonBuildHelp(tripleTransitions);
		Automaton aut = new Automaton(help, GenericWholeArrray.TYPE_SHORT);
		tripleTransitions.addAll(aut, help);
		tripleTransitions.setTheInitialState(aut, initialState.getIndex());
		aut = aut.determinize(tripleTransitions.getFinalitites()).minimize();
		allStates = aut.toFSM(tripleTransitions);
		int i = aut.getInitialState();
		if (i == Constants.NO) {
			initialState = new StatePDA();
			allStates = new StatePDA[1];
			allStates[0] = initialState;
		} else {
			initialState = allStates[i];
		}
		tripleTransitions = null;
	}

	protected StatePDA[] allStates;

	public FSMPDA(Rule rule, ClosedHashOfStrings setOfBindingNames,
			TripleTransitions tripleTransitions) {
		this();
		this.setOfBindingNames = setOfBindingNames;
		this.tripleTransitions = tripleTransitions;
		setRule(rule);
	}

	@Override
	protected void setRule(Rule rule) {
		LeftHandSide lhs = rule.getLHS();

		PatternElement[][] constraints = lhs.getConstraintGroup()
				.getPatternElementDisjunction();
		// the rectangular array constraints is a disjunction of sequences of
		// constraints = [[PE]:[PE]...[PE] ||
		// [PE]:[PE]...[PE] ||
		// ...
		// [PE]:[PE]...[PE] ]

		// The current and the next state for the current ROW.
		StatePDA currentRowState, nextRowState;
		StatePDA finalState = new StatePDA();
		PatternElement currentPattern;

		for (int i = 0; i < constraints.length; i++) {
			// for each row we have to create a sequence of states that will
			// accept
			// the sequence of annotations described by the restrictions on that
			// row.
			// The final state of such a sequence will always be a final state
			// which
			// will have associated the right hand side of the rule used for
			// this
			// constructor.

			// For each row we will start from the initial state.
			currentRowState = initialState;
			for (int j = 0; j < constraints[i].length; j++) {

				// parse the sequence of constraints:
				// For each basic pattern element add a new state and link it to
				// the
				// currentRowState.
				// The case of kleene operators has to be considered!
				currentPattern = constraints[i][j];
				StatePDA insulator = new StatePDA();
				currentRowState.addTransition(
						new TransitionPDA(null, insulator), tripleTransitions);
				currentRowState = insulator;
				if (currentPattern instanceof BasicPatternElement) {
					// the easy case
					nextRowState = new StatePDA();
					currentRowState.addTransition(
							new TransitionPDA(
									(BasicPatternElement) currentPattern,
									nextRowState), tripleTransitions);
					currentRowState = nextRowState;
				} else if (currentPattern instanceof ComplexPatternElement) {
					// the current pattern is a complex pattern element
					// ..it will probaly be converted into a sequence of states
					// itself.
					currentRowState = convertComplexPE(currentRowState,
							(ComplexPatternElement) currentPattern);
				} else {
					// we got an unknown kind of pattern
					throw new RuntimeException("Strange looking pattern: "
							+ currentPattern);
				}
			} // for j

			// link the end of the current row to the final state using
			// an empty transition.
			currentRowState.addTransition(new TransitionPDA(null, finalState),
					tripleTransitions);
			finalState.setAction(rule.getRHS(), tripleTransitions);
			finalState.setFileIndex(rule.getPosition());
			finalState.setPriority(rule.getPriority());
		} // for i
	}

	protected FSMPDA(ComplexPatternElement cpe) {
		this();
		finalState = convertComplexPE(initialState, cpe);
		((StatePDA) finalState).setItFinal(tripleTransitions);
	}

	@Override
	protected FSMPDA spawn(Rule r) {
		return new FSMPDA(r, setOfBindingNames, tripleTransitions);
	}

	@Override
	protected FSMPDA spawn(ComplexPatternElement currentPattern) {
		return new FSMPDA(currentPattern);
	}

	private StatePDA convertComplexPE(StatePDA startState,
			ComplexPatternElement cpe) {
		String bindingName = cpe.getBindingName();
		KleeneOperator kleeneOp = cpe.getKleeneOp();
		KleeneOperator.Type type = kleeneOp.getType();

		StatePDA innerStartState;
		if (bindingName != null) {
			innerStartState = new StatePDA();
		} else {
			innerStartState = startState;
		}
		StatePDA innerEndState = generateStates(innerStartState, cpe);
		StatePDA endState;
		if (bindingName != null) {
			endState = new StatePDA();
			startState.addTransition(new TransitionPDA(null, innerStartState,
					TransitionPDA.TYPE_OPENING_ROUND_BRACKET),
					tripleTransitions);
			if (type != RANGE) {
				innerEndState.addTransition(new TransitionPDA(null, endState,
						setOfBindingNames.put(bindingName)), tripleTransitions);
			}
		} else {
			endState = innerEndState;
		}

		// now take care of the kleene operator
		if (type == OPTIONAL) {
			// allow to skip everything via a null transition
			startState.addTransition(new TransitionPDA(null, endState),
					tripleTransitions);
		} else if (type == PLUS) {
			// allow to return to innerStartState from innerEndState
			innerEndState
					.addTransition(new TransitionPDA(null, innerStartState),
							tripleTransitions);
		} else if (type == STAR) {
			// allow to skip everything via a null transition
			startState.addTransition(new TransitionPDA(null, endState),
					tripleTransitions);

			// allow to return to innerStartState from innerEndState
			innerEndState
					.addTransition(new TransitionPDA(null, innerStartState),
							tripleTransitions);
		} else if (type == RANGE) {
			Integer min = kleeneOp.getMin();
			Integer max = kleeneOp.getMax();
			List<StatePDA> startStateList;
			if (bindingName != null) {
				startStateList = null;
			} else {
				// in this case keep a list of the start states for each
				// possible optional sets so can make
				// direct transitions from them to the final end state
				startStateList = new ArrayList<StatePDA>();
			}

			if (min == null || min == 0) {
				// if min is empty or 0, allow to skip everything via a null
				// transition
				if (bindingName != null) {
					startState.addTransition(new TransitionPDA(null, endState),
							tripleTransitions);
				} else {
					startStateList.add(innerStartState);
				}
			} else if (min > 1) {
				// add min-1 copies of the set of states for the CPE. It's -1
				// because
				// one set was already added by the first generateStates call
				for (int i = 1; i < min; i++) {
					// the end state of the previous set always moves up to be
					// the
					// start state of the next set.
					innerStartState = innerEndState;
					innerEndState = generateStates(innerStartState, cpe);
				}
			}

			if (max == null) {
				// if there is no defined max, allow to return to startState any
				// number of times. Start state may be the original start or, if
				// min > 1, then it's the start of the last set of states added.
				// Example: A range with min 3 and max = unbounded will look
				// like
				// this:
				// v------|
				// start1...end1->start2...end2->start3...end3->...
				//
				innerEndState.addTransition(new TransitionPDA(null,
						innerStartState), tripleTransitions);
			} else if (max > min) {
				// there are some optional state sets. Make a copy of the state
				// set for each.
				int numCopies = max - min;

				// if min == 0 then reduce numCopies by one since we already
				// added
				// one set of states that are optional
				if (min == 0)
					numCopies--;

				for (int i = 1; i <= numCopies; i++) {
					innerStartState = innerEndState;
					if (bindingName != null) {
						innerStartState.addTransition(new TransitionPDA(null,
								endState, setOfBindingNames.put(bindingName)),
								tripleTransitions);
					} else {
						startStateList.add(innerStartState);
					}
					innerEndState = generateStates(innerStartState, cpe);
				}
			}
			if (bindingName != null) {
				innerEndState.addTransition(new TransitionPDA(null, endState,
						setOfBindingNames.put(bindingName)), tripleTransitions);
			} else {
				// each of the optional stages can transition directly to the
				// final end
				for (StatePDA state : startStateList) {
					state.addTransition(new TransitionPDA(null, innerEndState),
							tripleTransitions);
				}
				endState = innerEndState;
			}
		} // end if type == RANGE

		return endState;
	}

	private StatePDA generateStates(StatePDA startState,
			ComplexPatternElement cpe) {
		ConstraintGroup constraintGroup = cpe.getConstraintGroup();
		PatternElement[][] constraints = constraintGroup
				.getPatternElementDisjunction();

		// the rectangular array constraints is a disjunction of sequences of
		// constraints = [[PE]:[PE]...[PE] ||
		// [PE]:[PE]...[PE] ||
		// ...
		// [PE]:[PE]...[PE] ]

		// The current and the next state for the current ROW.
		StatePDA currentRowState, nextRowState, endState = new StatePDA();
		PatternElement currentPattern;

		for (int i = 0; i < constraints.length; i++) {
			// for each row we have to create a sequence of states that will
			// accept
			// the sequence of annotations described by the restrictions on that
			// row.
			// The final state of such a sequence will always be a finale state
			// which
			// will have associated the right hand side of the rule used for
			// this
			// constructor.

			// For each row we will start from the initial state.
			currentRowState = startState;
			for (int j = 0; j < (constraints[i]).length; j++) {
				// parse the sequence of constraints:
				// For each basic pattern element add a new state and link it to
				// the
				// currentRowState.
				// The case of kleene operators has to be considered!
				StatePDA insulator = new StatePDA();
				currentRowState.addTransition(
						new TransitionPDA(null, insulator), tripleTransitions);
				currentRowState = insulator;
				currentPattern = constraints[i][j];
				if (currentPattern instanceof BasicPatternElement) {
					// the easy case
					nextRowState = new StatePDA();
					currentRowState.addTransition(
							new TransitionPDA(
									(BasicPatternElement) currentPattern,
									nextRowState), tripleTransitions);
					currentRowState = nextRowState;
				} else if (currentPattern instanceof ComplexPatternElement) {
					// the current pattern is a complex pattern element
					// ..it will probaly be converted into a sequence of states
					// itself.
					currentRowState = convertComplexPE(currentRowState,
							(ComplexPatternElement) currentPattern);
				} else {
					// we got an unknown kind of pattern
					throw new RuntimeException("Strange looking pattern:"
							+ currentPattern);
				}
			} // for j
				// link the end of the current row to the general end state
				// using
				// an empty transition.
			currentRowState.addTransition(new TransitionPDA(null, endState),
					tripleTransitions);
		} // for i
		return endState;
	}
}