io.yields.math.framework.kpi.ExplorerJsonExporter.java Source code

Java tutorial

Introduction

Here is the source code for io.yields.math.framework.kpi.ExplorerJsonExporter.java

Source

/*
 * 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();
    }

}