예제 #1
0
  /**
   * Let's add temporal constraints to the formula whenever the formula is activated:
   *
   * <p>duration = end - start;
   *
   * <p>start >= origin;
   *
   * <p>end {@literal <=} horizon;
   *
   * <p>duration {@literal >=} 0;
   *
   * <p>We also constraint the amount to be greater than or equal to 0:
   *
   * <p>amount {@literal >=} 0;
   *
   * <p>If the formula is a charge formula, we also add a constraint that forces the c_amount to be
   * less or equal to the amount:
   *
   * <p>c_amount {@literal <=} amount;
   *
   * <p>c_amount {@literal >=} 0;
   *
   * @param formula the formula that has been created.
   */
  @Override
  public void formulaActivated(IFormula formula) {
    IConstraintNetwork network = solver.getConstraintNetwork();
    final INumber start = formula.get(Constants.START);
    final INumber end = formula.get(Constants.END);
    final INumber duration = formula.get(Constants.DURATION);
    final INumber amount = formula.get(AMOUNT);
    final INumber origin = solver.get(Constants.ORIGIN);
    final INumber horizon = solver.get(Constants.HORIZON);
    if (formula.getType().getName().equals(CHARGE_PREDICATE_NAME)) {
      final INumber c_amount = formula.get(C_AMOUNT);
      network.assertFacts(
          network.eq(duration, network.subtract(end, start)),
          network.geq(start, origin),
          network.leq(end, horizon),
          network.geq(duration, network.newReal("0")),
          network.geq(amount, network.newReal("0")),
          network.leq(c_amount, amount),
          network.geq(c_amount, network.newReal("0")));
    } else {
      network.assertFacts(
          network.eq(duration, network.subtract(end, start)),
          network.geq(start, origin),
          network.leq(end, horizon),
          network.geq(duration, network.newReal("0")),
          network.geq(amount, network.newReal("0")));
    }

    if (!lazy_scheduling) {
      throw new UnsupportedOperationException(
          "Eager scheduling for batteries is not supported yet..");
    }
  }
예제 #2
0
 @Override
 public void applyRule(IFormula formula) {
   formula.setActiveState();
 }
예제 #3
0
  @Override
  public List<IBool> checkConsistency(IModel model) {
    if (!lazy_scheduling) {
      return Collections.emptyList();
    } else {
      List<IBool> constraints = new ArrayList<>();
      IConstraintNetwork network = solver.getConstraintNetwork();
      final Map<IObject, Collection<IFormula>> formulas = getFormulas(model);

      IStaticCausalGraph causal_graph = solver.getStaticCausalGraph();
      if (!closed_batteries
          && solver
              .getCurrentNode()
              .getFlaws()
              .stream()
              .map(
                  flaw -> {
                    if (flaw instanceof IGoal) {
                      return causal_graph.getNode(((IGoal) flaw).getFormula().getType());
                    } else if (flaw instanceof IFact) {
                      return causal_graph.getNode(((IFact) flaw).getFormula().getType());
                    } else if (flaw instanceof IDisjunctionFlaw) {
                      return causal_graph.getNode(((IDisjunctionFlaw) flaw).getDisjunction());
                    } else if (flaw instanceof IPreferenceFlaw) {
                      return causal_graph.getNode(((IPreferenceFlaw) flaw).getPreference());
                    } else {
                      throw new AssertionError(
                          "Flaw " + flaw.getClass().getName() + " is supported yet..");
                    }
                  })
              .noneMatch(
                  node ->
                      causal_graph.existsPath(node, causal_graph.getNode(charge_predicate))
                          || causal_graph.existsPath(
                              node, causal_graph.getNode(consume_predicate)))) {
        // We need a resolver in order to re-open the resource when backtracking
        solver
            .getCurrentNode()
            .addResolver(
                new IResolver() {
                  private boolean resolved = false;

                  @Override
                  public double getKnownCost() {
                    return 0;
                  }

                  @Override
                  public void resolve() {
                    assert !resolved;

                    // Let's close the batteries
                    closed_batteries = true;
                    resolved = true;
                  }

                  @Override
                  public boolean isResolved() {
                    return resolved;
                  }

                  @Override
                  public void retract() {
                    assert resolved;
                    closed_batteries = false;
                    resolved = false;
                  }
                });
      }

      if (closed_batteries) {
        instances.forEach(
            battery -> {
              Collection<IFormula> c_formulas = formulas.get(battery);
              BatteryTimeline timeline = new BatteryTimeline(solver, model, battery, c_formulas);
              for (int i = 0; i < timeline.values.size(); i++) {
                // <editor-fold defaultstate="collapsed" desc="battery overcharge">
                if (model.evaluate(
                    network.gt(timeline.values.get(i).max_amount, timeline.capacity))) {
                  // We have a battery overcharge so we need to anticipate consumptions to charges
                  Collection<IFormula> good_charges = new ArrayList<>(c_formulas.size());
                  Collection<IFormula> good_consumptions = new ArrayList<>(c_formulas.size());
                  for (IFormula f : c_formulas) {
                    switch (f.getType().getName()) {
                      case CHARGE_PREDICATE_NAME:
                        if (model.evaluate(
                            network.leq(
                                (INumber) f.get(Constants.START),
                                network.newReal(timeline.pulses.get(i).toString())))) {
                          // Charges that affect current overcharge are all those that start before
                          // this timeline value
                          good_charges.add(f);
                        }
                        break;
                      case CONSUME_PREDICATE_NAME:
                        if (model.evaluate(
                            network.geq(
                                (INumber) f.get(Constants.END),
                                network.newReal(timeline.pulses.get(i + 1).toString())))) {
                          // Consumptions that might resolve the current overcharge are all those
                          // that end after this timeline value
                          good_consumptions.add(f);
                        }
                        break;
                      default:
                        throw new AssertionError(f.getType().getName());
                    }
                  }
                  List<IBool> or = new ArrayList<>(good_charges.size() * good_consumptions.size());
                  good_consumptions.forEach(
                      (cons) -> {
                        good_charges.forEach(
                            (charge) -> {
                              or.add(
                                  network.leq(
                                      cons.get(Constants.END), charge.get(Constants.START)));
                              or.add(network.not(cons.getScope().eq(charge.getScope())));
                            });
                      });
                  or.add(network.geq(battery.get(CAPACITY), timeline.values.get(i).max_amount));
                  constraints.add(network.or(or.toArray(new IBool[or.size()])));
                }
                // </editor-fold>
                // <editor-fold defaultstate="collapsed" desc="battery overconsumption">
                if (model.evaluate(
                    network.lt(timeline.values.get(i).min_amount, network.newReal("0")))) {
                  // We have a battery overconsumption so we need to anticipate charges to
                  // consumption
                  Collection<IFormula> good_charges = new ArrayList<>(c_formulas.size());
                  Collection<IFormula> good_consumptions = new ArrayList<>(c_formulas.size());
                  for (IFormula f : c_formulas) {
                    switch (f.getType().getName()) {
                      case CHARGE_PREDICATE_NAME:
                        if (model.evaluate(
                            network.geq(
                                (INumber) f.get(Constants.END),
                                network.newReal(timeline.pulses.get(i + 1).toString())))) {
                          // Charges that might resolve the current overconsumption are all those
                          // that end after this timeline value
                          good_charges.add(f);
                        }
                        break;
                      case CONSUME_PREDICATE_NAME:
                        if (model.evaluate(
                            network.leq(
                                (INumber) f.get(Constants.START),
                                network.newReal(timeline.pulses.get(i).toString())))) {
                          // Consumptions that affect current overconsumption are all those that
                          // start before this timeline value
                          good_consumptions.add(f);
                        }
                        break;
                      default:
                        throw new AssertionError(f.getType().getName());
                    }
                  }
                  List<IBool> or = new ArrayList<>(good_charges.size() * good_consumptions.size());
                  good_consumptions.forEach(
                      (cons) -> {
                        good_charges.forEach(
                            (charge) -> {
                              or.add(
                                  network.leq(
                                      charge.get(Constants.END), cons.get(Constants.START)));
                              or.add(network.not(charge.getScope().eq(cons.getScope())));
                            });
                      });
                  or.add(network.leq(network.newReal("0"), timeline.values.get(i).min_amount));
                  constraints.add(network.or(or.toArray(new IBool[or.size()])));
                }
                // </editor-fold>
              }

              if (timeline.values.isEmpty()
                  ? model.evaluate(network.not(timeline.initial_amount.eq(timeline.final_amount)))
                  : model.evaluate(
                      network.not(
                          timeline
                              .values
                              .get(timeline.values.size() - 1)
                              .final_amount
                              .eq(timeline.final_amount)))) {
                // The initial amount plus the sum of charges and consumptions is not equal to the
                // final amount
                final List<INumber> sum = new ArrayList<>(c_formulas.size() + 1);
                sum.add(battery.get(INITIAL_AMOUNT));
                sum.addAll(
                    c_formulas
                        .stream()
                        .map(
                            f -> {
                              switch (f.getType().getName()) {
                                case CHARGE_PREDICATE_NAME:
                                  return f.get(C_AMOUNT);
                                case CONSUME_PREDICATE_NAME:
                                  return network.negate((INumber) f.get(AMOUNT));
                                default:
                                  throw new AssertionError(f.getType().getName());
                              }
                            })
                        .collect(Collectors.toList()));

                final List<IBool> or = new ArrayList<>();
                c_formulas.forEach(
                    formula -> {
                      or.add(network.not(battery.eq(formula.getScope())));
                    });
                instances
                    .stream()
                    .filter(instance -> (instance != battery))
                    .forEach(
                        instance -> {
                          formulas
                              .get(instance)
                              .forEach(
                                  formula -> {
                                    or.add(battery.eq(formula.getScope()));
                                  });
                        });
                if (sum.size() == 1) {
                  or.add(network.eq(sum.get(0), (INumber) battery.get(FINAL_AMOUNT)));
                } else {
                  or.add(
                      network.eq(
                          network.add(sum.toArray(new INumber[sum.size()])),
                          (INumber) battery.get(FINAL_AMOUNT)));
                }

                constraints.add(network.or(or.toArray(new IBool[or.size()])));
              }
            });
      }

      return constraints;
    }
  }
예제 #4
0
 @Override
 public void goalCreated(IFormula goal) {
   goal.getType().applyRule(goal);
 }
예제 #5
0
 @Override
 public void factCreated(IFormula fact) {
   fact.getType().applyRule(fact);
 }