/**
   *
   *
   * <pre>
   * A 3
   *     B ?
   * C -> A
   * D -> A
   * </pre>
   */
  @Test(timeout = 60000)
  public void breakTargetRefWithChildren() {
    AstModel model = newModel();

    AstConcreteClafer a = model.addChild("A").withCard(3, 3);
    AstConcreteClafer b = a.addChild("B").withCard(Optional);
    AstConcreteClafer c = model.addChild("C").refTo(a).withCard(Mandatory);
    AstConcreteClafer d = model.addChild("D").refTo(a).withCard(Mandatory);

    ClaferSolver solver = ClaferCompiler.compile(model, Scope.setScope(b, 1).defaultScope(3));
    assertEquals(7, solver.allInstances().length);
  }
  /**
   *
   *
   * <pre>
   * abstract Service
   *     cpu: integer
   *     machine -> Machine // the -> means every service must be allocated to some machine
   *     [ this in machine.services ]
   *
   * MailService : Service
   *     [cpu = 8]
   *
   * SearchService : Service
   *     [cpu = 7]
   *
   * CalendarService : Service
   *     [cpu = 5]
   *
   * DriveService : Service
   *     [cpu = 4]
   *
   * GroupsService : Service
   *     [cpu = 5]
   *
   * abstract Machine
   *     services -> Service*
   *     [this.machine = parent]
   *     total_cpu : integer = sum services.cpu
   *     [total_cpu &lt;= this.cpuLimit]
   *     cpuLimit : integer
   *     isFree : integer = (if (#this.services = 0) then 1 else 0)
   *
   * GoogleCA : Machine
   *     [cpuLimit = 20]
   *
   * GoogleNY : Machine
   *     [cpuLimit = 10]
   *
   * GoogleTX : Machine
   *     [cpuLimit = 11]
   *
   * abstract Task
   *     total_free : integer = sum Machine.isFree
   *
   * MyTask: Task
   * &lt;&lt;max MyTask.total_free&gt;&gt;
   * </pre>
   */
  @Test(timeout = 60000)
  public void breakServices() {
    AstModel model = newModel();

    AstAbstractClafer c0_Service = model.addAbstract("Service");
    AstAbstractClafer c0_Machine = model.addAbstract("c0_Machine");
    AstAbstractClafer c0_Task = model.addAbstract("c0_Task");
    AstConcreteClafer c0_cpu = c0_Service.addChild("c0_cpu").withCard(1, 1);
    AstConcreteClafer c0_machine = c0_Service.addChild("c0_machine").withCard(1, 1);
    AstConcreteClafer c0_MailService =
        model.addChild("c0_MailService").withCard(1, 1).extending(c0_Service);
    AstConcreteClafer c0_SearchService =
        model.addChild("c0_SearchService").withCard(1, 1).extending(c0_Service);
    AstConcreteClafer c0_CalendarService =
        model.addChild("c0_CalendarService").withCard(1, 1).extending(c0_Service);
    AstConcreteClafer c0_DriveService =
        model.addChild("c0_DriveService").withCard(1, 1).extending(c0_Service);
    AstConcreteClafer c0_GroupsService =
        model.addChild("c0_GroupsService").withCard(1, 1).extending(c0_Service);
    AstConcreteClafer c0_services = c0_Machine.addChild("c0_services");
    AstConcreteClafer c0_total_cpu = c0_Machine.addChild("c0_total_cpu").withCard(1, 1);
    AstConcreteClafer c0_cpuLimit = c0_Machine.addChild("c0_cpuLimit").withCard(1, 1);
    AstConcreteClafer c0_isFree = c0_Machine.addChild("c0_isFree").withCard(1, 1);
    AstConcreteClafer c0_GoogleCA =
        model.addChild("c0_GoogleCA").withCard(1, 1).extending(c0_Machine);
    AstConcreteClafer c0_GoogleNY =
        model.addChild("c0_GoogleNY").withCard(1, 1).extending(c0_Machine);
    AstConcreteClafer c0_GoogleTX =
        model.addChild("c0_GoogleTX").withCard(1, 1).extending(c0_Machine);
    AstConcreteClafer c0_total_free = c0_Task.addChild("c0_total_free").withCard(1, 1);
    AstConcreteClafer c0_MyTask = model.addChild("c0_MyTask").withCard(1, 1).extending(c0_Task);
    c0_cpu.refTo(IntType);
    c0_machine.refToUnique(c0_Machine);
    c0_services.refToUnique(c0_Service);
    c0_total_cpu.refTo(IntType);
    c0_cpuLimit.refTo(IntType);
    c0_isFree.refTo(IntType);
    c0_total_free.refTo(IntType);
    c0_Service.addConstraint(
        in($this(), joinRef(join(joinRef(join($this(), c0_machine)), c0_services))));
    c0_MailService.addConstraint(equal(joinRef(join($this(), c0_cpu)), constant(8)));
    c0_SearchService.addConstraint(equal(joinRef(join($this(), c0_cpu)), constant(7)));
    c0_CalendarService.addConstraint(equal(joinRef(join($this(), c0_cpu)), constant(5)));
    c0_DriveService.addConstraint(equal(joinRef(join($this(), c0_cpu)), constant(4)));
    c0_GroupsService.addConstraint(equal(joinRef(join($this(), c0_cpu)), constant(5)));
    c0_Machine.addConstraint(
        equal(
            joinRef(join($this(), c0_total_cpu)),
            sum(join(joinRef(join($this(), c0_services)), c0_cpu))));
    c0_Machine.addConstraint(
        lessThanEqual(joinRef(join($this(), c0_total_cpu)), joinRef(join($this(), c0_cpuLimit))));
    c0_Machine.addConstraint(
        equal(
            joinRef(join($this(), c0_isFree)),
            ifThenElse(
                equal(card(join($this(), c0_services)), constant(0)), constant(1), constant(0))));
    c0_services.addConstraint(
        equal(joinRef(join(joinRef($this()), c0_machine)), joinParent($this())));
    c0_GoogleCA.addConstraint(equal(joinRef(join($this(), c0_cpuLimit)), constant(20)));
    c0_GoogleNY.addConstraint(equal(joinRef(join($this(), c0_cpuLimit)), constant(10)));
    c0_GoogleTX.addConstraint(equal(joinRef(join($this(), c0_cpuLimit)), constant(11)));
    c0_Task.addConstraint(
        equal(joinRef(join($this(), c0_total_free)), sum(join(global(c0_Machine), c0_isFree))));

    ClaferOptimizer solver =
        ClaferCompiler.compile(
            model,
            Scope.setScope(c0_services, 5)
                .setScope(c0_Machine, 4)
                .setScope(c0_Service, 5)
                .setScope(c0_Task, 1)
                .setScope(c0_cpu, 5)
                .setScope(c0_cpuLimit, 4)
                .setScope(c0_isFree, 4)
                .setScope(c0_machine, 5)
                .setScope(c0_total_cpu, 4)
                .setScope(c0_total_free, 1)
                .intLow(-128)
                .intHigh(128),
            Objective.maximize(joinRef(join(global(c0_MyTask), c0_total_free))));
    int count = 0;
    while (solver.find()) {
      assertArrayEquals(new int[] {1}, solver.optimalValues());
      count++;
    }
    assertEquals(7, count);
  }