File: DoubleQuantileEstimator.java

package info (click to toggle)
libcolt-free-java 1.2.0%2Bdfsg-8
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 20,832 kB
  • sloc: java: 30,337; xml: 893; makefile: 26; sh: 3
file content (260 lines) | stat: -rw-r--r-- 8,998 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/*
Copyright (c) 1999 CERN - European Organization for Nuclear Research.
Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose 
is hereby granted without fee, provided that the above copyright notice appear in all copies and 
that both that copyright notice and this permission notice appear in supporting documentation. 
CERN makes no representations about the suitability of this software for any purpose. 
It is provided "as is" without expressed or implied warranty.
*/
package cern.jet.stat.quantile;

import cern.colt.list.DoubleArrayList;
import cern.colt.list.ObjectArrayList;
/**
  * The abstract base class for approximate quantile finders computing quantiles over a sequence of <tt>double</tt> elements.
  */
//abstract class ApproximateDoubleQuantileFinder extends Object implements DoubleQuantileFinder {
abstract class DoubleQuantileEstimator extends cern.colt.PersistentObject implements DoubleQuantileFinder {
	protected DoubleBufferSet bufferSet;
	protected DoubleBuffer currentBufferToFill;
	protected int totalElementsFilled;
/**
 * Makes this class non instantiable, but still let's others inherit from it.
 */
protected DoubleQuantileEstimator() {}
/**
 * Adds a value to the receiver.
 * @param value the value to add.
 */
public void add(double value) {
	totalElementsFilled++;
	if (! sampleNextElement()) return;

	//System.out.println("adding "+value);

	if (currentBufferToFill==null) { 
		if (bufferSet._getFirstEmptyBuffer()==null) collapse();
		newBuffer();
	}

	currentBufferToFill.add(value);
	if (currentBufferToFill.isFull()) currentBufferToFill = null;
}
/**
 * Adds all values of the specified list to the receiver.
 * @param values the list of which all values shall be added.
 */
public void addAllOf(DoubleArrayList values) {
	addAllOfFromTo(values,0,values.size()-1);
}
/**
 * Adds the part of the specified list between indexes <tt>from</tt> (inclusive) and <tt>to</tt> (inclusive) to the receiver.
 *
 * @param values the list of which elements shall be added.
 * @param from the index of the first element to be added (inclusive).
 * @param to the index of the last element to be added (inclusive).
 */
public void addAllOfFromTo(DoubleArrayList values, int from, int to) {
	/*
	// the obvious version, but we can do quicker...
	double[] theValues = values.elements();
	int theSize=values.size();
	for (int i=0; i<theSize; ) add(theValues[i++]);
	*/
	
	double[] valuesToAdd = values.elements();
	int k = this.bufferSet.k();
	int bufferSize = k;
	double[] bufferValues = null;
	if (currentBufferToFill != null) {
		bufferValues = currentBufferToFill.values.elements();
		bufferSize = currentBufferToFill.size();
	}

	for (int i=from-1; ++i <= to; ) {
		if (sampleNextElement()) {
			if (bufferSize == k) { // full
				if (bufferSet._getFirstEmptyBuffer()==null) collapse();
				newBuffer();
				if (!currentBufferToFill.isAllocated) currentBufferToFill.allocate();
				currentBufferToFill.isSorted = false;
				bufferValues = currentBufferToFill.values.elements();
				bufferSize = 0;
			}

			bufferValues[bufferSize++] = valuesToAdd[i];
			if (bufferSize == k) { // full
				currentBufferToFill.values.setSize(bufferSize);
				currentBufferToFill = null;
			}
		}
	}
	if (this.currentBufferToFill != null) {
		this.currentBufferToFill.values.setSize(bufferSize);
	}
	
	this.totalElementsFilled += to-from+1;
}
/**
 * Not yet commented.
 */
protected DoubleBuffer[] buffersToCollapse() {
	int minLevel = bufferSet._getMinLevelOfFullOrPartialBuffers();
	return bufferSet._getFullOrPartialBuffersWithLevel(minLevel);
}
/**
 * Removes all elements from the receiver.  The receiver will
 * be empty after this call returns, and its memory requirements will be close to zero.
 */
public void clear() {
	this.totalElementsFilled = 0;
	this.currentBufferToFill = null;
	this.bufferSet.clear();
}
/**
 * Returns a deep copy of the receiver.
 *
 * @return a deep copy of the receiver.
 */
public Object clone() {
	DoubleQuantileEstimator copy = (DoubleQuantileEstimator) super.clone();
	if (this.bufferSet != null) {
		copy.bufferSet = (DoubleBufferSet) copy.bufferSet.clone();
		if (this.currentBufferToFill != null) {
			 int index = new ObjectArrayList(this.bufferSet.buffers).indexOf(this.currentBufferToFill, true);
			 copy.currentBufferToFill = copy.bufferSet.buffers[index];
		}		
	}
	return copy;
}
/**
 * Not yet commented.
 */
protected void collapse() {
	DoubleBuffer[] toCollapse = buffersToCollapse();
	DoubleBuffer outputBuffer = bufferSet.collapse(toCollapse);

	int minLevel = toCollapse[0].level();
	outputBuffer.level(minLevel + 1);

	postCollapse(toCollapse);
}
/**
 * Returns whether the specified element is contained in the receiver.
 */
public boolean contains(double element) {
	return bufferSet.contains(element);
}
/**
 * Applies a procedure to each element of the receiver, if any.
 * Iterates over the receiver in no particular order.
 * @param procedure    the procedure to be applied. Stops iteration if the procedure returns <tt>false</tt>, otherwise continues. 
 * @return <tt>false</tt> if the procedure stopped before all elements where iterated over, <tt>true</tt> otherwise. 
 */
public boolean forEach(cern.colt.function.DoubleProcedure procedure) {
	return this.bufferSet.forEach(procedure);
}
/**
 * Returns the number of elements currently needed to store all contained elements.
 * This number usually differs from the results of method <tt>size()</tt>, according to the underlying datastructure.
 */
public long memory() {
	return bufferSet.memory();
}
/**
 * Not yet commented.
 */
protected abstract void newBuffer();
/**
 * Returns how many percent of the elements contained in the receiver are <tt>&lt;= element</tt>.
 * Does linear interpolation if the element is not contained but lies in between two contained elements.
 *
 * @param the element to search for.
 * @return the percentage <tt>p</tt> of elements <tt>&lt;= element</tt> (<tt>0.0 &lt;= p &lt;=1.0)</tt>.
 */
public double phi(double element) {
	return bufferSet.phi(element);
}
/**
 * Not yet commented.
 */
protected abstract void postCollapse(DoubleBuffer[] toCollapse);
/**
 * Default implementation does nothing.
 */
protected DoubleArrayList preProcessPhis(DoubleArrayList phis) {
	return phis;
}
/**
 * Computes the specified quantile elements over the values previously added.
 * @param phis the quantiles for which elements are to be computed. Each phi must be in the interval [0.0,1.0]. <tt>phis</tt> must be sorted ascending.
 * @return the approximate quantile elements.
 */
public DoubleArrayList quantileElements(DoubleArrayList phis) {
	/*
	//check parameter
	DoubleArrayList sortedPhiList = phis.copy();
	sortedPhiList.sort();
	if (! phis.equals(sortedPhiList)) {
		throw new IllegalArgumentException("Phis must be sorted ascending.");
	}
	*/

	//System.out.println("starting to augment missing values, if necessary...");

	phis = preProcessPhis(phis);
	
	long[] triggerPositions = new long[phis.size()];
	long totalSize = this.bufferSet.totalSize();
	for (int i=phis.size(); --i >=0;) {
		triggerPositions[i]=Utils.epsilonCeiling(phis.get(i) * totalSize)-1;
	}

	//System.out.println("triggerPositions="+cern.colt.Arrays.toString(triggerPositions));
	//System.out.println("starting to determine quantiles...");
	//System.out.println(bufferSet);

	DoubleBuffer[] fullBuffers = bufferSet._getFullOrPartialBuffers();
	double[] quantileElements = new double[phis.size()];

	//do the main work: determine values at given positions in sorted sequence
	return new DoubleArrayList(bufferSet.getValuesAtPositions(fullBuffers, triggerPositions));
}
/**
 * Not yet commented.
 */
protected abstract boolean sampleNextElement();
/**
 * Initializes the receiver
 */
protected void setUp(int b, int k) {
	if (!(b>=2 && k>=1)) {
		throw new IllegalArgumentException("Assertion: b>=2 && k>=1");
	}
	this.bufferSet = new DoubleBufferSet(b,k);
	this.clear();
}
/**
 * Returns the number of elements currently contained in the receiver (identical to the number of values added so far).
 */
public long size() {
	return totalElementsFilled;
}
/**
 * Returns a String representation of the receiver.
 */
public String toString() {
	String s=this.getClass().getName();
	s = s.substring(s.lastIndexOf('.')+1);
	int b = bufferSet.b();
	int k = bufferSet.k();
	return s + "(mem="+memory()+", b="+b+", k="+k+", size="+size()+", totalSize="+this.bufferSet.totalSize()+")";
}
/**
 * Returns the number of elements currently needed to store all contained elements.
 * This number usually differs from the results of method <tt>size()</tt>, according to the underlying datastructure.
 */
public long totalMemory() {
	return bufferSet.b()*bufferSet.k();
}
}