View Javadoc

1   /*
2    * jcurl java curling software framework http://www.jcurl.org Copyright (C)
3    * 2005-2009 M. Rohrmoser
4    * 
5    * This program is free software; you can redistribute it and/or modify it under
6    * the terms of the GNU General Public License as published by the Free Software
7    * Foundation; either version 2 of the License, or (at your option) any later
8    * version.
9    * 
10   * This program is distributed in the hope that it will be useful, but WITHOUT
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12   * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13   * details.
14   * 
15   * You should have received a copy of the GNU General Public License along with
16   * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17   * Place, Suite 330, Boston, MA 02111-1307 USA
18   */
19  package org.jcurl.math;
20  
21  import java.io.Serializable;
22  import java.util.ArrayList;
23  import java.util.Comparator;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Map.Entry;
28  
29  import org.apache.commons.logging.Log;
30  import org.jcurl.core.log.JCLoggerFactory;
31  
32  /**
33   * Combined curve. Becomes more and more similar to {@link List} with some
34   * restrictions and additions.
35   * 
36   * @param <T>
37   *            type of the parts to be combined.
38   * @author <a href="mailto:m@jcurl.org">M. Rohrmoser </a>
39   * @version $Id: CurveCombined.java 1031 2009-07-23 15:06:05Z mro $
40   */
41  public class CurveCombined<T extends R1RNFunction> extends R1RNFunctionImpl
42  		implements Iterable<Entry<Double, T>>, Serializable {
43  	/**
44  	 * One segment of the combined curve.
45  	 * 
46  	 * @author <a href="mailto:m@jcurl.org">M. Rohrmoser </a>
47  	 * @version $Id: CurveCombined.java 1031 2009-07-23 15:06:05Z mro $
48  	 */
49  	public static class Part<U extends R1RNFunction> extends Number implements
50  			Entry<Double, U>, Comparable<Number> {
51  		private static final long serialVersionUID = 2799393238450079381L;
52  		private final U curve;
53  		private final Double t0;
54  
55  		public Part(final double t0, final U f) {
56  			this.t0 = new Double(t0);
57  			curve = f;
58  		}
59  
60  		public int compareTo(final Number o2) {
61  			if (doubleValue() < o2.doubleValue())
62  				return -1;
63  			if (doubleValue() > o2.doubleValue())
64  				return 1;
65  			return 0;
66  		}
67  
68  		@Override
69  		public double doubleValue() {
70  			return getKey();
71  		}
72  
73  		@Override
74  		public float floatValue() {
75  			return (float) doubleValue();
76  		}
77  
78  		public Double getKey() {
79  			return t0;
80  		}
81  
82  		public U getValue() {
83  			return curve;
84  		}
85  
86  		@Override
87  		public int intValue() {
88  			return (int) doubleValue();
89  		}
90  
91  		@Override
92  		public long longValue() {
93  			return (long) doubleValue();
94  		}
95  
96  		public U setValue(final U value) {
97  			throw new UnsupportedOperationException();
98  		}
99  
100 		@Override
101 		public String toString() {
102 			return new StringBuilder().append("[").append(getKey()).append(
103 					" : ").append(getValue()).append("]").toString();
104 		}
105 	}
106 
107 	private static final Log log = JCLoggerFactory
108 			.getLogger(CurveCombined.class);
109 
110 	private static final long serialVersionUID = 5955065096153576747L;
111 
112 	/**
113 	 * Search only part of an array.
114 	 * 
115 	 * @see java.util.Arrays#binarySearch(double[], double)
116 	 * @param a
117 	 * @param min
118 	 * @param max
119 	 * @param key
120 	 * @return found index
121 	 */
122 	static int binarySearch(final double[] a, int min, int max, final double key) {
123 		// if(true) {
124 		// return Arrays.binarySearch(a, min, max, key);
125 		// } else
126 		for (;;) {
127 			if (key == a[min])
128 				return min;
129 			if (key == a[max])
130 				return max;
131 			final int m = (max + min) / 2;
132 			if (key == a[m])
133 				return m;
134 			if (min + 1 >= max) {
135 				if (a[min] < key && key < a[max])
136 					return -1 - max;
137 				return -1;
138 			}
139 			if (key < a[m]) {
140 				max = m;
141 				continue;
142 			} else if (key > a[m]) {
143 				min = m;
144 				continue;
145 			}
146 		}
147 	}
148 
149 	/**
150 	 * Search only part of a list.
151 	 * 
152 	 * @param a
153 	 * @param fromIndex
154 	 * @param toIndex
155 	 * @param key
156 	 * @param comp
157 	 * 
158 	 * @return found index
159 	 */
160 	static <E> int binarySearch(final List<E> a, final int fromIndex,
161 			final int toIndex, final E key, final Comparator<? super E> comp) {
162 		if (fromIndex > toIndex)
163 			throw new IllegalArgumentException("fromIndex(" + fromIndex
164 					+ ") > toIndex(" + toIndex + ")");
165 		if (fromIndex < 0)
166 			throw new ArrayIndexOutOfBoundsException(fromIndex);
167 		if (toIndex > a.size())
168 			throw new ArrayIndexOutOfBoundsException(toIndex);
169 
170 		int low = fromIndex;
171 		int high = toIndex - 1;
172 		while (low <= high) {
173 			final int mid = low + high >>> 1;
174 			final E midVal = a.get(mid);
175 			final int cmp = comp.compare(midVal, key);
176 			if (cmp < 0)
177 				low = mid + 1;
178 			else if (cmp > 0)
179 				high = mid - 1;
180 			else
181 				return mid; // done
182 		}
183 		return -(low + 1); // no such key
184 	}
185 
186 	/**
187 	 * Search only part of an array. Could be more general operating with
188 	 * {@link Comparable} and {@link Object}s.
189 	 * 
190 	 * @param a
191 	 * @param fromIndex
192 	 * @param toIndex
193 	 * @param key
194 	 * 
195 	 * @return found index
196 	 */
197 	static <V extends R1RNFunction> int binarySearch(
198 			final List<Entry<Double, V>> a, int fromIndex, int toIndex,
199 			final double key) {
200 		if (false) {
201 			if (fromIndex > toIndex)
202 				throw new IllegalArgumentException("fromIndex(" + fromIndex
203 						+ ") > toIndex(" + toIndex + ")");
204 			if (fromIndex < 0)
205 				throw new ArrayIndexOutOfBoundsException(fromIndex);
206 			if (toIndex > a.size())
207 				throw new ArrayIndexOutOfBoundsException(toIndex);
208 
209 			int low = fromIndex;
210 			int high = toIndex - 1;
211 			while (low <= high) {
212 				final int mid = low + high >>> 1;
213 				final double midVal = a.get(mid).getKey().doubleValue();
214 				final int cmp = Double.compare(midVal, key);
215 				if (cmp < 0)
216 					low = mid + 1;
217 				else if (cmp > 0)
218 					high = mid - 1;
219 				else
220 					return mid; // done
221 			}
222 			return -(low + 1); // no such key
223 		} else {
224 			double fromKey = a.get(fromIndex).getKey().doubleValue();
225 			double toKey = a.get(toIndex).getKey().doubleValue();
226 			for (;;) {
227 				if (key == fromKey)
228 					return fromIndex;
229 				if (key == toKey)
230 					return toIndex;
231 				final int midIndex = (toIndex + fromIndex) / 2;
232 				final double midKey = a.get(midIndex).getKey().doubleValue();
233 				if (key == midKey)
234 					return midIndex;
235 				if (fromIndex + 1 >= toIndex) {
236 					if (fromKey < key && key < toKey)
237 						return -1 - toIndex;
238 					return -1;
239 				}
240 				if (key < midKey) {
241 					toIndex = midIndex;
242 					toKey = midKey;
243 					continue;
244 				} else if (key > midKey) {
245 					fromIndex = midIndex;
246 					fromKey = midKey;
247 					continue;
248 				}
249 			}
250 		}
251 	}
252 
253 	Map<Integer, String> m;
254 	private final List<Entry<Double, T>> parts = new ArrayList<Entry<Double, T>>();
255 
256 	public CurveCombined(final int dim) {
257 		super(dim);
258 	}
259 
260 	public void add(final double t0, final T fkt, final boolean dropTail) {
261 		log.debug("");
262 		if (fkt.dim() != dim())
263 			throw new IllegalArgumentException();
264 		if (dropTail) {
265 			final int idx = findFunctionIndex(t0);
266 			for (int i = parts.size() - 1; i > idx; i--)
267 				parts.remove(i);
268 		}
269 		parts.add(new Part<T>(t0, fkt));
270 	}
271 
272 	/**
273 	 * Get the n-th derivative of all dimensions.
274 	 * 
275 	 * @param t
276 	 * @param c
277 	 *            derivative
278 	 * @param ret
279 	 *            <code>null</code> creates a new instance
280 	 * 
281 	 * @return the value
282 	 * @see R1RNFunctionImpl#at(double, int, double[])
283 	 */
284 	@Override
285 	public double[] at(final double t, final int c, final double[] ret) {
286 		return parts.get(findFunctionIndex(t)).getValue().at(t, c, ret);
287 	}
288 
289 	@Override
290 	public double at(final double t, final int c, final int dim) {
291 		return parts.get(findFunctionIndex(t)).getValue().at(t, c, dim);
292 	}
293 
294 	public void clear() {
295 		parts.clear();
296 	}
297 
298 	/**
299 	 * Drop all segments with t0 &gt;= t.
300 	 * 
301 	 * @param t
302 	 * @return <code>false</code> nothing dropped.
303 	 */
304 	public boolean dropTail(final double t) {
305 		if (Double.isNaN(t))
306 			return false;
307 		final int n = parts.size() - 1;
308 		if (n < 0)
309 			return false;
310 		int j = findFunctionIndex(t);
311 		if (parts.get(j).getKey() == t)
312 			j += 1;
313 		if (n < j)
314 			return false;
315 		for (int i = n; i >= j; i--)
316 			parts.remove(i);
317 		return true;
318 	}
319 
320 	private int findFunctionIndex(final double t) {
321 		int highIdx = parts.size() - 1;
322 		if (highIdx < 0)
323 			return -1;
324 		double highKey = parts.get(highIdx).getKey();
325 		if (t >= highKey)
326 			return highIdx;
327 
328 		int lowIdx = 0;
329 		double lowKey = parts.get(lowIdx).getKey();
330 		if (t < lowKey)
331 			return -1;
332 
333 		while (lowIdx + 1 < highIdx) {
334 			final int midIdx = (highIdx + lowIdx) / 2;
335 			final double midKey = parts.get(midIdx).getKey();
336 
337 			if (t >= midKey) {
338 				// Throw away left half
339 				lowIdx = midIdx;
340 				lowKey = midKey;
341 			} else {
342 				// Throw away right half
343 				highIdx = midIdx;
344 				highKey = midKey;
345 			}
346 		}
347 		return lowIdx;
348 	}
349 
350 	public T first() {
351 		if (parts.size() <= 0)
352 			return null;
353 		return parts.get(0).getValue();
354 	}
355 
356 	public Iterator<Entry<Double, T>> iterator() {
357 		return parts.iterator();
358 	}
359 
360 	@Override
361 	public String toString() {
362 		final StringBuilder b = new StringBuilder();
363 		b.append('[');
364 		for (final Entry<Double, T> elem : parts)
365 			b.append("x>=").append(elem.getKey()).append(" f(x)=").append(
366 					elem.getValue()).append(", ");
367 		if (b.length() > 2)
368 			b.setLength(b.length() - 2);
369 		b.append(']');
370 		return b.toString();
371 	}
372 }