001: /*
002: * (c) Copyright 2006 by Volker Bergmann. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, is permitted under the terms of the
006: * GNU General Public License.
007: *
008: * For redistributing this software or a derivative work under a license other
009: * than the GPL-compatible Free Software License as defined by the Free
010: * Software Foundation or approved by OSI, you must first obtain a commercial
011: * license to this software product from Volker Bergmann.
012: *
013: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
014: * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
015: * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
016: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
017: * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
018: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
019: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
020: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
021: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
022: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
023: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
024: * POSSIBILITY OF SUCH DAMAGE.
025: */
026:
027: package org.databene.benerator.sample;
028:
029: import org.databene.benerator.WeightFunction;
030: import org.databene.benerator.LightweightGenerator;
031: import org.databene.benerator.SimpleRandom;
032: import org.databene.benerator.primitive.number.adapter.IntegerGenerator;
033:
034: import java.util.List;
035: import java.util.ArrayList;
036: import java.util.Collection;
037:
038: /**
039: * Generates values from a weighted or unweighted set of samples.<br/>
040: * <br/>
041: * Created: 07.06.2006 19:04:08
042: */
043: public class WeightedSampleGenerator<E> extends LightweightGenerator<E> {
044:
045: /** Keeps the Sample information */
046: private List<WeightedSample<E>> samples = new ArrayList<WeightedSample<E>>();
047:
048: /** Generator for choosing a List index of the sample list */
049: private IntegerGenerator indexGenerator = new IntegerGenerator(0,
050: 0, 1, new SampleWeightFunction());
051:
052: /** Flag that indicates if the generator needs to be initialized */
053: private boolean dirty = true;
054:
055: // constructors ----------------------------------------------------------------------------------------------------
056:
057: /** Initializes the generator to an empty sample list */
058: public WeightedSampleGenerator() {
059: this ((E[]) null);
060: }
061:
062: /** Initializes the generator to an unweighted sample list */
063: public WeightedSampleGenerator(E... values) {
064: setValues(values);
065: }
066:
067: /** Initializes the generator to an unweighted sample list */
068: public WeightedSampleGenerator(WeightFunction distribution,
069: E... values) {
070: setValues(values);
071: setDistribution(distribution);
072: }
073:
074: /** Initializes the generator to an unweighted sample list */
075: public WeightedSampleGenerator(Collection<E> values) {
076: setValues(values);
077: }
078:
079: /** Initializes the generator to an unweighted sample list */
080: public WeightedSampleGenerator(WeightFunction distribution,
081: Collection<E> values) {
082: setValues(values);
083: setDistribution(distribution);
084: }
085:
086: // /** Initializes the generator to a weighted sample list */
087: // public SampleGenerator(Sample<E> ... samples) {
088: // setSamples(samples);
089: // }
090:
091: // config properties -----------------------------------------------------------------------------------------------
092:
093: public WeightFunction getDistribution() {
094: return (WeightFunction) indexGenerator.getDistribution();
095: }
096:
097: public void setDistribution(WeightFunction distribution) {
098: indexGenerator.setDistribution(distribution);
099: }
100:
101: public Integer getVariation1() {
102: return indexGenerator.getVariation1();
103: }
104:
105: public void setVariation1(Integer varation1) {
106: indexGenerator.setVariation1(varation1);
107: }
108:
109: public Integer getVariation2() {
110: return indexGenerator.getVariation2();
111: }
112:
113: public void setVariation2(Integer variation2) {
114: indexGenerator.setVariation2(variation2);
115: }
116:
117: // samples property ------------------------------------------------------------------------------------------------
118:
119: /** returns the sample list */
120: public List<WeightedSample<E>> getSamples() {
121: return samples;
122: }
123:
124: /** Sets the sample list to the specified weighted values */
125: public void setSamples(WeightedSample<E>... samples) {
126: this .samples.clear();
127: for (WeightedSample<E> sample : samples)
128: this .samples.add(sample);
129: this .dirty = true;
130: }
131:
132: // /** Adds weighted values to the sample list */
133: // public void addSamples(Sample<E> ... samples) {
134: // if (samples != null)
135: // for (Sample<E> sample : samples)
136: // this.addSample(sample);
137: // }
138: //
139: /** Adds weighted values to the sample list */
140: public void setSamples(Collection<WeightedSample<E>> samples) {
141: this .samples.clear();
142: if (samples != null)
143: this .samples.addAll(samples);
144: this .dirty = true;
145: }
146:
147: //
148: // /** Adds weighted values to the sample list */
149: // public void addSample(E value, double weight) {
150: // addSample(new Sample<E>(value, weight));
151: // }
152: //
153: // /** Adds a weighted value to the sample list */
154: // public void addSample(Sample<E> sample) {
155: // samples.add(sample);
156: // valid = false;
157: // }
158: //
159: // values property -------------------------------------------------------------------------------------------------
160:
161: /** Adds unweighted values to the sample list */
162: public void setValues(Collection<E> values) {
163: this .samples.clear();
164: if (values != null)
165: for (E value : values)
166: addValue(value);
167: }
168:
169: /** Sets the sample list to the specified unweighted values */
170: public void setValues(E... values) {
171: this .samples.clear();
172: if (values != null)
173: for (E value : values)
174: addValue(value);
175: }
176:
177: /** Adds unweighted values to the sample list */
178: public void addValues(E... values) {
179: if (values != null)
180: for (E value : values)
181: addValue(value);
182: }
183:
184: /** Adds unweighted values to the sample list */
185: public void addValues(Collection<E> values) {
186: if (values != null)
187: for (E value : values)
188: addValue(value);
189: }
190:
191: /** Adds an unweighted value to the sample list */
192: public void addValue(E value) {
193: samples.add(new WeightedSample<E>(value, 1));
194: this .dirty = true;
195: }
196:
197: // Generator implementation ----------------------------------------------------------------------------------------
198:
199: public Class<E> getGeneratedType() {
200: return (Class<E>) samples.get(0).getClass();
201: }
202:
203: /** Initializes all attributes */
204: public void validate() {
205: if (dirty) {
206: if (samples.size() > 0) {
207: indexGenerator.setMax(samples.size() - 1);
208: indexGenerator.validate();
209: normalize();
210: }
211: this .dirty = false;
212: }
213: }
214:
215: /** @see org.databene.benerator.Generator#generate() */
216: public E generate() {
217: if (dirty)
218: validate();
219: if (samples.size() == 0)
220: return null;
221: int index = indexGenerator.generate();
222: WeightedSample<E> sample = samples.get(index);
223: return sample.getValue();
224: }
225:
226: // static interface ------------------------------------------------------------------------------------------------
227:
228: /** Convenience utility method that chooses one sample out of a list with uniform random distribution */
229: public static <T> T generate(T... samples) {
230: return samples[SimpleRandom.randomInt(0, samples.length - 1)];
231: }
232:
233: /** Convenience utility method that chooses one sample out of a list with uniform random distribution */
234: public static <T> T generate(List<T> samples) {
235: return samples.get(SimpleRandom
236: .randomInt(0, samples.size() - 1));
237: }
238:
239: // implementation --------------------------------------------------------------------------------------------------
240:
241: /** normalizes the sample weights to a sum of 1 */
242: private void normalize() {
243: double totalWeight = totalWeight();
244: for (WeightedSample<E> sample : samples) {
245: if (totalWeight == 0) {
246: sample.setWeight(1. / samples.size());
247: } else {
248: sample.setWeight(sample.getWeight() / totalWeight);
249: }
250: }
251: }
252:
253: /** Calculates the total weight of all samples */
254: private double totalWeight() {
255: double total = 0;
256: for (WeightedSample sample : samples)
257: total += sample.getWeight();
258: return total;
259: }
260:
261: /** Weight function that evaluates the weights that are stored in the sample list. */
262:
263: private class SampleWeightFunction implements WeightFunction {
264:
265: /** @see org.databene.benerator.WeightFunction#value(double) */
266: public double value(double param) {
267: return samples.get((int) param).getWeight();
268: }
269:
270: /** creates a String representation */
271: public String toString() {
272: return getClass().getSimpleName();
273: }
274: }
275:
276: // java.lang.Object overrides --------------------------------------------------------------------------------------
277:
278: public String toString() {
279: return getClass().getSimpleName();
280: }
281: }
|