public static MultiVariatePieceWiseLinearFunction createSenseSleepFunctionVerbose(
      ScenarioProperties scenario, List<SensorProperties> sensorProperties) {

    NCube domain = createDomain(sensorProperties, scenario);

    // max(0, min(x1 + l1, x2 + l2) - max(x1, x2))

    MultiVariatePieceWiseLinearFunction zero =
        MultiVariatePieceWiseLinearFunctionUtilities.createZeroFunction(domain);

    double l = scenario.getScheduleIntervalLength();

    StopWatch watch = new StopWatch();

    watch.start();
    MultiVariatePieceWiseLinearFunction maxStart = createMaxStartFunction(domain);
    watch.stop();
    System.out.println(
        "Created maxStart in "
            + watch.getTime()
            + ". Simplices "
            + maxStart.getPartitioning().getSimplices().size());

    watch.reset();
    watch.start();
    MultiVariatePieceWiseLinearFunction minEnd = createMinEndFunction(domain, sensorProperties);
    watch.stop();
    System.out.println(
        "Created minEnd in "
            + watch.getTime()
            + ". Simplices "
            + minEnd.getPartitioning().getSimplices().size());

    watch.reset();
    watch.start();
    MultiVariatePieceWiseLinearFunction minMinusMax = minEnd.subtract(maxStart);
    watch.stop();
    System.out.println(
        "Created minMinusMax in "
            + watch.getTime()
            + ". Simplices "
            + minMinusMax.getPartitioning().getSimplices().size());

    watch.reset();
    watch.start();
    MultiVariatePieceWiseLinearFunction overlap = minMinusMax.max(zero);
    System.out.println(
        "Created overlap in "
            + watch.getTime()
            + ". Simplices "
            + overlap.getPartitioning().getSimplices().size());

    MultiVariatePieceWiseLinearFunction result = overlap.subtract(l).multiply(-1.0);

    System.out.println("Simplices " + result.getPartitioning().getSimplices().size());

    return result;
  }
  private static List<MultiVariatePieceWiseLinearFunction> createStartFunctions(NCube domain) {
    List<MultiVariatePieceWiseLinearFunction> result =
        new Vector<MultiVariatePieceWiseLinearFunction>();

    for (int i = 0; i < domain.getDimensionCount(); i++) {
      result.add(MultiVariatePieceWiseLinearFunctionUtilities.createUnivariateFunction(domain, i));
    }

    return result;
  }
  public static MultiVariatePieceWiseLinearFunction createSenseSleepFunction(
      ScenarioProperties scenario,
      List<SensorProperties> sensorProperties,
      double overlappingArea) {
    System.out.println(
        "Creating continuous sense sleep function with " + sensorProperties.size() + " dimensions");

    NCube domain = createDomain(sensorProperties, scenario);

    if (sensorProperties.size() == 1) {
      return MultiVariatePieceWiseLinearFunctionUtilities.createConstantFunction(
          domain, overlappingArea * sensorProperties.iterator().next().getSenseIntervalLength());
    }

    // max(0, min(x1 + l1, x2 + l2) - max(x1, x2))
    MultiVariatePieceWiseLinearFunction zero =
        MultiVariatePieceWiseLinearFunctionUtilities.createZeroFunction(domain);

    // double l = scenario.getScheduleIntervalLength();

    MultiVariatePieceWiseLinearFunction maxStart = createMaxStartFunction(domain);

    MultiVariatePieceWiseLinearFunction minEnd = createMinEndFunction(domain, sensorProperties);

    MultiVariatePieceWiseLinearFunction minMinusMax = minEnd.subtract(maxStart);

    MultiVariatePieceWiseLinearFunction overlap = minMinusMax.max(zero);

    // MultiVariatePieceWiseLinearFunction result =
    // overlap.add(-l).multiply(
    // -1.0);

    MultiVariatePieceWiseLinearFunction result = overlap;

    for (SensorProperties properties : sensorProperties) {
      result = result.add(-properties.getSenseIntervalLength());
    }

    result = result.multiply(-1);

    return result.multiply(overlappingArea);
  }