001    package calhoun.analysis.crf.io;
002    
003    import java.util.Collection;
004    import java.util.HashMap;
005    import java.util.Map;
006    
007    import calhoun.util.Assert;
008    
009    /** a composite input sequence made up of individual components.  This is useful when putting together different
010     * features that may take different inputs.  Each component is given a name within the overall composite and can
011     * be reference by that name.  All sequences must have the same length.  The value at any position in the sequence
012     * is a map that relates component names to their values at that position.  */
013    public class InputSequenceComposite implements InputSequence<Map<String, Object>> {
014    
015            Map<String, InputSequence<?>> components = new HashMap<String, InputSequence<?>>();
016            int length = -1;
017    
018            /** default constructor.  Components should be added with addComponents. */
019            public InputSequenceComposite() {
020            }
021            
022            /** constructor that initializes the sequence with a set of components. 
023             * @param data the initial input sequences to use as the components */
024            public InputSequenceComposite(Map<String, InputSequence<?>> data) {
025                    addComponents(data);
026            }
027            
028            /** adds a new component input sequence to this composite.  Each new component must have a unique name and all 
029             * components must have the same length. */
030            public void addComponent(String name, InputSequence<?> seq) {
031                    Assert.a(!components.containsKey(name), "Component already exists in composite input: ", name);
032                    if(length == -1) {
033                            length = seq.length();
034                    }
035                    Assert.a(seq.length() == -1 || length == seq.length(), "Composite sequence has length ", length, " but attempted to add component named ", name, " of length ", seq.length());
036                    components.put(name, seq);
037            }
038            
039            /** adds all input sequences in the given map as components. */
040            public void addComponents(Map<String, InputSequence<?>> data) {
041                    for(Map.Entry<String, InputSequence<?>> entry : data.entrySet()) {
042                            addComponent(entry.getKey(), entry.getValue());
043                    }
044            }
045    
046            /** returns all of components of this input sequence.
047             * @return a map that maps component names to input sequences
048             */
049            public Map<String, InputSequence<?>> getComponents() {
050                    return components;
051            }
052    
053            public Map<String, Object> getX(int ix) {
054                    Map<String, Object> ret = new HashMap<String, Object>();
055                    for(Map.Entry<String, InputSequence<?>> entry : components.entrySet()) {
056                            ret.put(entry.getKey(), entry.getValue().getX(ix));
057                    }
058                    return ret;
059            }
060    
061            public int length() {
062                    Assert.a(components.size() > 0, "Length of composite sequence was called before any components were added.");
063                    return length;
064            }
065    
066            public InputSequence<?> getComponent(String name) {
067                    return components.get(name);
068            }
069    
070            public Collection<String> listComponents() {
071                    return components.keySet();
072            }
073    
074            public InputSequenceComposite subSequence(int start, int end) {
075                    Assert.a(start >= 1);
076                    Assert.a(end <= length());
077                    Assert.a(start <= end);              
078                    
079                    InputSequenceComposite ret = new InputSequenceComposite();
080                    for(Map.Entry<String, InputSequence<?>> entry : components.entrySet()) {
081                            ret.addComponent(entry.getKey(), entry.getValue().subSequence(start,end));
082                    }
083                    
084                    return ret;
085            }
086    }