All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cdc.applic.mountability.core.ComputeMountability Maven / Gradle / Ivy

The newest version!
package cdc.applic.mountability.core;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import cdc.applic.dictionaries.AssertionStrategy;
import cdc.applic.dictionaries.Dictionary;
import cdc.applic.dictionaries.NamingConvention;
import cdc.applic.dictionaries.ReserveStrategy;
import cdc.applic.dictionaries.handles.DictionaryHandle;
import cdc.applic.dictionaries.impl.RepositoryImpl;
import cdc.applic.dictionaries.impl.io.RepositoryIo;
import cdc.applic.expressions.Expression;
import cdc.applic.expressions.Formatting;
import cdc.applic.expressions.Spacing;
import cdc.applic.expressions.SymbolType;
import cdc.applic.expressions.checks.ApplicIssue;
import cdc.applic.mountability.MountabilityComputer;
import cdc.applic.mountability.MountabilityComputerFeatures;
import cdc.applic.mountability.MountabilityDataChecker;
import cdc.applic.mountability.handlers.MountabilityHandler;
import cdc.applic.mountability.impl.Data;
import cdc.applic.mountability.impl.UsePoint;
import cdc.applic.mountability.impl.Variant;
import cdc.applic.mountability.impl.io.DataXml;
import cdc.applic.proofs.ProverFeatures;
import cdc.applic.publication.ExpressionFormatter;
import cdc.applic.publication.core.formatters.FormattersCatalog;
import cdc.applic.publication.core.formatters.InfixFormatter;
import cdc.applic.publication.core.formatters.io.FormattersCatalogXml;
import cdc.applic.simplification.SimplifierFeatures;
import cdc.applic.simplification.SimplifierFeatures.Hint;
import cdc.io.xml.XmlWriter;
import cdc.issues.IssuesCollector;
import cdc.issues.io.IssuesIoFactoryFeatures;
import cdc.issues.io.IssuesWriter;
import cdc.issues.io.OutSettings;
import cdc.util.cli.AbstractMainSupport;
import cdc.util.cli.FeatureMask;
import cdc.util.cli.MainResult;
import cdc.util.cli.OptionEnum;
import cdc.util.events.ProgressController;
import cdc.util.events.ProgressEvent;
import cdc.util.lang.FailureReaction;
import cdc.util.time.Chronometer;

/**
 * Main program used to load mountability data and compute mountability.
 */
public final class ComputeMountability {
    private static final Logger LOGGER = LogManager.getLogger(ComputeMountability.class);
    private final MainArgs margs;
    private final ProgressController controller = new ProgressController() {
        @Override
        public void onProgress(ProgressEvent event) {
            LOGGER.info(event);
        }

        @Override
        public boolean isCancelled() {
            return false;
        }
    };

    public static class MainArgs {
        public enum Feature implements OptionEnum {
            SIMPLIFY("simplify", "Simplifies mountability expressions (default)."),
            NO_SIMPLIFY("no-simplify", "Does not simplify mountability expressions."),
            KEEP_GOING("keep-going", "Keep going even if an error is detected."),
            NO_KEEP_GOING("no-keep-going", "Interrupt processing when an error is detected (default)."),
            INCLUDE_ASSERTION("include-assertions", "Includes assertions in simplification of expressions."),
            EXCLUDE_ASSERTION("exclude-assertions", "Excludes assertions in simplification of expressions (default)."),
            NO_RESERVES("no-reserves", "Ignores reserves in simplification of expressions (default)."),
            ALL_POSSIBLE_RESERVES("all-possible-reserves",
                                  "Takes into account all possible reserves in simplification of expressions."),
            USER_DEFINED_RESERVES("user-defined-reserves",
                                  "Takes into account user defined reserves in simplifications of expressions."),
            SHORT_SYMBOLS("short-symbols", "Generates mountability using short symbols (&, |, <:, ...)."),
            LONG_SYMBOLS("long-symbols", "Generates mountability expressions using long symbols (and, or, in, ...) (default)."),
            MATH_SYMBOLS("math-symbols", "Generates mountability expressions using math symbols (\u2227, \u2228, \u2208, ...)."),
            PRETTY("pretty", "Pretty prints generated file (default)."),
            NO_PRETTY("no-pretty", "Does not pretty print generated file.");

            private final String name;
            private final String description;

            private Feature(String name,
                            String description) {
                this.name = name;
                this.description = description;
            }

            @Override
            public final String getName() {
                return name;
            }

            @Override
            public final String getDescription() {
                return description;
            }
        }

