Java tutorial
/* * Copyright 2015 by Yields. * * 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. */ package io.yields.math.framework.kpi; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JSR310Module; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.DoubleSummaryStatistics; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import io.yields.math.framework.Explorer; import io.yields.math.framework.Property; import io.yields.math.framework.Stats; import io.yields.math.framework.executor.PropertyVerification; import io.yields.math.framework.executor.PropertyVerifications; import static java.lang.String.format; import static java.util.stream.Collectors.toList; public class ExplorerJsonExporter implements ExplorerExporter { private static final double EPS = 1.e-6; @Override public void export(Explorer<?> explorer, File destinationFile) { ObjectMapper jsonMapper = getObjectMapper(); try { List<String> variableNames = explorer.all().findFirst().map(propertyVerification -> propertyVerification .getVariables().entrySet().stream().map(Map.Entry::getKey).sorted()).get().collect(toList()); List<Values> variableValues = explorer.all().map( propertyVerifications -> new Values(propertyVerifications.getVariables().entrySet().stream() .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue())))) .collect(Collectors.toList()); StandardResult variables = new StandardResult(buildDefinitions(variableNames, string -> ""), variableValues); PropertyVerifications<?> verifications = explorer.all().findAny() .orElseThrow(IllegalArgumentException::new); List<Definition> propertyDefinitions = buildDefinitions( verifications.getResults().stream().map(PropertyVerification::getName).collect(toList()), name -> verifications.getResults().stream() .filter(verification -> verification.getName().equals(name)) .map(verification -> verification.getProperty().map(Property::getExplanation) .orElse("")) .findAny().orElse("")); List<Values> propertiesValues = explorer.all() .map(propertyVerifications -> toValues(propertyVerifications)).collect(toList()); StandardResult properties = new StandardResult(propertyDefinitions, propertiesValues); Optional<Stats> statsTemplate = explorer.getStats().stream().findAny(); List<Definition> descriptorDefinitions = buildDefinitions( statsTemplate.map(Stats::getDescriptorNames).orElse(Collections.emptyList()), name -> statsTemplate.map(stats -> stats.getDescriptorExplanation(name)).orElse("")); List<Values> descriptorValues = explorer.getStats().stream().map(stats -> toDescriptorValues(stats)) .collect(Collectors.toList()); StandardResult descriptors = new StandardResult(descriptorDefinitions, descriptorValues); List<StatDefinition> statsDefinitions = buildStatDefinitions(explorer.getStats(), name -> statsTemplate.map(stats -> stats.getStatsExplanation(name)).orElse("")); List<Values> statsValues = explorer.getStats().stream().map(stats -> toStatsValues(stats)) .collect(Collectors.toList()); StatsResult statsDefinition = new StatsResult(statsDefinitions, statsValues); ScoreResult scoreResult = explorer.getScore(); ExplorerResult result = new ExplorerResult(explorer.getMetadata(), variables, statsDefinition, descriptors, properties, scoreResult); jsonMapper.writeValue(destinationFile, result); } catch (IOException ioe) { throw new IllegalStateException( format("Could not write explorer file at %s", destinationFile.getAbsolutePath()), ioe); } } public ExplorerResult retrieve(File file) { try { ObjectMapper jsonMapper = getObjectMapper(); return jsonMapper.readValue(file, ExplorerResult.class); } catch (Exception e) { throw new IllegalArgumentException(format("Could not read explorer file at %s", file.getAbsolutePath()), e); } } private static ObjectMapper getObjectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.enableDefaultTyping(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); mapper.registerModule(new JSR310Module()); return mapper; } private List<Definition> buildDefinitions(Collection<String> representations, Function<String, String> explanationProvider) { Map<String, Definition> roots = new HashMap<>(); for (String representation : representations) { String[] values = representation.split("#"); Definition root = roots.get(values[0]); if (root == null) { root = new Definition(values[0]); roots.put(root.getName(), root); } Definition element = root; for (int i = 1; i < values.length; i++) { element = DefinitionBuilder.addChild(element, new Definition(element, values[i])); } element.setDescription(explanationProvider.apply(representation)); } return new ArrayList<>(roots.values()); } private List<StatDefinition> buildStatDefinitions(List<Stats> stats, Function<String, String> explanationProvider) { Optional<Stats> template = stats.stream().findAny(); Map<String, StatDefinition> roots = new HashMap<>(); if (template.isPresent()) { Stats statsTemplate = template.get(); Map<String, DoubleSummaryStatistics> summaries = statsTemplate.getStatsNames().stream() .collect(Collectors.toMap(Function.identity(), name -> getStats(name, stats))); summaries.keySet().stream().forEach(name -> { String values[] = name.split("#"); double refLevel = statsTemplate.getRefLevel(name); double min = summaries.get(name).getMin(); double max = summaries.get(name).getMax(); if (Math.abs(max - min) < 2 * EPS) { min -= EPS; max += EPS; } if (values.length == 1) { roots.put(name, new StatDefinition(null, name, explanationProvider.apply(name), Math.min(refLevel, min), Math.max(max, refLevel), refLevel)); } else { StatDefinition root = roots.get(values[0]); if (root == null) { root = new StatDefinition(values[0]); roots.put(root.getName(), root); } StatDefinition element = root; for (int i = 1; i < values.length; i++) { element = DefinitionBuilder.addChild(element, new StatDefinition(element, values[i], Math.min(refLevel, min), Math.max(max, refLevel), refLevel)); } element.setDescription(explanationProvider.apply(name)); } }); } return new ArrayList<>(roots.values()); } private <T> Values toValues(PropertyVerifications<T> verifications) { Stream<PropertyVerification<T>> stream = verifications.getResults().stream() .filter(verification -> verification.getProperty().isPresent()); Map<String, Object> map = stream .collect(Collectors.toMap(verification -> verification.getProperty().get().getLabel(), propertyVerification -> propertyVerification.getResult().getCode())); return new Values(map); } private Values toDescriptorValues(Stats stats) { return new Values(stats.getDescriptorNames().stream() .collect(Collectors.toMap(name -> name, name -> stats.getDescriptorAt(name)))); } private Values toStatsValues(Stats stats) { return new Values(stats.getStatsNames().stream() .collect(Collectors.toMap(name -> name, name -> stats.getStats(name)))); } private DoubleSummaryStatistics getStats(String name, List<Stats> values) { return values.stream().map(value -> value.getStats(name)).filter(entry -> entry != null) .mapToDouble(entry -> entry).summaryStatistics(); } }