001    package calhoun.analysis.crf.io;
002    
003    import java.util.Collection;
004    
005    import org.apache.commons.logging.Log;
006    import org.apache.commons.logging.LogFactory;
007    
008    import calhoun.util.Assert;
009    import calhoun.util.RangeMap;
010    
011    /** an input sequence made up of intervals of constant valued features.  Each position is represented
012     * by an {@link IntervalPosition} object.
013     */
014    public class IntervalInputSequence implements InputSequence<IntervalInputSequence.IntervalPosition>{
015            @SuppressWarnings("unused")
016            private static final Log log = LogFactory.getLog(IntervalInputSequence.class);
017    
018            RangeMap rmplus,rmminus;
019            String inputName;
020            int inputLength;
021            
022            /** constructs an input sequence from the necessary data
023             * @param rmplus range map of values on the positive strand
024             * @param rmminus range map of values on the negative strand
025             * @param inputName name of the input sequence
026             * @param inputLength length of the input sequence.  Requires since the intervals may not cover the whole sequence.
027             */
028            public IntervalInputSequence(RangeMap rmplus, RangeMap rmminus, String inputName, int inputLength) {
029                    this.rmplus = rmplus;
030                    this.rmminus = rmminus;
031                    this.inputName = inputName;
032                    this.inputLength = inputLength;
033            }
034            
035            public IntervalPosition getX(int ix) {
036                    IntervalPosition ret = new IntervalPosition(ix);
037                    return ret;
038            }
039    
040            public int length() {
041                    return inputLength;
042            }
043            
044            public IntervalInputSequence subSequence(int start, int end) { // 1-based inclusive
045                    Assert.a(end >= start);
046                    Assert.a(end <= inputLength);
047                    Assert.a(start >= 1);
048                    
049                    RangeMap newRmplus  = shiftedSubRangeMap(rmplus ,start,end);
050                    RangeMap newRmminus = shiftedSubRangeMap(rmminus,start,end);            
051    
052                    return new IntervalInputSequence(newRmplus,newRmminus,inputName,end-start+1);
053            }
054    
055            public InputSequence getComponent(String name) {
056                    throw new UnsupportedOperationException();
057            }
058    
059            public Collection<String> listComponents() {
060                    throw new UnsupportedOperationException();
061            }
062    
063            private RangeMap shiftedSubRangeMap(RangeMap rm, int start, int end) {
064                    Object[] rmplusList = rm.find(start-1,end-1).toArray();
065                    RangeMap newrm = new RangeMap();
066                    for (int i=0; i<rmplusList.length; i++) {
067                            IntervalRangeMapValue irmv = (IntervalRangeMapValue) rmplusList[i];
068                            IntervalRangeMapValue newirmv = new IntervalRangeMapValue(irmv.start-start+1, irmv.end-start+1, irmv.value);
069                            rm.add(newirmv.start,newirmv.end, newirmv);
070                    }
071                    
072                    return newrm;
073            }
074    
075            /** provides interval based queries for a particular position in the input sequence for an IntervalInputSequence. 
076             */
077            public class IntervalPosition {
078                    int pos;
079                    
080                    /** creates an IntervalPosition object for this sequence at this position. 
081                     * @param pos the position on the input sequence */
082                    public IntervalPosition(int pos) {
083                            this.pos = pos;
084                    }
085    
086                    /** returns true if an input interval exists on the positive strand at this position.  */
087                    public boolean queryPlus() {
088                            return (rmplus.find(pos,pos+1).size()>0);
089                    }
090                    
091                    /** returns true if an input interval exists on the negative strand at this position.  */
092                    public boolean queryMinus() {
093                            return (rmminus.find(pos,pos+1).size()>0);
094                    }
095            }
096    
097            static public class IntervalRangeMapValue {
098                    public int start;
099                    public int end;
100                    public double value;
101                    
102                    public IntervalRangeMapValue(int start, int end, double value) {
103                            this.start = start;
104                            this.end = end;
105                            this.value = value;
106                    }
107                    
108                    public void insertIntoRangeMap(RangeMap RM) {
109                            RM.add(start,end,this);
110                    }
111                    
112                    public String toStringStrand(String strand) {
113                            String ret = "(" + start + "," + end + "," + strand + "," + value + ")";
114                            return ret;
115                    }
116                    
117            }
118    }