![JAR search and dependency download from the Maven repository](/logo.png)
com.github.rinde.rinsim.experiment.ExperimentCli Maven / Gradle / Ivy
/*
* Copyright (C) 2011-2016 Rinde van Lon, iMinds-DistriNet, KU Leuven
*
* 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 com.github.rinde.rinsim.experiment;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Verify.verifyNotNull;
import static com.google.common.collect.Lists.newArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import com.github.rinde.rinsim.cli.ArgHandler;
import com.github.rinde.rinsim.cli.ArgumentParser;
import com.github.rinde.rinsim.cli.Menu;
import com.github.rinde.rinsim.cli.NoArgHandler;
import com.github.rinde.rinsim.cli.Option;
import com.github.rinde.rinsim.cli.Option.OptionArg;
import com.github.rinde.rinsim.cli.Option.OptionNoArg;
import com.github.rinde.rinsim.experiment.Experiment.Builder;
import com.github.rinde.rinsim.experiment.Experiment.Computers;
import com.github.rinde.rinsim.io.FileProviderCli;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
/**
* Defines a command-line interface for {@link Experiment.Builder}.
* @author Rinde van Lon
*/
public final class ExperimentCli {
static final String DEFAULT_LABEL = " (default)";
static final String S = "s";
static final String CONFIG_PREFIX = "c";
private ExperimentCli() {}
/**
* Creates a {@link Menu} for a {@link Experiment.Builder} instance.
* @param builder The instance to create a {@link Menu} for.
* @return A newly constructed {@link Menu}.
*/
public static Menu createMenu(Experiment.Builder builder) {
return createMenuBuilder(builder).build();
}
/**
* Creates a {@link com.github.rinde.rinsim.cli.Menu.Builder} for a
* {@link Experiment.Builder} instance. Via this instance the command-line
* interface menu can be extended.
* @param builder The experiment builder to create a menu builder for.
* @return A newly constructed menu builder.
*/
public static Menu.Builder createMenuBuilder(Experiment.Builder builder) {
final Map cfgMap = createConfigMap(builder);
final Menu.Builder menuBuilder = Menu.builder();
menuBuilder
.commandLineSyntax("java -jar jarname.jar ")
.header("RinSim Experiment command line interface.")
.footer("For more information see http://github.com/rinde/RinSim")
.openGroup()
.add(createBatchesOpt(builder), builder, IntHandlers.BATCHES)
.add(createThreadsOpt(builder), builder, IntHandlers.THREADS)
.openGroup()
.add(createIncludeOpt(cfgMap), builder, new IncludeHandler(cfgMap))
.add(createExcludeOpt(cfgMap), builder, new ExcludeHandler(cfgMap))
.openGroup()
.add(createLocalOpt(builder), builder, NoArgHandlers.LOCAL)
.add(createJppfOpt(builder), builder, NoArgHandlers.DISTRIBUTED)
.closeGroup()
.add(createDryRunOpt(builder), builder, StringHandler.DRY_RUN)
.add(createRepetitionsOpt(builder), builder, IntHandlers.REPS)
.add(createSeedRepetitionsOpt(builder), builder, IntHandlers.SEED_REPS)
.add(createSeedOption(builder), builder, LongHandlers.SEED)
.add(createGuiOpt(builder), builder, BooleanHandler.GUI)
.add(createOrderingOption(builder), builder, OrderingHandler.INSTANCE)
.add(createWarmupOption(builder), builder, LongHandlers.WARMUP)
.addHelpOption("h", "help", "Print this message.");
if (builder.scenarioProviderBuilder.isPresent()) {
menuBuilder.addSubMenu(S, "scenarios.",
FileProviderCli
.createDefaultMenu(builder.scenarioProviderBuilder
.get()));
}
return menuBuilder;
}
static OptionArg createBatchesOpt(Builder expBuilder) {
return Option.builder("b", ArgumentParser.intParser())
.longName("batches")
.description(
"Sets the number of batches to use in case of distributed "
+ "computation, default: ",
expBuilder.numBatches,
". This option can not be used together with --threads.")
.build();
}
static Map createConfigMap(
Experiment.Builder builder) {
final List configs =
ImmutableList.copyOf(builder.configurationsSet);
final ImmutableMap.Builder mapBuilder =
ImmutableMap.builder();
for (int i = 0; i < configs.size(); i++) {
mapBuilder.put(CONFIG_PREFIX + Integer.toString(i), configs.get(i));
}
return mapBuilder.build();
}
static OptionArg createDryRunOpt(Builder builder) {
return Option.builder("dr", ArgumentParser.stringParser())
.longName("dry-run")
.description(
"Will perform a 'dry run' of the experiment without doing any"
+ " actual simulations. A detailed description of the "
+ "experiment setup will be printed. If an additional "
+ "argument 'v' or 'verbose' is supplied, more details of"
+ " the experiment will be printed.")
.setOptionalArgument()
.build();
}
static OptionArg> createExcludeOpt(
Map configMap) {
return Option.builder("e", ArgumentParser.prefixedIntList(CONFIG_PREFIX))
.longName("exclude")
.description(
"The following configurations can be excluded from the experiment"
+ " setup:",
createConfigString(configMap),
"This option can not be used together with --include.")
.build();
}
static OptionArg createGuiOpt(Builder builder) {
return Option.builder("g", ArgumentParser.booleanParser())
.longName("show-gui")
.description(
"Starts the gui for each simulation when 'true' is supplied, hides "
+ "it when 'false' is supplied. By default the gui is ",
builder.showGui ? "" : "not",
" shown. The gui can only be shown if the computation is performed "
+ "locally and the number of threads is set to 1.")
.build();
}
static OptionArg> createIncludeOpt(
Map configMap) {
return Option.builder("i", ArgumentParser.prefixedIntList(CONFIG_PREFIX))
.longName("include")
.description(
"The following configurations can be included in the experiment "
+ "setup:",
createConfigString(configMap),
"This option can not be used together with --exclude.")
.build();
}
static String createConfigString(Map configMap) {
final StringBuilder sb = new StringBuilder(System.lineSeparator());
Joiner.on(System.lineSeparator())
.withKeyValueSeparator(" = ")
.appendTo(sb, toStringMap(configMap))
.append(
"\nThe options should be given as a comma ',' separated list. ")
.append(
"If this option is not used all configurations are automatically "
+ "included. ");
return sb.toString();
}
static Map toStringMap(
Map configMap) {
return Maps.transformValues(configMap, ConfigToName.INSTANCE);
}
static OptionNoArg createJppfOpt(Builder builder) {
return Option.builder("j")
.longName("jppf")
.description(
"Compute the experiment using the JPPF framework",
builder.getComputer() == Computers.DISTRIBUTED ? DEFAULT_LABEL
: "",
". This option can not be used together with the --local option.")
.build();
}
static OptionNoArg createLocalOpt(Builder builder) {
return Option.builder("l")
.longName("local")
.description(
"Compute the experiment locally",
builder.getComputer() == Computers.LOCAL ? DEFAULT_LABEL : "",
". This option can not be used together with the --jppf option.")
.build();
}
static OptionArg createRepetitionsOpt(Builder builder) {
return Option
.builder("r", ArgumentParser.intParser())
.longName("repetitions")
.description(
"Sets the number of repetitions of each setting, default: ",
builder.repetitions)
.build();
}
static OptionArg createSeedRepetitionsOpt(Builder builder) {
return Option
.builder("sr", ArgumentParser.intParser())
.longName("seed-repetitions")
.description(
"Sets the number of seed repetitions of each setting, default: ",
builder.seedRepetitions)
.build();
}
static OptionArg createSeedOption(Experiment.Builder builder) {
return Option.builder(S, ArgumentParser.longParser())
.longName("seed")
.description(
"Sets the master random seed, default: ", builder.masterSeed, ".")
.build();
}
static OptionArg createThreadsOpt(Experiment.Builder builder) {
return Option
.builder("t", ArgumentParser.intParser())
.longName("threads")
.description(
"Sets the number of threads to use in case of local computation, "
+ "default: ",
builder.numThreads,
". This option can not be used together with --batches.")
.build();
}
static OptionArg> createOrderingOption(
Builder builder) {
return Option.builder("o",
ArgumentParser.enumListParser("list", SimulationProperty.class))
.longName("ordering")
.description(
"Sets the ordering of simulations as specified by simulation "
+ "properties, default: ",
Joiner.on(",").join(builder.experimentOrdering),
". All options must be specified exactly once.")
.build();
}
static OptionArg createWarmupOption(Builder builder) {
return Option.builder("w", ArgumentParser.longParser())
.longName("warmup")
.description(
"Sets the warmup period (in ms) of the experiment, default: ",
builder.warmupPeriodMs, " ms.")
.build();
}
static Optional execute(Experiment.Builder builder, String[] args) {
return createMenu(builder).execute(args);
}
static Optional safeExecute(Experiment.Builder builder,
String[] args) {
return createMenu(builder).safeExecute(args);
}
enum StringHandler implements ArgHandler {
DRY_RUN {
@Override
public void execute(Builder builder, Optional value) {
if (value.isPresent()) {
checkArgument(
"v".equalsIgnoreCase(value.get())
|| "verbose".equalsIgnoreCase(value.get()),
"only accepts 'v', 'verbose' or no argument, not '%s'.",
value.get());
}
builder.dryRun(value.isPresent(), System.out, System.err);
}
}
}
enum BooleanHandler implements ArgHandler {
GUI {
@Override
public void execute(Builder builder, Optional value) {
builder.showGui(value.isPresent() && value.get());
}
}
}
enum LongHandlers implements ArgHandler {
SEED {
@Override
public void execute(Builder builder, Optional value) {
builder.withRandomSeed(value.get());
}
},
WARMUP {
@Override
public void execute(Builder subject, Optional argument) {
subject.withWarmup(argument.get());
}
}
}
enum NoArgHandlers implements NoArgHandler {
LOCAL {
@Override
public void execute(Builder builder) {
builder.computeLocal();
}
},
DISTRIBUTED {
@Override
public void execute(Builder builder) {
builder.computeDistributed();
}
}
}
enum IntHandlers implements ArgHandler {
THREADS {
@Override
public void execute(Builder builder, Optional value) {
builder.withThreads(value.get());
}
},
REPS {
@Override
public void execute(Builder builder, Optional value) {
builder.repeat(value.get());
}
},
SEED_REPS {
@Override
public void execute(Builder builder, Optional value) {
builder.repeatSeed(value.get());
}
},
BATCHES {
@Override
public void execute(Builder subject, Optional value) {
subject.numBatches(value.get());
}
};
}
enum OrderingHandler
implements ArgHandler> {
INSTANCE {
@Override
public void execute(Builder subject,
Optional> argument) {
subject.withOrdering(argument.get());
}
}
}
enum ConfigToName implements Function {
INSTANCE {
@Override
@Nullable
public String apply(@Nullable MASConfiguration input) {
return verifyNotNull(input).getName();
}
}
}
static class ExcludeHandler extends ConfigHandler {
protected ExcludeHandler(Map map) {
super(map);
}
@Override
void checkNumArgs(List args) {
checkArgument(
args.size() < configMap.size(),
"Too many configurations, at most %s configurations can be excluded.",
configMap.size() - 1);
}
@Override
void doExecute(Builder builder, List selectedConfigs) {
builder.configurationsSet.removeAll(selectedConfigs);
}
}
static class IncludeHandler extends ConfigHandler {
IncludeHandler(Map map) {
super(map);
}
@Override
void checkNumArgs(List args) {
checkArgument(
args.size() <= configMap.size(),
"Too many configurations, at most %s configurations can be included.",
configMap.size());
}
@Override
void doExecute(Builder builder, List selectedConfigs) {
builder.configurationsSet.retainAll(selectedConfigs);
}
}
abstract static class ConfigHandler implements
ArgHandler> {
final Map configMap;
ConfigHandler(Map map) {
configMap = map;
}
@Override
public final void execute(Builder builder,
Optional> argument) {
final List args = argument.get();
final List selectedConfigs = newArrayList();
checkNumArgs(args);
for (final String k : args) {
checkArgument(configMap.containsKey(k),
"The key '%s' is not valid. Valid keys: %s.", k,
configMap.keySet());
selectedConfigs.add(configMap.get(k));
}
doExecute(builder, selectedConfigs);
}
abstract void checkNumArgs(List args);
abstract void doExecute(Builder builder,
List selectedConfigs);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy