001package org.maltparser.ml.lib;
002
003import java.io.Serializable;
004
005
006import org.maltparser.core.helper.HashMap;
007
008/**
009 * The purpose of the feature map is to map MaltParser's column based features together with the symbol code from the symbol table to 
010 * unique indices suitable for liblinear and libsvm.  A feature column position are combined together with the symbol code in a 
011 * 64-bit key (Long), where 16 bits are reserved for the position and 48 bits are reserved for the symbol code.  
012 * 
013 * @author Johan Hall
014 *
015 */
016public class FeatureMap  implements Serializable {
017        private static final long serialVersionUID = 7526471155622776147L;
018        private final HashMap<Long,Integer> map;
019        private int featureCounter;
020        
021        /**
022         * Creates a feature map and sets the feature counter to 1
023         */
024        public FeatureMap() {
025                map = new HashMap<Long, Integer>();
026                this.featureCounter = 1;
027        }
028        
029        /**
030         * Adds a mapping from a combination of the position in the column-based feature vector and the symbol code to 
031         * an index value suitable for liblinear and libsvm.
032         * 
033         * @param featurePosition a position in the column-based feature vector
034         * @param code a symbol code
035         * @return the index value 
036         */
037        public int addIndex(int featurePosition, int code) {
038                final long key = ((((long)featurePosition) << 48) | (long)code);
039                Integer index = map.get(key);
040                if (index == null) {
041                        index = featureCounter++;
042                        map.put(key, index);
043                }
044                return index.intValue();
045        }
046        
047        /**
048         * Return
049         * 
050         * @param featurePosition the position in the column-based feature vector
051         * @param code the symbol code suitable for liblinear and libsvm
052         * @return the index value if it exists, otherwise -1
053         */
054        public int getIndex(int featurePosition, int code) {
055                final Integer index = map.get(((((long)featurePosition) << 48) | (long)code));
056                return (index == null)?-1:index;
057        }
058        
059        
060        public int addIndex(int featurePosition, int code1, int code2) {
061                final long key = ((((long)featurePosition) << 48) | (((long)code1) << 24) | (long)code2);
062                Integer index = map.get(key);
063                if (index == null) {
064                        index = featureCounter++;
065                        map.put(key, index);
066                }
067                return index.intValue();
068        }
069        
070        public int setIndex(long key, int index) {
071                return map.put(key, index);
072        }
073        
074        public int decrementIndex(Long key) {
075                Integer index = map.get(key);
076                if (index != null) {
077                        map.put(key, index - 1);
078                }
079                return (index != null)?index - 1 : -1;
080        }
081        
082        public void decrementfeatureCounter() {
083                featureCounter--;
084        }
085        
086        public Integer removeIndex(long key) {
087                return map.remove(key);
088        }
089        
090        public int getIndex(int featurePosition, int code1, int code2) {
091                final Integer index = map.get(((((long)featurePosition) << 48) | (((long)code1) << 24) | (long)code2));
092                return (index == null)?-1:index;
093        }
094                
095        /**
096         * @return the size of the map
097         */
098        public int size() {
099                return map.size();
100        }
101        
102        
103        public Long[] reverseMap() {
104                Long[] reverseMap = new Long[map.size() +1];
105
106                for (Long key : map.keySet()) {
107                        reverseMap[map.get(key)] = key;
108                }
109                return reverseMap;
110        }
111        
112        
113        
114        public void setFeatureCounter(int featureCounter) {
115                this.featureCounter = featureCounter;
116        }
117
118        /**
119         * @return the current value of the feature counter.
120         */
121        public int getFeatureCounter() {
122                return featureCounter;
123        }
124}