001package org.maltparser.parser.history.kbest;
002
003import java.util.ArrayList;
004
005import org.maltparser.core.exception.MaltChainedException;
006import org.maltparser.parser.history.action.SingleDecision;
007/**
008*
009* @author Johan Hall
010**/
011public class KBestList {
012        protected final ArrayList<Candidate> kBestList;
013        protected int k = -1;
014        protected int topCandidateIndex;
015        protected int addCandidateIndex;
016        protected final 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                        decision.addDecision(actionCode);
074                        topCandidateIndex++;
075                }
076                addCandidateIndex++;
077        }
078        
079        public void addList(int[] predictionList) throws MaltChainedException {
080                int n = (k != -1 && k <= predictionList.length-1)?k:predictionList.length - 1;
081                for (int i=0; i<n; i++) {
082                        add(predictionList[i]);
083                }       
084        }
085        
086        /**
087         * Adds a candidate to the k-best list
088         * 
089         * @param symbol the string representation of candidate action
090         * @throws MaltChainedException
091         */
092        public void add(String symbol) throws MaltChainedException {
093//              if (decision instanceof SingleDecision) {
094//                      this.add(((SingleDecision)decision).getDecisionCode(symbol));
095//              }
096                this.add(decision.getDecisionCode(symbol));
097        }
098        
099
100        /**
101         * Updates the corresponding single decision with the next value in the k-best list.
102         * 
103         * @return true if decision has been updated, otherwise false
104         * @throws MaltChainedException
105         */
106        public boolean updateActionWithNextKBest() throws MaltChainedException {
107                if (addCandidateIndex != 0 && topCandidateIndex < addCandidateIndex && topCandidateIndex < kBestList.size()) {
108                        int actionCode = kBestList.get(topCandidateIndex).getActionCode();
109                        if (decision instanceof SingleDecision) {
110                                ((SingleDecision)decision).addDecision(actionCode);
111                        }
112                        topCandidateIndex++;
113                        return true;
114                } 
115                return false;
116        }
117        
118        public int peekNextKBest() {
119                if (addCandidateIndex != 0 && topCandidateIndex < addCandidateIndex && topCandidateIndex < kBestList.size()) {
120                        return kBestList.get(topCandidateIndex).getActionCode();
121                }
122                return -1;
123        }
124        
125        /**
126         * Returns the current size of the k-best list
127         * 
128         * @return the current size of the k-best list
129         */
130        public int getCurrentSize() {
131                return addCandidateIndex;
132                //return kBestList.size();
133        }
134        
135        /**
136         * Returns the maximum number of candidates in the k-best list.
137         * 
138         * @return the maximum number of candidates in the k-best list
139         */
140        public int getK() {
141                return k;
142        }
143        /**
144         * Sets the maximum number of candidates in the k-best list
145         * 
146         * @param k the maximum number of candidates 
147         */
148        protected void setK(int k) {
149                if (k == 0) {
150                        this.k = 1; // the k-best list must contain at least one candidate
151                } if (k < 0) {
152                        this.k = -1; // this means that the k-best list is unrestricted.
153                } else {
154                        this.k = k;
155                }
156        }
157        
158        protected int getTopCandidateIndex() {
159                return topCandidateIndex;
160        }
161
162        protected int getAddCandidateIndex() {
163                return addCandidateIndex;
164        }
165
166        /**
167         * Returns a single decision object
168         * 
169         * @return a single decision object
170         */
171        public SingleDecision getDecision() {
172                return decision;
173        }       
174        
175        public int getKBestListSize() {
176                return kBestList.size();
177        }
178        
179        public ScoredCandidate getCandidate(int i) {
180                if (i >= kBestList.size()) {
181                        return null;
182                }
183                return (ScoredCandidate)kBestList.get(i);
184        }
185        
186        /* (non-Javadoc)
187         * @see java.lang.Object#toString()
188         */
189        public String toString() {
190                final StringBuilder sb = new StringBuilder();
191                sb.append("[ ");
192                for (int i = 0; i < addCandidateIndex; i++) {
193                        sb.append(kBestList.get(i));
194                        sb.append(' ');
195                }
196                sb.append("] ");
197                return sb.toString();
198        }
199}