View Javadoc
1   /*
2    * (c) Copyright 2006-2020 by rapiddweller GmbH & Volker Bergmann. All rights reserved.
3    *
4    * Redistribution and use in source and binary forms, with or without
5    * modification, is permitted under the terms of the
6    * GNU General Public License.
7    *
8    * For redistributing this software or a derivative work under a license other
9    * than the GPL-compatible Free Software License as defined by the Free
10   * Software Foundation or approved by OSI, you must first obtain a commercial
11   * license to this software product from rapiddweller GmbH & Volker Bergmann.
12   *
13   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14   * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
15   * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
16   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
17   * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24   * POSSIBILITY OF SUCH DAMAGE.
25   */
26  
27  package com.rapiddweller.benerator.primitive.number;
28  
29  import com.rapiddweller.benerator.IllegalGeneratorStateException;
30  import com.rapiddweller.benerator.distribution.Distribution;
31  import com.rapiddweller.benerator.distribution.SequenceManager;
32  import com.rapiddweller.benerator.util.GeneratingConverter;
33  import com.rapiddweller.benerator.wrapper.ProductWrapper;
34  import com.rapiddweller.common.Converter;
35  import com.rapiddweller.common.converter.ConverterManager;
36  import com.rapiddweller.model.data.Uniqueness;
37  import com.rapiddweller.script.math.ArithmeticEngine;
38  
39  /**
40   * {@link Converter} implementation that transforms numbers
41   * inducing relative or absolute numerical noise based on a {@link Distribution}.<br/><br/>
42   * Created: 06.10.2010 17:14:46
43   *
44   * @author Volker Bergmann
45   * @since 0.6.4
46   */
47  public class NoiseInducer extends GeneratingConverter<Number, Number, Number> {
48  
49    private double minNoise;
50    private double maxNoise;
51    private double noiseGranularity;
52    private Distribution noiseDistribution;
53    private boolean relative;
54  
55    private Class<? extends Number> numberType;
56    private ArithmeticEngine arithmetic;
57  
58    /**
59     * Instantiates a new Noise inducer.
60     */
61    public NoiseInducer() {
62      this(-0.1, 0.1, 0.001);
63    }
64  
65    /**
66     * Instantiates a new Noise inducer.
67     *
68     * @param minNoise         the min noise
69     * @param maxNoise         the max noise
70     * @param noiseGranularity the noise granularity
71     */
72    public NoiseInducer(double minNoise, double maxNoise, double noiseGranularity) {
73      super(Number.class, Number.class, null);
74      this.minNoise = minNoise;
75      this.maxNoise = maxNoise;
76      this.noiseGranularity = noiseGranularity;
77      this.noiseDistribution = SequenceManager.CUMULATED_SEQUENCE;
78      this.relative = true;
79    }
80  
81    // properties ------------------------------------------------------------------------------------------------------
82  
83    /**
84     * Gets min noise.
85     *
86     * @return the min noise
87     */
88    public double getMinNoise() {
89      return minNoise;
90    }
91  
92    /**
93     * Sets min noise.
94     *
95     * @param minNoise the min noise
96     */
97    public void setMinNoise(double minNoise) {
98      this.minNoise = minNoise;
99    }
100 
101   /**
102    * Gets max noise.
103    *
104    * @return the max noise
105    */
106   public double getMaxNoise() {
107     return maxNoise;
108   }
109 
110   /**
111    * Sets max noise.
112    *
113    * @param maxNoise the max noise
114    */
115   public void setMaxNoise(double maxNoise) {
116     this.maxNoise = maxNoise;
117   }
118 
119   /**
120    * Gets noise granularity.
121    *
122    * @return the noise granularity
123    */
124   public double getNoiseGranularity() {
125     return noiseGranularity;
126   }
127 
128   /**
129    * Sets noise granularity.
130    *
131    * @param noiseGranularity the noise granularity
132    */
133   public void setNoiseGranularity(double noiseGranularity) {
134     this.noiseGranularity = noiseGranularity;
135   }
136 
137   /**
138    * Gets noise distribution.
139    *
140    * @return the noise distribution
141    */
142   public Distribution getNoiseDistribution() {
143     return noiseDistribution;
144   }
145 
146   /**
147    * Sets noise distribution.
148    *
149    * @param noiseDistribution the noise distribution
150    */
151   public void setNoiseDistribution(Distribution noiseDistribution) {
152     this.noiseDistribution = noiseDistribution;
153   }
154 
155   /**
156    * Is relative boolean.
157    *
158    * @return the boolean
159    */
160   public boolean isRelative() {
161     return relative;
162   }
163 
164   /**
165    * Sets relative.
166    *
167    * @param relative the relative
168    */
169   public void setRelative(boolean relative) {
170     this.relative = relative;
171   }
172 
173   // Converter interface implementation ------------------------------------------------------------------------------
174 
175   @Override
176   protected Number doConvert(Number sourceValue) {
177     if (sourceValue == null) {
178       return null;
179     }
180     if (numberType == null) {
181       initialize(sourceValue);
182     }
183     ProductWrapper<Number> wrapper = generate();
184     if (wrapper == null) {
185       throw new IllegalGeneratorStateException("Noise generator unavailable: " + generator);
186     }
187     Number delta = wrapper.unwrap();
188     Number result;
189     if (relative) {
190       result = (Number) arithmetic.multiply(sourceValue, arithmetic.subtract(1, delta));
191     } else {
192       result = (Number) arithmetic.add(sourceValue, delta);
193     }
194     return result;
195   }
196 
197   /**
198    * Convert number.
199    *
200    * @param sourceValue the source value
201    * @param minValue    the min value
202    * @param maxValue    the max value
203    * @return the number
204    */
205   public Number convert(Number sourceValue, Number minValue, Number maxValue) {
206     if (sourceValue == null) {
207       return null;
208     }
209     Number result = convert(sourceValue);
210     double rd = result.doubleValue();
211     if (rd < minValue.doubleValue()) {
212       return minValue;
213     }
214     if (rd > maxValue.doubleValue()) {
215       return maxValue;
216     }
217     return result;
218   }
219 
220   // private helpers -------------------------------------------------------------------------------------------------
221 
222   @Override
223   @SuppressWarnings("unchecked")
224   protected void initialize(Number sourceValue) {
225     this.numberType = (relative ? Double.class : sourceValue.getClass());
226     Converter<Number, ? extends Number> converter = ConverterManager.getInstance().createConverter(Number.class, numberType);
227     arithmetic = new ArithmeticEngine();
228     generator = context.getGeneratorFactory().createNumberGenerator(
229         (Class<Number>) numberType,
230         converter.convert(minNoise), true,
231         converter.convert(maxNoise), true,
232         converter.convert(noiseGranularity),
233         noiseDistribution, Uniqueness.NONE);
234     super.initialize(sourceValue);
235   }
236 
237 }