001package conexp.fx.cli; 002 003/* 004 * #%L 005 * Concept Explorer FX 006 * %% 007 * Copyright (C) 2010 - 2023 Francesco Kriegel 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025import java.io.File; 026import java.util.Set; 027import java.util.concurrent.Executors; 028import java.util.function.Consumer; 029 030import org.apache.commons.cli.CommandLine; 031import org.apache.commons.cli.DefaultParser; 032import org.apache.commons.cli.HelpFormatter; 033import org.apache.commons.cli.Option; 034import org.apache.commons.cli.OptionBuilder; 035import org.apache.commons.cli.Options; 036import org.apache.commons.cli.ParseException; 037 038import conexp.fx.core.algorithm.nextclosures.NextClosures2Bit; 039import conexp.fx.core.collections.Collections3; 040import conexp.fx.core.collections.Pair; 041import conexp.fx.core.context.Concept; 042import conexp.fx.core.context.ConceptLattice; 043import conexp.fx.core.context.Implication; 044import conexp.fx.core.context.MatrixContext; 045import conexp.fx.core.exporter.CXTExporter; 046import conexp.fx.core.importer.CXTImporter; 047import conexp.fx.gui.ConExpFX; 048 049public final class CLI { 050 051 public static void main(final String[] args) throws Exception { 052 new CLI(args); 053 } 054 055 private final CommandLine commandLine; 056 private MatrixContext<String, String> cxt; 057 private Set<Concept<String, String>> concepts; 058 private Set<Implication<String, String>> implications; 059 private ConceptLattice<String, String> lattice; 060 061 private CLI(final String[] args) throws Exception { 062 super(); 063 try { 064 commandLine = new DefaultParser().parse(OPTIONS, args); 065 } catch (ParseException e) { 066 printHelp(); 067 throw new RuntimeException("Unable to parse command line arguments. Please check supplied arguments!", e); 068 } 069 if (!commandLine.getArgList().isEmpty()) { 070 printHelp(); 071 throw new RuntimeException("Unrecognized Arguments: " + commandLine.getArgList()); 072 } 073 execute(); 074 } 075 076 private final void printHelp() { 077 new HelpFormatter().printHelp( 078 120, 079 "java -jar conexp-fx-VERSION-jar-with_dependencies.jar [OPTIONS]", 080 "Available command line options for Concept Explorer FX", 081 OPTIONS, 082 ""); 083 } 084 085 private final void execute() throws Exception { 086 if (commandLine.getOptions().length == 0 || commandLine.hasOption(GUI.getLongOpt())) 087 ConExpFX.main(new String[] {}); 088 else if (commandLine.hasOption(HELP.getLongOpt())) 089 printHelp(); 090 else { 091 final Consumer<Concept<String, String>> c1; 092 final Consumer<Implication<String, String>> c2; 093 final Consumer<String> c3; 094 final Consumer<Double> c4; 095 if (commandLine.hasOption(PRINT_TO_CONSOLE.getLongOpt())) { 096 c1 = System.out::println; 097 c2 = System.out::println; 098 c3 = System.out::println; 099 c4 = System.out::println; 100 } else { 101 c1 = __ -> {}; 102 c2 = __ -> {}; 103 c3 = __ -> {}; 104 c4 = __ -> {}; 105 } 106 if (!commandLine.hasOption(IMPORT_CXT.getLongOpt())) 107 throw new IllegalArgumentException( 108 "Unable to instanciate FCA service without formal context. Please specify a file in Burmeister formatting by adding a command line prefix\r\n\t--importContextFromCXT <path_to_file>"); 109 final File input = new File(commandLine.getOptionValue(IMPORT_CXT.getLongOpt())); 110 cxt = CXTImporter.read(input); 111 if (commandLine.hasOption(CALC_CONCEPTS.getLongOpt()) || commandLine.hasOption(CALC_IMPLICATIONS.getLongOpt()) 112 || commandLine.hasOption(CALC_NEIGHBORHOOD.getLongOpt())) { 113 final Pair<Set<Concept<String, String>>, Set<Implication<String, String>>> result = 114 NextClosures2Bit.bitCompute(cxt, Executors.newWorkStealingPool(), c1, c2, c3, c4, () -> false); 115 concepts = result.first(); 116 implications = result.second(); 117 } 118 if (commandLine.hasOption(CALC_NEIGHBORHOOD.getLongOpt())) { 119// IPred. 120 } 121 if (commandLine.hasOption(WRITE_TO_FILE.getLongOpt())) { 122 final String filename = input.getName().substring(0, input.getName().lastIndexOf(".")); 123 if (concepts != null) 124 Collections3.writeToFile( 125 new File(input.getParentFile(), filename + ".concepts"), 126 concepts, 127 "Formal Concepts of " + input.getAbsolutePath()); 128 if (implications != null) 129 Collections3.writeToFile( 130 new File(input.getParentFile(), filename + ".implications"), 131 implications, 132 "Implications of " + input.getAbsolutePath()); 133 if (lattice != null) 134 CXTExporter.export(lattice, new File(input.getParentFile(), filename + ".lattice")); 135 } 136 } 137 } 138 139// private final void test(final CommandLine commandLine) { 140// final String path = commandLine.getOptionValue(CLI.TEST.getLongOpt()); 141// NextClosuresTest.run(path); 142// TestSuite.main(new String[] {}); 143//// -Xms256m 144//// -Xmx2048m 145//// -Djub.customkey=oracle-1.7.0_45 146//// -Djub.consumers=CONSOLE,H2,XML 147//// -Djub.db.file=benchmarks/.benchmarks 148//// -Djub.xml.file=benchmarks/latest.xml 149// } 150 151 private final Options OPTIONS = new Options(); 152 @SuppressWarnings("static-access") 153 private final Option HELP = OptionBuilder 154 .isRequired(false) 155 .withLongOpt("showHelp") 156 .hasArg(false) 157 .withDescription("shows available command line options and their arguments.") 158 .create("help"); 159 @SuppressWarnings("static-access") 160 private final Option IMPORT_CXT = OptionBuilder 161 .isRequired(false) 162 .withLongOpt("importContextFromCXT") 163 .hasArg(true) 164 .withArgName("file") 165 .withDescription("imports formal context file in Burmeister formatting (*.cxt)") 166 .create("import"); 167 @SuppressWarnings("static-access") 168 private final Option CALC_CONCEPTS = OptionBuilder 169 .isRequired(false) 170 .withLongOpt("calculateConcepts") 171 .hasArg(false) 172 .withDescription("computes all formal concepts") 173 .create("concepts"); 174 @SuppressWarnings("static-access") 175 private final Option CALC_NEIGHBORHOOD = OptionBuilder 176 .isRequired(false) 177 .withLongOpt("calculateNeighborhood") 178 .hasArg(false) 179 .withDescription("computes the neighborhood relation") 180 .create("lattice"); 181// @SuppressWarnings("static-access") 182// private final Option CALC_LAYOUT = OptionBuilder 183// .isRequired(false) 184// .withLongOpt("calculateLayout") 185// .hasArg(false) 186// .withDescription("computes a concept layout") 187// .create("layout"); 188 @SuppressWarnings("static-access") 189 private final Option CALC_IMPLICATIONS = OptionBuilder 190 .isRequired(false) 191 .withLongOpt("calculateImplications") 192 .hasArg(false) 193 .withDescription("computes implicational base") 194 .create("implications"); 195// @SuppressWarnings("static-access") 196// private final Option CALC_ASSOCIATIONS = OptionBuilder 197// .isRequired(false) 198// .withLongOpt("calculateAssociations") 199// .hasArg(true) 200// .withArgName("supp") 201// .withArgName("conf") 202// .withDescription("computes all association rules") 203// .create("associationrules"); 204 @SuppressWarnings("static-access") 205 private final Option PRINT_TO_CONSOLE = OptionBuilder 206 .isRequired(false) 207 .withLongOpt("printToConsole") 208 .hasArg(false) 209 .withDescription("prints all results to console") 210 .create("print"); 211 @SuppressWarnings("static-access") 212 private final Option WRITE_TO_FILE = OptionBuilder 213 .isRequired(false) 214 .withLongOpt("writeToFile") 215 .hasArg(false) 216 // .hasArgs(2) 217 // .withValueSeparator(' ') 218 // .withArgName("format") 219 // .withArgName("file") 220 .withDescription("writes all results to files") 221 .create("write"); 222 @SuppressWarnings("static-access") 223 private final Option GUI = OptionBuilder 224 .isRequired(false) 225 .hasArg(false) 226 .withDescription("starts the JavaFX gui") 227 .withLongOpt("startGUI") 228 .create("gui"); 229// @SuppressWarnings("static-access") 230// private final Option TEST = OptionBuilder 231// .isRequired(false) 232// .hasArg(true) 233// .withArgName("path") 234// .withDescription("runs the test suite") 235// .withLongOpt("runTestSuite") 236// .create("test"); 237// @SuppressWarnings("static-access") 238// private final Option BENCHMARK = OptionBuilder 239// .isRequired(false) 240// .hasArg(true) 241// .withArgName("path") 242// .withDescription("runs the benchmark suite") 243// .withLongOpt("runBenchmarkSuite") 244// .create("bench"); 245 246 { 247 OPTIONS.addOption(GUI); 248 OPTIONS.addOption(HELP); 249 OPTIONS.addOption(IMPORT_CXT); 250 OPTIONS.addOption(CALC_CONCEPTS); 251 OPTIONS.addOption(CALC_NEIGHBORHOOD); 252// OPTIONS.addOption(CALC_LAYOUT); 253 OPTIONS.addOption(CALC_IMPLICATIONS); 254// OPTIONS.addOption(CALC_ASSOCIATIONS); 255 OPTIONS.addOption(PRINT_TO_CONSOLE); 256 OPTIONS.addOption(WRITE_TO_FILE); 257// OPTIONS.addOption(TEST); 258// OPTIONS.addOption(BENCHMARK); 259 } 260}