View Javadoc
1   package org.opentrafficsim.simulationengine;
2   
3   /**
4    * Property that describes a probability distribution.
5    * <p>
6    * Copyright (c) 2013-2014 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights
7    * reserved. <br>
8    * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
9    * <p>
10   * @version 18 dec. 2014 <br>
11   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
12   */
13  public class ProbabilityDistributionProperty extends AbstractProperty<Double[]>
14  {
15      /** The current set of probability values (should add up to 1.0). */
16      private Double[] value;
17  
18      /** The names of the values. */
19      private String[] names;
20  
21      /** The shortName of the property. */
22      private String shortName;
23  
24      /** The description of the property. */
25      private String description;
26  
27      /** The property is read-only. */
28      private final Boolean readOnly;
29  
30      /**
31       * Construct a new ProbabilityDistributionProperty.
32       * @param shortName String; the short name of the new ProbabilityDistributionProperty
33       * @param description String; the description of the new ProbabilityDistributionProperty (may use HTML markup)
34       * @param elementNames String[]; names of the elements that, together, add up to probability 1.0
35       * @param initialValue Double[]; array of Double values
36       * @param readOnly boolean; if true this ProbabilityDistributionProperty can not be altered
37       * @param displayPriority int; the display priority of the new ProbabilityDistributionProperty
38       * @throws PropertyException when the array is empty, any value is outside the range 0.0 .. 1.0, or when the sum of
39       *             the values is not equal to 1.0 within a small error margin
40       */
41      public ProbabilityDistributionProperty(final String shortName, final String description,
42              final String[] elementNames, final Double[] initialValue, final boolean readOnly, final int displayPriority)
43              throws PropertyException
44      {
45          super(displayPriority);
46          this.shortName = shortName;
47          this.description = description;
48          this.names = new String[elementNames.length];
49          for (int i = 0; i < elementNames.length; i++)
50          {
51              this.names[i] = elementNames[i];
52          }
53          verifyProposedValues(initialValue);
54          copyValue(initialValue);
55          this.readOnly = readOnly;
56      }
57  
58      /**
59       * Verify that a provided array of probability values is acceptable.
60       * @param values double[]; the array of values to verify
61       * @throws PropertyException when the number of values is 0, any value is outside [0..1], or the sum of the values
62       *             does not add up to 1.0 within a (very small) error margin
63       */
64      private void verifyProposedValues(final Double[] values) throws PropertyException
65      {
66          if (values.length < 1)
67          {
68              throw new PropertyException("Array of probability values may not be empty");
69          }
70          double sum = 0.0;
71          for (double v : values)
72          {
73              if (v < 0.0 || v > 1.0)
74              {
75                  throw new PropertyException("Probability value " + v + " is invalid (valid range is 0.0..1.0)");
76              }
77              sum += v;
78          }
79          double maximumError = Math.ulp(1.0) * values.length;
80          if (sum < 1.0 - maximumError || sum > 1.0 + maximumError)
81          {
82              throw new PropertyException("Probabilities do not add up to 1.0 (actual sum is " + sum + ")");
83          }
84  
85      }
86  
87      /** {@inheritDoc} */
88      @Override
89      public final Double[] getValue()
90      {
91          // Double is immutable; but we should return a shallow copy of the array so the caller can't replace the
92          // elements of our array
93          return this.value.clone();
94      }
95  
96      /**
97       * Retrieve one probability value.
98       * @param index int; the index of the requested probability value
99       * @return Double; the requested probability value
100      */
101     final Double getValue(final int index)
102     {
103         return this.value[index];
104     }
105 
106     /**
107      * Retrieve the name of one of the values of this ProbabilityDistributionProperty.
108      * @param index int; the index of the value
109      * @return String; the name of the value at the requested index
110      */
111     final String getElementName(final int index)
112     {
113         return this.names[index];
114     }
115 
116     /** {@inheritDoc} */
117     @Override
118     public final String getShortName()
119     {
120         return this.shortName;
121     }
122 
123     /** {@inheritDoc} */
124     @Override
125     public final String getDescription()
126     {
127         return this.description;
128     }
129 
130     /** {@inheritDoc} */
131     @Override
132     public final void setValue(final Double[] newValue) throws PropertyException
133     {
134         if (this.readOnly)
135         {
136             throw new PropertyException("This property is read-only");
137         }
138         updateValue(newValue);
139     }
140 
141     /**
142      * Make a deep copy of the provided array of values.
143      * @param newValue Double[]; the array of values to copy to this.value
144      */
145     private void copyValue(final Double[] newValue)
146     {
147         // Make a deep copy
148         this.value = new Double[newValue.length];
149         for (int i = 0; i < newValue.length; i++)
150         {
151             this.value[i] = newValue[i];
152         }
153     }
154 
155     /**
156      * Verify proposed values and make a deep copy.
157      * @param newValue Double[]; the proposed values
158      */
159     private void updateValue(final Double[] newValue) throws PropertyException
160     {
161         verifyProposedValues(newValue);
162         copyValue(newValue);
163     }
164 
165     /**
166      * Return the names of the elements of this ProbabilityDistributionProperty.
167      * @return String[]; the names of the elements of this ProbabilityDistributionProperty
168      */
169     public final String[] getElementNames()
170     {
171         return this.names.clone();
172     }
173 
174     /** {@inheritDoc} */
175     @Override
176     public final boolean isReadOnly()
177     {
178         return this.readOnly;
179     }
180 
181 }