1 package org.opentrafficsim.simulationengine.properties;
2
3
4
5
6
7
8
9
10
11
12
13 public class ProbabilityDistributionProperty extends AbstractProperty<Double[]>
14 {
15
16 private Double[] value;
17
18
19 private String[] names;
20
21
22 private String shortName;
23
24
25 private String description;
26
27
28 private final Boolean readOnly;
29
30
31
32
33
34
35
36
37
38
39
40
41 public ProbabilityDistributionProperty(final String shortName, final String description, final String[] elementNames,
42 final Double[] initialValue, final boolean readOnly, final int displayPriority) throws PropertyException
43 {
44 super(displayPriority);
45 this.shortName = shortName;
46 this.description = description;
47 this.names = new String[elementNames.length];
48 for (int i = 0; i < elementNames.length; i++)
49 {
50 this.names[i] = elementNames[i];
51 }
52 verifyProposedValues(initialValue);
53 copyValue(initialValue);
54 this.readOnly = readOnly;
55 }
56
57
58
59
60
61
62
63 private void verifyProposedValues(final Double[] values) throws PropertyException
64 {
65 if (values.length < 1)
66 {
67 throw new PropertyException("Array of probability values may not be empty");
68 }
69 double sum = 0.0;
70 for (double v : values)
71 {
72 if (v < 0.0 || v > 1.0)
73 {
74 throw new PropertyException("Probability value " + v + " is invalid (valid range is 0.0..1.0)");
75 }
76 sum += v;
77 }
78 double maximumError = Math.ulp(1.0) * values.length;
79 if (sum < 1.0 - maximumError || sum > 1.0 + maximumError)
80 {
81 throw new PropertyException("Probabilities do not add up to 1.0 (actual sum is " + sum + ")");
82 }
83
84 }
85
86
87 @Override
88 public final Double[] getValue()
89 {
90
91
92 return this.value.clone();
93 }
94
95
96
97
98
99
100 final Double getValue(final int index)
101 {
102 return this.value[index];
103 }
104
105
106
107
108
109
110 final String getElementName(final int index)
111 {
112 return this.names[index];
113 }
114
115
116 @Override
117 public final String getShortName()
118 {
119 return this.shortName;
120 }
121
122
123 @Override
124 public final String getDescription()
125 {
126 return this.description;
127 }
128
129
130 @Override
131 public final void setValue(final Double[] newValue) throws PropertyException
132 {
133 if (this.readOnly)
134 {
135 throw new PropertyException("This property is read-only");
136 }
137 updateValue(newValue);
138 }
139
140
141
142
143
144 private void copyValue(final Double[] newValue)
145 {
146
147 this.value = new Double[newValue.length];
148 for (int i = 0; i < newValue.length; i++)
149 {
150 this.value[i] = newValue[i];
151 }
152 }
153
154
155
156
157
158
159
160 private void updateValue(final Double[] newValue) throws PropertyException
161 {
162 verifyProposedValues(newValue);
163 copyValue(newValue);
164 }
165
166
167
168
169
170 public final String[] getElementNames()
171 {
172 return this.names.clone();
173 }
174
175
176 @Override
177 public final boolean isReadOnly()
178 {
179 return this.readOnly;
180 }
181
182
183 @Override
184 public final String htmlStateDescription()
185 {
186 StringBuilder result = new StringBuilder();
187 result.append("<table>");
188 result.append("<tr><th>" + getShortName() + "</th></tr>\n");
189 for (int i = 0; i < this.names.length; i++)
190 {
191 result.append("<tr><td>" + this.names[i] + ": " + String.format("%.3f", this.value[i]) + "</td></tr>\n");
192 }
193 result.append("</table>\n");
194 return result.toString();
195 }
196
197
198 @Override
199 public AbstractProperty<Double[]> deepCopy()
200 {
201 System.out.println("copying probabilitydistribution " + this.shortName + ", " + this.getValue(0));
202 try
203 {
204 return new ProbabilityDistributionProperty(this.shortName, this.description, this.names, this.value,
205 this.readOnly, getDisplayPriority());
206 }
207 catch (PropertyException exception)
208 {
209 throw new Error("Cannot happen (the current values should ALWAYS be suitable for constructing a new "
210 + "ProbabilityDistributionProperty)");
211 }
212 }
213
214 }