public static void main(String[] args) {
    // see an example with detailed explanations -- package
    // opdytsintegration.example.networkparameters.RunNetworkParameters
    Config config = ConfigUtils.loadConfig(EQUIL_DIR + "/config.xml");

    config.controler().setOutputDirectory(OUT_DIR);
    config.controler().setOverwriteFileSetting(OverwriteFileSetting.deleteDirectoryIfExists);

    //		config.plans().setInputFile("relaxed_plans.xml.gz");
    config.plans().setInputFile("plans2000.xml.gz");

    // == default config has limited inputs
    StrategyConfigGroup strategies = config.strategy();
    strategies.clearStrategySettings();

    config.changeMode().setModes(new String[] {"car", "pt"});
    StrategySettings modeChoice = new StrategySettings();
    modeChoice.setStrategyName(
        DefaultPlanStrategiesModule.DefaultStrategy.ChangeSingleTripMode.name());
    modeChoice.setWeight(0.1);
    config.strategy().addStrategySettings(modeChoice);

    StrategySettings expChangeBeta = new StrategySettings();
    expChangeBeta.setStrategyName(DefaultPlanStrategiesModule.DefaultSelector.ChangeExpBeta.name());
    expChangeBeta.setWeight(0.9);
    config.strategy().addStrategySettings(expChangeBeta);

    for (PlanCalcScoreConfigGroup.ActivityParams params :
        config.planCalcScore().getActivityParams()) {
      params.setTypicalDurationScoreComputation(
          PlanCalcScoreConfigGroup.TypicalDurationScoreComputation.relative);
    }

    //		config.qsim().setTrafficDynamics( QSimConfigGroup.TrafficDynamics.withHoles );
    //
    //		if ( config.qsim().getTrafficDynamics()== QSimConfigGroup.TrafficDynamics.withHoles ) {
    //			config.qsim().setInflowConstraint(QSimConfigGroup.InflowConstraint.maxflowFromFdiag);
    //		}

    config.qsim().setUsingFastCapacityUpdate(true);

    // ==

    Scenario scenario = KNBerlinControler.prepareScenario(true, false, config);

    double time = 6 * 3600.;
    for (Person person : scenario.getPopulation().getPersons().values()) {
      Plan plan = person.getSelectedPlan();
      Activity activity = (Activity) plan.getPlanElements().get(0);
      activity.setEndTime(time);
      time++;
    }

    // ==

    // this is something like time bin generator
    int startTime = 0;
    int binSize = 3600; // can this be scenario simulation end time.
    int binCount = 24; // to me, binCount and binSize must be related
    TimeDiscretization timeDiscretization = new TimeDiscretization(startTime, binSize, binCount);

    Set<String> modes2consider = new HashSet<>();
    modes2consider.add("car");
    modes2consider.add("bike");

    OpdytsModalStatsControlerListener stasControlerListner =
        new OpdytsModalStatsControlerListener(modes2consider, EQUIL);

    // following is the  entry point to start a matsim controler together with opdyts
    MATSimSimulator<ModeChoiceDecisionVariable> simulator =
        new MATSimSimulator<>(new MATSimStateFactoryImpl<>(), scenario, timeDiscretization);
    simulator.addOverridingModule(
        new AbstractModule() {

          @Override
          public void install() {
            // add here whatever should be attached to matsim controler
            // some stats
            addControlerListenerBinding().toInstance(stasControlerListner);

            // from KN
            addControlerListenerBinding().to(KaiAnalysisListener.class);
            bind(CharyparNagelScoringParametersForPerson.class)
                .to(EveryIterationScoringParameters.class);
          }
        });

    // this is the objective Function which returns the value for given SimulatorState
    // in my case, this will be the distance based modal split
    ObjectiveFunction objectiveFunction =
        new ModeChoiceObjectiveFunction(
            EQUIL); // in this, the method argument (SimulatorStat) is not used.

    // search algorithm
    int maxIterations =
        10; // this many times simulator.run(...) and thus controler.run() will be called.
    int maxTransitions = Integer.MAX_VALUE;
    int populationSize =
        10; // the number of samples for decision variables, one of them will be drawn randomly for
    // the simulation.

    boolean interpolate = true;
    boolean includeCurrentBest = false;

    // randomize the decision variables (for e.g.\ utility parameters for modes)
    DecisionVariableRandomizer<ModeChoiceDecisionVariable> decisionVariableRandomizer =
        new ModeChoiceRandomizer(scenario, RandomizedUtilityParametersChoser.ONLY_ASC, EQUIL);

    // what would be the decision variables to optimize the objective function.
    ModeChoiceDecisionVariable initialDecisionVariable =
        new ModeChoiceDecisionVariable(scenario.getConfig().planCalcScore(), scenario, EQUIL);

    // what would decide the convergence of the objective function
    final int iterationsToConvergence = 200; //
    final int averagingIterations = 10;
    ConvergenceCriterion convergenceCriterion =
        new FixedIterationNumberConvergenceCriterion(iterationsToConvergence, averagingIterations);

    RandomSearch<ModeChoiceDecisionVariable> randomSearch =
        new RandomSearch<>(
            simulator,
            decisionVariableRandomizer,
            initialDecisionVariable,
            convergenceCriterion,
            maxIterations, // this many times simulator.run(...) and thus controler.run() will be
            // called.
            maxTransitions,
            populationSize,
            MatsimRandom.getRandom(),
            interpolate,
            objectiveFunction,
            includeCurrentBest);

    // probably, an object which decide about the inertia
    SelfTuner selfTuner = new SelfTuner(0.95);

    randomSearch.setLogPath(OUT_DIR);

    // run it, this will eventually call simulator.run() and thus controler.run
    randomSearch.run(selfTuner);
  }