        public File repositoryFile;
        public File formattersCatalogFile;
        public File mountabilityInputFile;
        public File mountabilityOutputFile;
        public String dictionaryPath;
        public String namingConvention;
        public File issuesFile;

        protected final FeatureMask features = new FeatureMask<>();

        public void setEnabled(Feature feature,
                               boolean enabled) {
            features.setEnabled(feature, enabled);
        }

        public boolean isEnabled(Feature feature) {
            return features.isEnabled(feature);
        }

        public AssertionStrategy getAssertionStrategy() {
            if (isEnabled(MainArgs.Feature.INCLUDE_ASSERTION)) {
                return AssertionStrategy.INCLUDE_ASSERTIONS;
            } else {
                return AssertionStrategy.EXCLUDE_ASSERTIONS;
            }
        }

        public ReserveStrategy getReserveStrategy() {
            if (isEnabled(MainArgs.Feature.ALL_POSSIBLE_RESERVES)) {
                return ReserveStrategy.ALL_POSSIBLE_RESERVES;
            } else if (isEnabled(MainArgs.Feature.USER_DEFINED_RESERVES)) {
                return ReserveStrategy.USER_DEFINED_RESERVES;
            } else {
                return ReserveStrategy.NO_RESERVES;
            }
        }

        public MountabilityComputerFeatures.Hint[] getHints() {
            final List hints = new ArrayList<>();
            if (!isEnabled(Feature.NO_SIMPLIFY)) {
                hints.add(MountabilityComputerFeatures.Hint.SIMPLIFY);
            }
            if (isEnabled(Feature.KEEP_GOING)) {
                hints.add(MountabilityComputerFeatures.Hint.KEEP_GOING);
            }
            return hints.toArray(new MountabilityComputerFeatures.Hint[hints.size()]);
        }

        public boolean prettyPrints() {
            return !isEnabled(Feature.NO_PRETTY);
        }

        public SymbolType getSymbolType() {
            if (isEnabled(Feature.MATH_SYMBOLS)) {
                return SymbolType.MATH;
            } else if (isEnabled(Feature.SHORT_SYMBOLS)) {
                return SymbolType.SHORT;
            } else {
                return SymbolType.LONG;
            }
        }

        public Spacing getSpacing() {
            if (getSymbolType() == SymbolType.LONG) {
                return Spacing.WIDE;
            } else {
                return Spacing.NARROW;
            }
        }

        public Formatting getFormatting() {
            return Formatting.builder()
                             .symbolType(getSymbolType())
                             .spacing(getSpacing())
                             .build();
        }
    }

    private ComputeMountability(MainArgs margs) {
        this.margs = margs;
    }

    private void execute() throws IOException {
        final Chronometer chrono = new Chronometer();
        // Load Repository
        LOGGER.info("Load repository from {}", margs.repositoryFile);
        chrono.start();

        final RepositoryImpl repository = RepositoryIo.load(margs.repositoryFile, FailureReaction.FAIL);
        chrono.suspend();
        LOGGER.info("Done ({})", chrono);

        final Dictionary dictionary;
        if (margs.dictionaryPath == null) {
            dictionary = repository.getRegistries().get(0);
        } else {
            dictionary = repository.getDictionary(margs.dictionaryPath);
        }
        final DictionaryHandle handle = new DictionaryHandle(dictionary);

        final FormattersCatalog catalog;
        // Load formatters catalog
        if (margs.formattersCatalogFile != null) {
            LOGGER.info("Load formatters catalog from {}", margs.formattersCatalogFile);
            chrono.start();
            final FormattersCatalogXml.StAXLoader catalogLoader = new FormattersCatalogXml.StAXLoader(FailureReaction.WARN);
            catalog = catalogLoader.load(margs.formattersCatalogFile);
            chrono.suspend();
            LOGGER.info("Done ({})", chrono);
        } else {
            catalog = null;
        }

        // Load data set
        LOGGER.info("Load mountability data from {}", margs.mountabilityInputFile);
        chrono.start();
        final DataXml.StAXLoader dataLoader = new DataXml.StAXLoader(FailureReaction.WARN, false);
        final Data data = dataLoader.load(margs.mountabilityInputFile);
        chrono.suspend();
        LOGGER.info("Done ({})", chrono);

        LOGGER.info("Check mountability data");
        chrono.start();
        final MountabilityDataChecker checker = new MountabilityDataCheckerImpl<>(handle);
        final IssuesCollector collector = new IssuesCollector<>();
        checker.check(data, collector);
        chrono.suspend();
        LOGGER.info("Done ({})", chrono);

        if (margs.issuesFile != null) {
            LOGGER.info("Save mountability data issues to {}", margs.issuesFile);
            chrono.start();
            IssuesWriter.save(collector.getIssues(),
                              OutSettings.builder()
                                         .hint(OutSettings.Hint.NO_ANSWERS)
                                         .hint(OutSettings.Hint.AUTO_LOCATIONS)
                                         .build(),
                              margs.issuesFile,
                              ProgressController.VOID,
                              IssuesIoFactoryFeatures.UTC_FASTEST);
            chrono.suspend();
            LOGGER.info("Saved mountability data issues to {} ({})", margs.issuesFile, chrono);
        } else {
            LOGGER.warn("Found {}  issues", collector.getIssues().size());
            for (final ApplicIssue issue : collector.getIssues()) {
                LOGGER.warn("   {}", issue);
            }
        }

        // ProverFeatures
        final ProverFeatures proverFeatures =
                ProverFeatures.builder()
                              .assertionStrategy(margs.getAssertionStrategy())
                              .reserveStrategy(margs.getReserveStrategy())
                              .build();

        // SimpliferFeatures
        final SimplifierFeatures simplifierFeatures =
                SimplifierFeatures.builder()
                                  .proverFeatures(proverFeatures)
                                  .hints(Hint.CONVERT_TO_DNF,
                                         Hint.NORMALIZE_BOOLEAN_PROPERTIES,
                                         Hint.REMOVE_ALWAYS_TRUE_OR_FALSE,
                                         Hint.REMOVE_NEGATION,
                                         Hint.REMOVE_REDUNDANT_SIBLINGS)
                                  .noLimits()
                                  .namingConvention(dictionary.getRegistry().getNamingConvention(margs.namingConvention))
                                  .build();

        final MountabilityComputer computer =
                new MountabilityComputerImpl<>(handle, simplifierFeatures);

        final Handler handler = new Handler();

        final MountabilityComputerFeatures features =
                MountabilityComputerFeatures.builder()
                                            .hints(margs.getHints())
                                            .build();

        LOGGER.info("Compute mountability");
        chrono.start();
        computer.compute(data, handler, features, controller);
        chrono.suspend();
        LOGGER.info("Done ({})", chrono);

        // Save computed data set
        LOGGER.info("Save data to {}", margs.mountabilityOutputFile);
        chrono.start();
        try (final XmlWriter writer = new XmlWriter(margs.mountabilityOutputFile)) {
            if (margs.prettyPrints()) {
                writer.setEnabled(XmlWriter.Feature.PRETTY_PRINT);
            }
            writer.setIndentString("  ");
            final DataXml.Printer dataPrinter = new DataXml.Printer();
            dataPrinter.setFormatting(margs.getFormatting());
            if (catalog != null) {
                final ExpressionFormatter formatter = new InfixFormatter(dictionary.getRegistry(), catalog);
                dataPrinter.setFormatter(formatter);
            }

            dataPrinter.write(writer, handler.data);
        }
        chrono.suspend();
        LOGGER.info("Done ({})", chrono);
    }

    public static void execute(MainArgs margs) throws IOException {
        final ComputeMountability instance = new ComputeMountability(margs);
        instance.execute();
    }

    public static MainResult exec(String... args) {
        final MainSupport support = new MainSupport();
        support.main(args);
        return support.getResult();
    }

    public static void main(String... args) {
        final int code = exec(args).getCode();
        System.exit(code);
    }

    private static class Handler implements MountabilityHandler {
        public final Data data = new Data();
        private UsePoint currentUsePoint;

        public Handler() {
            super();
        }

        @Override
        public void processBeginUsePoints() {
            LOGGER.debug("processBeginUsePoints()");
        }

        @Override
        public void processEndUsePoints() {
            LOGGER.debug("processEndUsePoints()");
        }

        @Override
        public void processBeginUsePoint(UsePoint usePoint) {
            LOGGER.debug("processBeginUsePoint({})", usePoint);
            currentUsePoint = new UsePoint(usePoint.getId());
        }

        @Override
        public void processEndUsePoint(UsePoint usePoint) {
            LOGGER.debug("processEndUsePoint({})", usePoint);
            data.addUsePoint(currentUsePoint);
        }

        @Override
        public void processVariantMountability(UsePoint usePoint,
                                               Variant variant,
                                               Expression mountability) {
            LOGGER.debug("processVariantMountability({}, {}, {})", usePoint, variant, mountability);
            currentUsePoint.addVariant(variant.getId(),
                                       variant.getInterchangeability(),
                                       variant.getApplicability(),
                                       mountability);
        }

        @Override
        public void processError(RuntimeException e) {
            LOGGER.error("processError({})", e.getMessage());
        }
    }

