public ConfigurableProgramAnalysis createCPA(
      final CFA cfa,
      @Nullable final MainCPAStatistics stats,
      SpecAutomatonCompositionType composeWithSpecificationCPAs)
      throws InvalidConfigurationException, CPAException {
    logger.log(Level.FINE, "Creating CPAs");
    if (stats != null) {
      stats.cpaCreationTime.start();
    }
    try {

      if (useRestartingAlgorithm) {
        // hard-coded dummy CPA
        return LocationCPA.factory().set(cfa, CFA.class).setConfiguration(config).createInstance();
      }

      final ConfigurableProgramAnalysis cpa;
      switch (composeWithSpecificationCPAs) {
        case TARGET_SPEC:
          cpa = cpaFactory.buildCPAWithSpecAutomatas(cfa);
          break;
        case BACKWARD_TO_ENTRY_SPEC:
          cpa = cpaFactory.buildCPAWithBackwardSpecAutomatas(cfa);
          break;
        default:
          cpa = cpaFactory.buildCPAs(cfa, null);
      }

      if (stats != null && cpa instanceof StatisticsProvider) {
        ((StatisticsProvider) cpa).collectStatistics(stats.getSubStatistics());
      }
      return cpa;

    } finally {
      if (stats != null) {
        stats.cpaCreationTime.stop();
      }
    }
  }
  public Algorithm createAlgorithm(
      final ConfigurableProgramAnalysis cpa,
      final String programDenotation,
      final CFA cfa,
      @Nullable final MainCPAStatistics stats)
      throws InvalidConfigurationException, CPAException {
    logger.log(Level.FINE, "Creating algorithms");

    Algorithm algorithm;

    if (useProofCheckAlgorithm) {
      logger.log(Level.INFO, "Using Proof Check Algorithm");
      algorithm = new ProofCheckAlgorithm(cpa, config, logger, shutdownNotifier, cfa);
    } else if (useRestartingAlgorithm) {
      logger.log(Level.INFO, "Using Restarting Algorithm");
      algorithm = new RestartAlgorithm(config, logger, shutdownNotifier, programDenotation, cfa);

      if (useARGCombiningAlgorithm) {
        algorithm = new PartialARGsCombiner(algorithm, config, logger, shutdownNotifier, cfa);
      }
    } else if (useImpactAlgorithm) {
      algorithm = new ImpactAlgorithm(config, logger, shutdownNotifier, cpa, cfa);

    } else if (useRestartAlgorithmWithARGReplay) {
      algorithm = new RestartAlgorithmWithARGReplay(config, logger, shutdownNotifier, cfa);

    } else {
      algorithm = CPAAlgorithm.create(cpa, logger, config, shutdownNotifier, stats);

      if (useAnalysisWithEnablerCPAAlgorithm) {
        algorithm =
            new AnalysisWithRefinableEnablerCPAAlgorithm(
                algorithm, cpa, cfa, logger, config, shutdownNotifier);
      }

      if (useCEGAR) {
        algorithm = new CEGARAlgorithm(algorithm, cpa, config, logger);
      }

      if (useBMC) {
        algorithm =
            new BMCAlgorithm(
                algorithm, cpa, config, logger, reachedSetFactory, shutdownNotifier, cfa);
      }

      if (checkCounterexamples) {
        algorithm =
            new CounterexampleCheckAlgorithm(
                algorithm, cpa, config, logger, shutdownNotifier, cfa, programDenotation);
      }

      if (useBDDCPARestriction) {
        algorithm =
            new BDDCPARestrictionAlgorithm(
                algorithm, cpa, config, logger, shutdownNotifier, cfa, programDenotation);
      }

      if (collectAssumptions) {
        algorithm =
            new AssumptionCollectorAlgorithm(algorithm, cpa, cfa, shutdownNotifier, config, logger);
      }

      if (useAdjustableConditions) {
        algorithm = new RestartWithConditionsAlgorithm(algorithm, cpa, config, logger);
      }

      if (useTestGenAlgorithm) {
        algorithm = new TestGenAlgorithm(algorithm, cpa, shutdownNotifier, cfa, config, logger);
      }

      if (usePropertyCheckingAlgorithm) {
        if (!(cpa instanceof PropertyCheckerCPA)) {
          throw new InvalidConfigurationException(
              "Property checking algorithm requires CPAWithPropertyChecker as Top CPA");
        }
        algorithm = new AlgorithmWithPropertyCheck(algorithm, logger, (PropertyCheckerCPA) cpa);
      }

      if (useResultCheckAlgorithm) {
        algorithm = new ResultCheckAlgorithm(algorithm, cpa, cfa, config, logger, shutdownNotifier);
      }

      if (useCustomInstructionRequirementExtraction) {
        algorithm =
            new CustomInstructionRequirementsExtractingAlgorithm(
                algorithm, cpa, config, logger, shutdownNotifier, cfa);
      }

      if (usePreconditionRefinementAlgorithm) {
        algorithm =
            new PreconditionRefinerAlgorithm(algorithm, cpa, cfa, config, logger, shutdownNotifier);
      }
    }

    if (stats != null && algorithm instanceof StatisticsProvider) {
      ((StatisticsProvider) algorithm).collectStatistics(stats.getSubStatistics());
    }
    return algorithm;
  }