    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    }