001    package org.maltparser.parser.history.kbest;
002    
003    import java.util.ArrayList;
004    
005    import org.maltparser.core.exception.MaltChainedException;
006    import org.maltparser.parser.history.action.SingleDecision;
007    /**
008    *
009    * @author Johan Hall
010    **/
011    public class KBestList {
012            protected final ArrayList<Candidate> kBestList;
013            protected int k = -1;
014            protected int topCandidateIndex;
015            protected int addCandidateIndex;
016            protected SingleDecision decision;
017            
018            /**
019             * Creates a unrestricted k-best list
020             * 
021             * @param decision a reference to the single decision that uses the k-best list
022             */
023            public KBestList(SingleDecision decision) {
024                    this(-1, decision);
025            }
026    
027            /**
028             * Creates a k-best list
029             * 
030             * @param k     the k-best list size
031             * @param decision      a reference to the single decision that uses the k-best list.
032             */
033            public KBestList(Integer k, SingleDecision decision) {
034                    setK(k.intValue());
035                    this.decision = decision;
036                    if (this.k > 0) {
037                            kBestList = new ArrayList<Candidate>(this.k);
038                            initKBestList();
039                    } else {
040                            kBestList = new ArrayList<Candidate>();
041                    }
042                    
043            }
044            
045            protected void initKBestList() {
046                    for (int i=0; i < this.k; i++) {
047                            kBestList.add(new Candidate());
048                    }
049            }
050            
051            /**
052             * Resets the k-best list
053             */
054            public void reset() {
055                    this.topCandidateIndex = 0;
056                    this.addCandidateIndex = 0;
057            }
058            
059            /**
060             * Adds a candidate to the k-best list
061             * 
062             * @param actionCode the integer representation  of candidate action
063             * @throws MaltChainedException
064             */
065            public void add(int actionCode) throws MaltChainedException {
066                    if (k != -1 && addCandidateIndex >= k) { return; }
067                    if (addCandidateIndex >= kBestList.size()) { kBestList.add(new Candidate()); }
068                    kBestList.get(addCandidateIndex).setActionCode(actionCode);
069                    if (addCandidateIndex == 0) {
070                            if (decision instanceof SingleDecision) {
071                                    ((SingleDecision)decision).addDecision(actionCode);
072                            }
073                            topCandidateIndex++;
074                    }
075                    addCandidateIndex++;
076            }
077            
078            public void addList(int[] predictionList) throws MaltChainedException {
079                    int n = (k != -1 && k <= predictionList.length-1)?k:predictionList.length - 1;
080                    for (int i=0; i<n; i++) {
081                            add(predictionList[i]);
082                    }       
083            }
084            
085            /**
086             * Adds a candidate to the k-best list
087             * 
088             * @param symbol the string representation of candidate action
089             * @throws MaltChainedException
090             */
091            public void add(String symbol) throws MaltChainedException {
092                    if (decision instanceof SingleDecision) {
093                            this.add(((SingleDecision)decision).getDecisionCode(symbol));
094                    }
095            }
096            
097    
098            /**
099             * Updates the corresponding single decision with the next value in the k-best list.
100             * 
101             * @return true if decision has been updated, otherwise false
102             * @throws MaltChainedException
103             */
104            public boolean updateActionWithNextKBest() throws MaltChainedException {
105                    if (addCandidateIndex != 0 && topCandidateIndex < addCandidateIndex && topCandidateIndex < kBestList.size()) {
106                            int actionCode = kBestList.get(topCandidateIndex).getActionCode();
107                            if (decision instanceof SingleDecision) {
108                                    ((SingleDecision)decision).addDecision(actionCode);
109                            }
110                            topCandidateIndex++;
111                            return true;
112                    } 
113                    return false;
114            }
115            
116            public int peekNextKBest() {
117                    if (addCandidateIndex != 0 && topCandidateIndex < addCandidateIndex && topCandidateIndex < kBestList.size()) {
118                            return kBestList.get(topCandidateIndex).getActionCode();
119                    }
120                    return -1;
121            }
122            
123            /**
124             * Returns the current size of the k-best list
125             * 
126             * @return the current size of the k-best list
127             */
128            public int getCurrentSize() {
129                    return addCandidateIndex;
130                    //return kBestList.size();
131            }
132            
133            /**
134             * Returns the maximum number of candidates in the k-best list.
135             * 
136             * @return the maximum number of candidates in the k-best list
137             */
138            public int getK() {
139                    return k;
140            }
141            /**
142             * Sets the maximum number of candidates in the k-best list
143             * 
144             * @param k the maximum number of candidates 
145             */
146            protected void setK(int k) {
147                    if (k == 0) {
148                            this.k = 1; // the k-best list must contain at least one candidate
149                    } if (k < 0) {
150                            this.k = -1; // this means that the k-best list is unrestricted.
151                    } else {
152                            this.k = k;
153                    }
154            }
155            
156            protected int getTopCandidateIndex() {
157                    return topCandidateIndex;
158            }
159    
160            protected int getAddCandidateIndex() {
161                    return addCandidateIndex;
162            }
163    
164            /**
165             * Returns a single decision object
166             * 
167             * @return a single decision object
168             */
169            public SingleDecision getDecision() {
170                    return decision;
171            }       
172            
173            public int getKBestListSize() {
174                    return kBestList.size();
175            }
176            
177            public ScoredCandidate getCandidate(int i) {
178                    if (i >= kBestList.size()) {
179                            return null;
180                    }
181                    return (ScoredCandidate)kBestList.get(i);
182            }
183            
184            /* (non-Javadoc)
185             * @see java.lang.Object#toString()
186             */
187            public String toString() {
188                    StringBuilder sb = new StringBuilder();
189                    sb.append("[ ");
190                    for (int i = 0; i < addCandidateIndex; i++) {
191                            sb.append(kBestList.get(i));
192                            sb.append(' ');
193                    }
194                    sb.append("] ");
195                    return sb.toString();
196            }
197    }