/* * Java Genetic Algorithm Library (@__identifier__@). * Copyright (c) @__year__@ Franz Wilhelmstötter * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Author: * Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at) */ package org.jenetics.tool.trial; import static java.io.File.createTempFile; import static java.lang.String.format; import static java.nio.file.Files.deleteIfExists; import static java.nio.file.Files.move; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static java.util.Objects.requireNonNull; import static org.jenetics.internal.util.jaxb.marshal; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UncheckedIOException; import java.nio.file.Path; import java.util.Optional; import java.util.function.Function; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; import javax.xml.bind.annotation.adapters.XmlAdapter; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; /** * Represents an function testing measurement environment. * * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a> * @version 3.4 * @since 3.4 */ @XmlJavaTypeAdapter(TrialMeter.Model.Adapter.class) public final class TrialMeter<T> { private final String _name; private final String _description; private final Env _env; private final Params<T> _params; private final DataSet _dataSet; private TrialMeter( final String name, final String description, final Env env, final Params<T> params, final DataSet dataSet ) { _name = requireNonNull(name); _description = description; _env = requireNonNull(env); _params = requireNonNull(params); _dataSet = requireNonNull(dataSet); } public String getName() { return _name; } /** * Return the optional description string. * * @return the optional description string */ public Optional<String> getDescription() { return Optional.ofNullable(_description); } /** * The trial meter environment information. * * @return the trial meter environment information */ public Env getEnv() { return _env; } /** * Return the testing parameters. * * @return the testing parameters */ public Params<T> getParams() { return _params; } /** * Return the current trail {@link DataSet}. * * @return the current trail data set */ public DataSet getDataSet() { return _dataSet; } /** * Return the test data with the given name * * @param name the data name * @return the test {@link Data} with the given name * @throws NullPointerException if the given {@code name} is {@code null} */ public Data getData(final String name) { return _dataSet.get(name); } /** * Return the number of test data results. * * @return the number of test data results. */ public int dataSize() { return _dataSet.dataSize(); } /** * Calculates the test values for all parameters. The length of the * resulting {@code double[]} array must be {@link #dataSize()}. * * @param function the test function */ public void sample(final Function<T, double[]> function) { _params.values() .subSeq(_dataSet.nextParamIndex()) .forEach(p -> _dataSet.add(function.apply(p))); } @Override public String toString() { return format( "TrialMeter[sample=%d, param=%d]", dataSize(), _dataSet.nextParamIndex() ); } /** * Writes the current {@code TrialMeter} object (the calculated samples + * the parameters) to the given output stream. * * @param out the output stream where to write the trial meter * @throws UncheckedIOException if the marshalling fails */ public void write(final OutputStream out) { try { final Marshaller marshaller = jaxb.context().createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(marshal(this), out); } catch (Exception e) { throw new UncheckedIOException(new IOException(e)); } } /** * Writes the current {@code TrialMeter} object (the calculated samples + * the parameters) to the given path. * * @param path the output path * @throws UncheckedIOException if the marshalling fails */ public void write(final Path path) { try { final File tempFile = createTempFile("__trial_meter__", ".xml"); try { try (OutputStream out = new FileOutputStream(tempFile)) { write(out); } move(tempFile.toPath(), path, REPLACE_EXISTING); } finally { deleteIfExists(tempFile.toPath()); } } catch (IOException e) { throw new UncheckedIOException(e); } } /** * Return a new trial measure environment. * * @param name the trial meter name * @param description the trial meter description, maybe {@code null} * @param params the parameters which are tested by this trial meter * @param dataSetNames the names of the calculated data sets * @param <T> the parameter type * @return a new trial measure environment */ public static <T> TrialMeter<T> of( final String name, final String description, final Params<T> params, final String... dataSetNames ) { return new TrialMeter<T>( name, description, Env.of(), params, DataSet.of(params.size(), dataSetNames) ); } /** * Return a new trial measure environment. * * @param name the trial meter name * @param description the trial meter description, maybe {@code null} * @param env the environment information * @param params the parameters which are tested by this trial meter * @param dataSetNames the names of the calculated data sets * @param <T> the parameter type * @return a new trial measure environment */ public static <T> TrialMeter<T> of( final String name, final String description, final Env env, final Params<T> params, final String... dataSetNames ) { return new TrialMeter<T>( name, description, env, params, DataSet.of(params.size(), dataSetNames) ); } /** * Read existing {@code TrialMeter} (intermediate) results from the given * input stream. * * @param in the {@link InputStream} to read from * @param <T> the parameter type * @throws UncheckedIOException if reading the {@code TrialMeter} fails * @return the {@code TrialMeter} object read from the input stream */ @SuppressWarnings("unchecked") public static <T> TrialMeter<T> read(final InputStream in) { try { final Unmarshaller unmarshaller = jaxb.context().createUnmarshaller(); return (TrialMeter<T>)Model.ADAPTER .unmarshal((Model)unmarshaller.unmarshal(in)); } catch (Exception e) { throw new UncheckedIOException(new IOException(e)); } } /** * Read existing {@code TrialMeter} (intermediate) results from the given * path. * * @param path the path the {@code TrialMeter} is read * @param <T> the parameter type * @throws UncheckedIOException if reading the {@code TrialMeter} fails * @return the {@code TrialMeter} object read from the input stream */ public static <T> TrialMeter<T> read(final Path path) { try (InputStream in = new FileInputStream(path.toFile())) { return read(in); } catch (IOException e) { throw new UncheckedIOException(e); } } /* ************************************************************************* * JAXB object serialization * ************************************************************************/ @XmlRootElement(name = "measurement") @XmlType(name = "org.jenetics.tool.trial.TrialMeter") @XmlAccessorType(XmlAccessType.FIELD) @SuppressWarnings({"unchecked", "rawtypes"}) static final class Model { @XmlAttribute public String name; @XmlAttribute public String description; @XmlElement(name = "environment", required = true, nillable = false) public Env env; @XmlElement(name = "params", required = true, nillable = false) public Params params; @XmlElement(name = "data-set", required = true, nillable = false) public DataSet dataSet; public static final class Adapter extends XmlAdapter<Model, TrialMeter> { @Override public Model marshal(final TrialMeter data) { final Model model = new Model(); model.name = data._name; model.description = data._description; model.env = data._env; model.params = data.getParams(); model.dataSet = data._dataSet; return model; } @Override public TrialMeter unmarshal(final Model model) { return new TrialMeter( model.name, model.description, model.env, model.params, model.dataSet ); } } static final Adapter ADAPTER = new Adapter(); } }