001/*
002 * $Id$
003 */
004
005package edu.jas.root;
006
007
008import java.io.Serializable;
009import java.util.SortedSet;
010import java.util.TreeSet;
011
012import edu.jas.arith.BigDecimal;
013import edu.jas.arith.BigRational;
014import edu.jas.arith.Rational;
015import edu.jas.structure.RingElem;
016import edu.jas.structure.RingFactory;
017
018
019/**
020 * Interval. For example isolating interval for real roots.
021 * @param <C> coefficient type.
022 * @author Heinz Kredel
023 */
024public class Interval<C extends RingElem<C> & Rational> implements Serializable { //findbugs
025
026
027    /**
028     * left interval border.
029     */
030    public final C left;
031
032
033    /**
034     * right interval border.
035     */
036    public final C right;
037
038
039    /**
040     * Constructor.
041     * @param left interval border.
042     * @param right interval border.
043     */
044    public Interval(C left, C right) {
045        this.left = left;
046        this.right = right;
047    }
048
049
050    /**
051     * Constructor.
052     * @param mid left and right interval border.
053     */
054    public Interval(C mid) {
055        this(mid, mid);
056    }
057
058
059    /**
060     * String representation of Interval.
061     * @see java.lang.Object#toString()
062     */
063    @Override
064    public String toString() {
065        return "[" + left + ", " + right + "]";
066        //return "[" + left.getRational().getDecimal() + ", " + right.getRational().getDecimal() + "]";
067    }
068
069
070    /**
071     * Get a scripting compatible string representation.
072     * @return script compatible representation for this Interval.
073     */
074    public String toScript() {
075        // Python case
076        return "[ " + left.toScript() + ", " + right.toScript() + " ]";
077    }
078
079
080    /**
081     * Copy this.
082     * @return a copy of this.
083     */
084    public Interval<C> copy() {
085        return new Interval<C>(left, right);
086    }
087
088
089    /**
090     * Comparison with any other object.
091     * @see java.lang.Object#equals(java.lang.Object)
092     */
093    @Override
094    @SuppressWarnings("unchecked")
095    public boolean equals(Object b) {
096        if (!(b instanceof Interval)) {
097            return false;
098        }
099        Interval<C> a = null;
100        try {
101            a = (Interval<C>) b;
102        } catch (ClassCastException e) {
103            return false;
104        }
105        return left.equals(a.left) && right.equals(a.right);
106    }
107
108
109    /**
110     * Hash code for this Interval.
111     * @see java.lang.Object#hashCode()
112     */
113    @Override
114    public int hashCode() {
115        return 37 * left.hashCode() + right.hashCode();
116    }
117
118
119    /**
120     * Test if an element is contained in this interval.
121     * @param c element to test.
122     * @return true, if left &le; b &le; right;
123     */
124    public boolean contains(C c) {
125        return left.compareTo(c) <= 0 && c.compareTo(right) <= 0;
126    }
127
128
129    /**
130     * Test if an interval is contained in this interval.
131     * @param vc interval to test.
132     * @return true, if left &le; vc.left and vc.right &le; right;
133     */
134    public boolean contains(Interval<C> vc) {
135        return contains(vc.left) && contains(vc.right);
136    }
137
138
139    /**
140     * Length.
141     * @return |left-right|;
142     */
143    public C length() {
144        C m = right.subtract(left);
145        return m.abs();
146    }
147
148
149    /**
150     * BigRational Length.
151     * @return |left-right|;
152     */
153    public BigRational rationalLength() {
154        return length().getRational();
155    }
156
157
158    /**
159     * BigDecimal representation of Interval.
160     */
161    public BigDecimal toDecimal() {
162        BigDecimal l = new BigDecimal(left.getRational());
163        BigDecimal r = new BigDecimal(right.getRational());
164        BigDecimal two = new BigDecimal(2);
165        BigDecimal v = l.sum(r).divide(two);
166        return v;
167    }
168
169
170    /**
171     * Rational middle point.
172     * @return (left+right)/2;
173     */
174    public BigRational rationalMiddle() {
175        BigRational m = left.getRational().sum(right.getRational());
176        BigRational t = new BigRational(1L, 2L);
177        m = m.multiply(t);
178        return m;
179    }
180
181
182    /**
183     * Middle point.
184     * @return (left+right)/2;
185     */
186    public C middle() {
187        C m = left.sum(right);
188        C h = left.factory().parse("1/2");
189        m = m.multiply(h);
190        return m;
191    }
192
193
194    /**
195     * Random point of interval.
196     * @return a random point contained in this interval.
197     */
198    public C randomPoint() {
199        C dr = right.subtract(left);
200        RingFactory<C> fac = (RingFactory<C>) dr.factory();
201        C r = fac.random(13);
202        r = r.abs();
203        if (!r.isZERO()) {
204            if (r.compareTo(fac.getONE()) > 0) {
205                r = r.inverse();
206            }
207        }
208        // 0 <= r <= 1
209        dr = dr.multiply(r);
210        C rv = left.sum(dr);
211        //System.out.println("rv   = " + new BigDecimal(rv.getRational()) );
212        return rv;
213    }
214
215
216    /**
217     * Sum of intervals.
218     * @param o other interval.
219     * @return this+other
220     */
221    public Interval<C> sum(Interval<C> o) {
222        C l = left.sum(o.left);
223        C r = right.sum(o.right);
224        Interval<C> v = new Interval<C>(l, r);
225        return v;
226    }
227
228
229    /**
230     * Subtract intervals.
231     * @param o other interval.
232     * @return this-other
233     */
234    public Interval<C> subtract(Interval<C> o) {
235        C l = left.subtract(o.right);
236        C r = right.subtract(o.left);
237        Interval<C> v = new Interval<C>(l, r);
238        return v;
239    }
240
241
242    /**
243     * Multiply intervals.
244     * @param o other interval.
245     * @return this*other
246     */
247    public Interval<C> multiply(Interval<C> o) {
248        C v1 = left.multiply(o.left);
249        C v2 = left.multiply(o.right);
250        C v3 = right.multiply(o.left);
251        C v4 = right.multiply(o.right);
252        SortedSet<C> so = new TreeSet<C>();
253        so.add(v1); so.add(v2); so.add(v3); so.add(v4);
254        //System.out.println("sorted set = " + so);
255        Interval<C> v = new Interval<C>(so.first(), so.last());
256        return v;
257    }
258
259}