Data.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.lang.String.format;
023 import static java.util.Collections.singletonList;
024 import static java.util.Objects.requireNonNull;
025 import static org.jenetics.tool.trial.SampleSummary.toSampleSummary;
026 
027 import java.io.Serializable;
028 import java.util.ArrayList;
029 import java.util.Arrays;
030 import java.util.List;
031 import java.util.stream.Collectors;
032 
033 import javax.xml.bind.annotation.XmlAccessType;
034 import javax.xml.bind.annotation.XmlAccessorType;
035 import javax.xml.bind.annotation.XmlAttribute;
036 import javax.xml.bind.annotation.XmlElement;
037 import javax.xml.bind.annotation.XmlRootElement;
038 import javax.xml.bind.annotation.XmlType;
039 import javax.xml.bind.annotation.adapters.XmlAdapter;
040 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
041 
042 /**
043  * This class collects a list of {@link Sample} result objects into on
044  * {@code Data} object.
045  *
046  @see Sample
047  *
048  @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a>
049  @version 3.4
050  @since 3.4
051  */
052 @XmlJavaTypeAdapter(Data.Model.Adapter.class)
053 public final class Data implements Serializable {
054 
055     private static final long serialVersionUID = 1L;
056 
057     private final String _name;
058     private final List<Sample> _samples = new ArrayList<>();
059 
060     private Data(final String name, final List<Sample> samples) {
061         if (samples.isEmpty()) {
062             throw new IllegalArgumentException("Sample list must not be empty.");
063         }
064         if (!samples.stream().allMatch(s -> samples.get(0).size() == s.size())) {
065             throw new IllegalArgumentException(
066                 "All sample object must have the same size."
067             );
068         }
069 
070         _name = requireNonNull(name);
071         _samples.addAll(samples);
072     }
073 
074     /**
075      * Return the name of the sample {@code Data} collections.
076      *
077      @return the name of the sample {@code Data} collections
078      */
079     public String getName() {
080         return _name;
081     }
082 
083     /**
084      * The number of {@link Sample} objects this {@code Data} class contains.
085      *
086      @return the size of the data object
087      */
088     public int dataSize() {
089         return _samples.size();
090     }
091 
092     /**
093      * The number of values of an {@link Sample} object.
094      *
095      @see Sample#size()
096      *
097      @return number of values of an {@link Sample} object
098      */
099     public int sampleSize() {
100         return _samples.get(0).size();
101     }
102 
103     /**
104      * Return the current {@link Sample} object. A newly created object is
105      * returned on demand.
106      *
107      @return the current {@link Sample} object
108      */
109     public Sample currentSample() {
110         Sample sample = _samples.get(_samples.size() 1);
111         if (sample.isFull()) {
112             sample = sample.newSample();
113             _samples.add(sample);
114         }
115 
116         return sample;
117     }
118 
119     /**
120      * Return the index of the next parameter index to calculate.
121      *
122      @return the index of the next parameter index to calculate
123      */
124     public int nextParamIndex() {
125         return currentSample().nextIndex();
126     }
127 
128     /**
129      * Calculate the sample summary of this data object.
130      *
131      @return the sample summary of this data object
132      */
133     public SampleSummary summary() {
134         return _samples.stream()
135             .filter(Sample::isFull)
136             .collect(toSampleSummary(sampleSize()));
137     }
138 
139     @Override
140     public int hashCode() {
141         return (37*_name.hashCode() 17)*_samples.hashCode()*37 17;
142     }
143 
144     @Override
145     public boolean equals(final Object obj) {
146         return obj instanceof Data &&
147             _name.equals(((Data)obj)._name&&
148             _samples.equals(((Data)obj)._samples);
149     }
150 
151     @Override
152     public String toString() {
153         return format("Data[name=%s, size=%d]", _name, dataSize());
154     }
155 
156     /**
157      * Create a new {@code Data} object with the given parameters.
158      *
159      @param name the name of the data object
160      @param samples the sample list of the data object
161      @throws NullPointerException if one of the parameters is {@code null}
162      @return a new {@code Data} object with the given parameters
163      */
164     public static Data of(final String name, final List<Sample> samples) {
165         return new Data(name, samples);
166     }
167 
168     /**
169      * Return a new {@code Data} object with the given name and the given number
170      * of parameters.
171      *
172      @param name the name of the data object
173      @param parameterCount the parameter count of the created samples
174      @throws NullPointerException if the data {@code name} is {@code null}
175      @throws IllegalArgumentException if the given {@code parameterCount} is
176      *         smaller then one
177      @return a new {@code Data} object with the given parameters
178      */
179     public static Data of(final String name, final int parameterCount) {
180         return of(name, singletonList(Sample.of(parameterCount)));
181     }
182 
183 
184     /* *************************************************************************
185      *  JAXB object serialization
186      * ************************************************************************/
187 
188     @XmlRootElement(name = "data")
189     @XmlType(name = "org.jenetics.tool.trial.Data")
190     @XmlAccessorType(XmlAccessType.FIELD)
191     final static class Model {
192 
193         @XmlAttribute
194         public String name;
195 
196         @XmlElement(name = "sample")
197         public List<String> samples;
198 
199         public static final class Adapter extends XmlAdapter<Model, Data> {
200             @Override
201             public Model marshal(final Data data) {
202                 final Model model = new Model();
203                 model.name = data._name;
204                 model.samples = data._samples.stream()
205                     .map(s -> s.stream().mapToObj(Double::toString)
206                                 .collect(Collectors.joining(" ")))
207                     .collect(Collectors.toList());
208                 return model;
209             }
210 
211             @Override
212             public Data unmarshal(final Model model) {
213                 return Data.of(
214                     model.name,
215                     model.samples.stream()
216                         .map(s -> Arrays.stream(s.split("\\s"))
217                             .mapToDouble(Double::parseDouble).toArray())
218                         .map(Sample::of)
219                         .collect(Collectors.toList())
220                 );
221             }
222         }
223 
224     }
225 }