001 002 003 004 005package org.biojava.utils.automata; 006 007import java.util.HashMap; 008import java.util.HashSet; 009import java.util.Iterator; 010import java.util.Map; 011import java.util.Set; 012 013import org.biojava.bio.symbol.Symbol; 014 015/** 016 * This class caches a reference to all objects that 017 * it directs its delegate to make. These references 018 * make it relatively easy for it to duplicate 019 * all objects made through this class. 020 */ 021public class NfaSubModel 022 implements NfaBuilder 023{ 024 private NfaBuilder delegate; 025 private Set nodes = new HashSet(); 026 private Set transitions = new HashSet(); 027 028 private FiniteAutomaton.Node start = null; 029 private FiniteAutomaton.Node end = null; 030 031 NfaSubModel(NfaBuilder delegate) 032 { 033 this.delegate = delegate; 034 start = addNode(false); 035 end = addNode(false); 036 } 037 038 public FiniteAutomaton getAutomaton() 039 { 040 return delegate.getAutomaton(); 041 } 042 043 public FiniteAutomaton.Node getStart() { return start; } 044 public FiniteAutomaton.Node getEnd() { return end; } 045 046 void setStart(FiniteAutomaton.Node start) 047 { 048 nodes.add(start); 049 this.start = start; 050 } 051 052 void setEnd(FiniteAutomaton.Node end) 053 { 054 nodes.add(end); 055 this.end = end; 056 } 057 058 public FiniteAutomaton.Node addNode(boolean isTerminal) 059 { 060 FiniteAutomaton.Node newNode = delegate.addNode(isTerminal); 061 nodes.add(newNode); 062 return newNode; 063 } 064 065 public FiniteAutomaton.Transition addTransition(FiniteAutomaton.Node start, FiniteAutomaton.Node end, Symbol sym) 066 { 067 FiniteAutomaton.Transition newTransition = delegate.addTransition(start, end, sym); 068 transitions.add(newTransition); 069 return newTransition; 070 } 071 072 public FiniteAutomaton.Transition addEpsilonTransition(FiniteAutomaton.Node start, FiniteAutomaton.Node end) 073 { 074 FiniteAutomaton.Transition newTransition = delegate.addEpsilonTransition(start, end); 075 transitions.add(newTransition); 076 return newTransition; 077 } 078 079 public FiniteAutomaton.Transition addLambdaTransition(FiniteAutomaton.Node start, FiniteAutomaton.Node end) 080 { 081 FiniteAutomaton.Transition newTransition = delegate.addLambdaTransition(start, end); 082 transitions.add(newTransition); 083 return newTransition; 084 } 085 086 public FiniteAutomaton.NodeSet getNodes() 087 { 088 FiniteAutomaton.NodeSet nodeSet = delegate.createNodeSet(); 089 nodeSet.addAll(nodes); 090 return nodeSet; 091 } 092 093 public Set getTransitions() 094 { 095 return transitions; 096 } 097 098 public FiniteAutomaton.NodeSet createNodeSet() 099 { 100 return delegate.createNodeSet(); 101 } 102 103 /** 104 * Makes a deep clone of this instance. 105 */ 106 public NfaSubModel duplicate() 107 { 108 // create a new NfaSubModel 109 NfaSubModel newSubModel = new NfaSubModel(delegate); 110 111 // create a mapping between old and new Nodes 112 Map old2New = new HashMap(); 113 114 for (Iterator nodesI = nodes.iterator(); nodesI.hasNext(); ) { 115 FiniteAutomaton.Node oldNode = (FiniteAutomaton.Node) nodesI.next(); 116 old2New.put(oldNode, newSubModel.addNode(oldNode.isTerminal())); 117 } 118 119 // set up the start and end 120 newSubModel.setStart((FiniteAutomaton.Node) old2New.get(start)); 121 newSubModel.setEnd((FiniteAutomaton.Node) old2New.get(end)); 122 123 // for each transition, create a new one with remapped 124 // nodes. 125 for (Iterator transI = transitions.iterator(); transI.hasNext(); ) { 126 FiniteAutomaton.Transition oldTrans = (FiniteAutomaton.Transition) transI.next(); 127 128 newSubModel.addTransition((FiniteAutomaton.Node) old2New.get(oldTrans.source), 129 (FiniteAutomaton.Node) old2New.get(oldTrans.dest), oldTrans.sym); 130 } 131 132 return newSubModel; 133 } 134 135 public void append(NfaSubModel submodel) 136 { 137 addEpsilonTransition(end, submodel.getStart()); 138 setEnd(submodel.getEnd()); 139 } 140 141 public String toString() { return delegate.toString(); } 142} 143