    private static class MainSupport extends AbstractMainSupport {
        private static final String REPOSITORY_FILE = "repository";
        private static final String FORMATTERS_CATALOG_FILE = "formatters-catalog";
        private static final String MOUNTABILITY_INPUT_FILE = "input";
        private static final String MOUNTABILITY_OUTPUT_FILE = "output";
        private static final String ISSUES_FILE = "issues";
        private static final String DICTIONARY = "dictionary";
        private static final String NAMING_CONVENTION = "naming-convention";

        public MainSupport() {
            super(ComputeMountability.class, LOGGER);
        }

        @Override
        protected String getVersion() {
            return "2020-07-04";
        }

        @Override
        protected boolean addArgsFileOption(Options options) {
            return true;
        }

        @Override
        protected void addSpecificOptions(Options options) {
            options.addOption(Option.builder()
                                    .longOpt(REPOSITORY_FILE)
                                    .desc("Name of the mandatory input XML, XLS or XLSX repository file.")
                                    .hasArg()
                                    .required()
                                    .build());

            options.addOption(Option.builder()
                                    .longOpt(FORMATTERS_CATALOG_FILE)
                                    .desc("Name of the optional input XML formatters catalog file.")
                                    .hasArg()
                                    .build());

            options.addOption(Option.builder()
                                    .longOpt(MOUNTABILITY_INPUT_FILE)
                                    .desc("Name of the mandatory input XML mountability file.")
                                    .hasArg()
                                    .required()
                                    .build());

            options.addOption(Option.builder()
                                    .longOpt(MOUNTABILITY_OUTPUT_FILE)
                                    .desc("Name of the mandatory output XML mountability file.")
                                    .hasArg()
                                    .required()
                                    .build());

            options.addOption(Option.builder()
                                    .longOpt(ISSUES_FILE)
                                    .desc("Name of the optional output issues file.")
                                    .hasArg()
                                    .build());

            options.addOption(Option.builder()
                                    .longOpt(DICTIONARY)
                                    .desc("Key of the optional dictionary to use. If none is passed, the first registry is used.\n"
                                            + "It has the form 'name(/name)*'.")
                                    .hasArg()
                                    .build());

            options.addOption(Option.builder()
                                    .longOpt(NAMING_CONVENTION)
                                    .desc("Optional naming convention (Defaults to default naming convention).")
                                    .hasArg()
                                    .build());

            addNoArgOptions(options, MainArgs.Feature.class);

            createGroup(options,
                        MainArgs.Feature.PRETTY,
                        MainArgs.Feature.NO_PRETTY);
            createGroup(options,
                        MainArgs.Feature.EXCLUDE_ASSERTION,
                        MainArgs.Feature.INCLUDE_ASSERTION);
            createGroup(options,
                        MainArgs.Feature.NO_RESERVES,
                        MainArgs.Feature.ALL_POSSIBLE_RESERVES,
                        MainArgs.Feature.USER_DEFINED_RESERVES);
            createGroup(options,
                        MainArgs.Feature.SIMPLIFY,
                        MainArgs.Feature.NO_SIMPLIFY);
            createGroup(options,
                        MainArgs.Feature.KEEP_GOING,
                        MainArgs.Feature.NO_KEEP_GOING);
            createGroup(options,
                        MainArgs.Feature.SHORT_SYMBOLS,
                        MainArgs.Feature.LONG_SYMBOLS,
                        MainArgs.Feature.MATH_SYMBOLS);
        }

        @Override
        protected MainArgs analyze(CommandLine cl) throws ParseException {
            final MainArgs margs = new MainArgs();
            margs.repositoryFile = getValueAsResolvedFile(cl, REPOSITORY_FILE, IS_FILE);
            margs.formattersCatalogFile = getValueAsResolvedFile(cl, FORMATTERS_CATALOG_FILE, IS_NULL_OR_FILE);
            margs.mountabilityInputFile = getValueAsResolvedFile(cl, MOUNTABILITY_INPUT_FILE, IS_FILE);
            margs.mountabilityOutputFile = getValueAsResolvedFile(cl, MOUNTABILITY_OUTPUT_FILE);
            margs.issuesFile = getValueAsResolvedFile(cl, ISSUES_FILE);
            margs.dictionaryPath = getValueAsString(cl, DICTIONARY, null);
            margs.namingConvention = getValueAsString(cl, NAMING_CONVENTION, NamingConvention.DEFAULT_NAME.getNonEscapedLiteral());

            setMask(cl, MainArgs.Feature.class, margs.features::setEnabled);

            return margs;
        }

        @Override
        protected Void execute(MainArgs margs) throws Exception {
            ComputeMountability.execute(margs);
            return null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy