TrialMeter.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-3.7.0).
003  * Copyright (c) 2007-2016 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at)
019  */
020 package org.jenetics.tool.trial;
021 
022 import static java.io.File.createTempFile;
023 import static java.lang.String.format;
024 import static java.nio.file.Files.deleteIfExists;
025 import static java.nio.file.Files.move;
026 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
027 import static java.util.Objects.requireNonNull;
028 import static org.jenetics.internal.util.jaxb.marshal;
029 
030 import java.io.File;
031 import java.io.FileInputStream;
032 import java.io.FileOutputStream;
033 import java.io.IOException;
034 import java.io.InputStream;
035 import java.io.OutputStream;
036 import java.io.UncheckedIOException;
037 import java.nio.file.Path;
038 import java.util.Optional;
039 import java.util.function.Function;
040 
041 import javax.xml.bind.Marshaller;
042 import javax.xml.bind.Unmarshaller;
043 import javax.xml.bind.annotation.XmlAccessType;
044 import javax.xml.bind.annotation.XmlAccessorType;
045 import javax.xml.bind.annotation.XmlAttribute;
046 import javax.xml.bind.annotation.XmlElement;
047 import javax.xml.bind.annotation.XmlRootElement;
048 import javax.xml.bind.annotation.XmlType;
049 import javax.xml.bind.annotation.adapters.XmlAdapter;
050 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
051 
052 /**
053  * Represents an function testing measurement environment.
054  *
055  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
056  @version 3.4
057  @since 3.4
058  */
059 @XmlJavaTypeAdapter(TrialMeter.Model.Adapter.class)
060 public final class TrialMeter<T> {
061 
062     private final String _name;
063     private final String _description;
064     private final Env _env;
065 
066     private final Params<T> _params;
067     private final DataSet _dataSet;
068 
069     private TrialMeter(
070         final String name,
071         final String description,
072         final Env env,
073         final Params<T> params,
074         final DataSet dataSet
075     ) {
076         _name = requireNonNull(name);
077         _description = description;
078         _env = requireNonNull(env);
079         _params = requireNonNull(params);
080         _dataSet = requireNonNull(dataSet);
081     }
082 
083     public String getName() {
084         return _name;
085     }
086 
087     /**
088      * Return the optional description string.
089      *
090      @return the optional description string
091      */
092     public Optional<String> getDescription() {
093         return Optional.ofNullable(_description);
094     }
095 
096     /**
097      * The trial meter environment information.
098      *
099      @return the trial meter environment information
100      */
101     public Env getEnv() {
102         return _env;
103     }
104 
105     /**
106      * Return the testing parameters.
107      *
108      @return the testing parameters
109      */
110     public Params<T> getParams() {
111         return _params;
112     }
113 
114     /**
115      * Return the current trail {@link DataSet}.
116      *
117      @return the current trail data set
118      */
119     public DataSet getDataSet() {
120         return _dataSet;
121     }
122 
123     /**
124      * Return the test data with the given name
125      *
126      @param name the data name
127      @return the test {@link Data} with the given name
128      @throws NullPointerException if the given {@code name} is {@code null}
129      */
130     public Data getData(final String name) {
131         return _dataSet.get(name);
132     }
133 
134     /**
135      * Return the number of test data results.
136      *
137      @return the number of test data results.
138      */
139     public int dataSize() {
140         return _dataSet.dataSize();
141     }
142 
143     /**
144      * Calculates the test values for all parameters. The length of the
145      * resulting {@code double[]} array must be {@link #dataSize()}.
146      *
147      @param function the test function
148      */
149     public void sample(final Function<T, double[]> function) {
150         _params.values()
151             .subSeq(_dataSet.nextParamIndex())
152             .forEach(p -> _dataSet.add(function.apply(p)));
153     }
154 
155     @Override
156     public String toString() {
157         return format(
158             "TrialMeter[sample=%d, param=%d]",
159             dataSize(), _dataSet.nextParamIndex()
160         );
161     }
162 
163     /**
164      * Writes the current {@code TrialMeter} object (the calculated samples +
165      * the parameters) to the given output stream.
166      *
167      @param out the output stream where to write the trial meter
168      @throws UncheckedIOException if the marshalling fails
169      */
170     public void write(final OutputStream out) {
171         try {
172             final Marshaller marshaller = jaxb.context().createMarshaller();
173             marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
174             marshaller.marshal(marshal(this), out);
175         catch (Exception e) {
176             throw new UncheckedIOException(new IOException(e));
177         }
178     }
179 
180     /**
181      * Writes the current {@code TrialMeter} object (the calculated samples +
182      * the parameters) to the given path.
183      *
184      @param path the output path
185      @throws UncheckedIOException if the marshalling fails
186      */
187     public void write(final Path path) {
188         try {
189             final File tempFile = createTempFile("__trial_meter__"".xml");
190             try {
191                 try (OutputStream out = new FileOutputStream(tempFile)) {
192                     write(out);
193                 }
194 
195                 move(tempFile.toPath(), path, REPLACE_EXISTING);
196             finally {
197                 deleteIfExists(tempFile.toPath());
198             }
199         catch (IOException e) {
200             throw new UncheckedIOException(e);
201         }
202     }
203 
204     /**
205      * Return a new trial measure environment.
206      *
207      @param name the trial meter name
208      @param description the trial meter description, maybe {@code null}
209      @param params the parameters which are tested by this trial meter
210      @param dataSetNames the names of the calculated data sets
211      @param <T> the parameter type
212      @return a new trial measure environment
213      */
214     public static <T> TrialMeter<T> of(
215         final String name,
216         final String description,
217         final Params<T> params,
218         final String... dataSetNames
219     ) {
220         return new TrialMeter<T>(
221             name,
222             description,
223             Env.of(),
224             params,
225             DataSet.of(params.size(), dataSetNames)
226         );
227     }
228 
229     /**
230      * Return a new trial measure environment.
231      *
232      @param name the trial meter name
233      @param description the trial meter description, maybe {@code null}
234      @param env the environment information
235      @param params the parameters which are tested by this trial meter
236      @param dataSetNames the names of the calculated data sets
237      @param <T> the parameter type
238      @return a new trial measure environment
239      */
240     public static <T> TrialMeter<T> of(
241         final String name,
242         final String description,
243         final Env env,
244         final Params<T> params,
245         final String... dataSetNames
246     ) {
247         return new TrialMeter<T>(
248             name,
249             description,
250             env,
251             params,
252             DataSet.of(params.size(), dataSetNames)
253         );
254     }
255 
256     /**
257      * Read existing {@code TrialMeter} (intermediate) results from the given
258      * input stream.
259      *
260      @param in the {@link InputStream} to read from
261      @param <T> the parameter type
262      @throws UncheckedIOException if reading the {@code TrialMeter} fails
263      @return the {@code TrialMeter} object read from the input stream
264      */
265     @SuppressWarnings("unchecked")
266     public static <T> TrialMeter<T> read(final InputStream in) {
267         try {
268             final Unmarshaller unmarshaller = jaxb.context().createUnmarshaller();
269             return (TrialMeter<T>)Model.ADAPTER
270                 .unmarshal((Model)unmarshaller.unmarshal(in));
271         catch (Exception e) {
272             throw new UncheckedIOException(new IOException(e));
273         }
274     }
275 
276     /**
277      * Read existing {@code TrialMeter} (intermediate) results from the given
278      * path.
279      *
280      @param path the path the {@code TrialMeter} is read
281      @param <T> the parameter type
282      @throws UncheckedIOException if reading the {@code TrialMeter} fails
283      @return the {@code TrialMeter} object read from the input stream
284      */
285     public static <T> TrialMeter<T> read(final Path path) {
286         try (InputStream in = new FileInputStream(path.toFile())) {
287             return read(in);
288         catch (IOException e) {
289             throw new UncheckedIOException(e);
290         }
291     }
292 
293 
294     /* *************************************************************************
295      *  JAXB object serialization
296      * ************************************************************************/
297 
298     @XmlRootElement(name = "measurement")
299     @XmlType(name = "org.jenetics.tool.trial.TrialMeter")
300     @XmlAccessorType(XmlAccessType.FIELD)
301     @SuppressWarnings({"unchecked""rawtypes"})
302     static final class Model {
303 
304         @XmlAttribute
305         public String name;
306 
307         @XmlAttribute
308         public String description;
309 
310         @XmlElement(name = "environment", required = true, nillable = false)
311         public Env env;
312 
313         @XmlElement(name = "params", required = true, nillable = false)
314         public Params params;
315 
316         @XmlElement(name = "data-set", required = true, nillable = false)
317         public DataSet dataSet;
318 
319         public static final class Adapter
320             extends XmlAdapter<Model, TrialMeter>
321         {
322             @Override
323             public Model marshal(final TrialMeter data) {
324                 final Model model = new Model();
325                 model.name = data._name;
326                 model.description = data._description;
327                 model.env = data._env;
328                 model.params = data.getParams();
329                 model.dataSet = data._dataSet;
330                 return model;
331             }
332 
333             @Override
334             public TrialMeter unmarshal(final Model model) {
335                 return new TrialMeter(
336                     model.name,
337                     model.description,
338                     model.env,
339                     model.params,
340                     model.dataSet
341                 );
342             }
343         }
344 
345         static final Adapter ADAPTER = new Adapter();
346     }
347 
348 }