or-toolscp-sat

OR-tools CP-SAT - implement presence_literal constraint


From the attached seminar (timestamped), if you constrain the sum of all presence_literals * interval_size to be less than the makespan, the proven problems number of problems rises according to the video.

Naturally, I would like to include that in my problem, which is based on sample. However, I have not found how to do this, in particular, since it considers machines, I was under the impression that it should be in this section of the sample;

 # Transition times and transition costs using a circuit constraint.
  switch_literals = []
  for machine_id in all_machines:
    machine_starts = starts_per_machines[machine_id]
    machine_ends = ends_per_machines[machine_id]
    machine_presences = presences_per_machines[machine_id]
    machine_resources = resources_per_machines[machine_id]
    machine_ranks = ranks_per_machines[machine_id]
    intervals = intervals_per_machines[machine_id]
    arcs = []
    num_machine_tasks = len(machine_starts)
    all_machine_tasks = range(num_machine_tasks)

    for i in all_machine_tasks:
      # Initial arc from the dummy node (0) to a task.
      start_lit = model.NewBoolVar('')
      arcs.append([0, i + 1, start_lit])
      # If this task is the first, set both rank and start to 0.
      model.Add(machine_ranks[i] == 0).OnlyEnforceIf(start_lit)
      model.Add(machine_starts[i] == 0).OnlyEnforceIf(start_lit)
      # Final arc from an arc to the dummy node.
      arcs.append([i + 1, 0, model.NewBoolVar('')])
      # Self arc if the task is not performed.
      arcs.append([i + 1, i + 1, machine_presences[i].Not()])
      model.Add(machine_ranks[i] == -1).OnlyEnforceIf(
          machine_presences[i].Not())

      for j in all_machine_tasks:
        if i == j:
          continue

        lit = model.NewBoolVar('%i follows %i' % (j, i))
        arcs.append([i + 1, j + 1, lit])
        model.AddImplication(lit, machine_presences[i])
        model.AddImplication(lit, machine_presences[j])

        # Maintain rank incrementally.
        model.Add(machine_ranks[j] == machine_ranks[i] + 1).OnlyEnforceIf(lit)

        # Compute the transition time if task j is the successor of task i.
        if machine_resources[i] != machine_resources[j]:
          transition_time = 3
          switch_literals.append(lit)
        else:
          transition_time = 0
        # We add the reified transition to link the literals with the times
        # of the tasks.
        model.Add(machine_starts[j] == machine_ends[i] +
                  transition_time).OnlyEnforceIf(lit)

I tried to implement it as follows;

model.Add(sum(machine_presences[i] * intervals[i] for i in all_machine_tasks) <= horizon)

Which yields error

arg = cmh.assert_is_a_number(arg)

TypeError: Not a number: interval_j5_t11_a0

What is the best way to implement this based on the sample? Would I for example need to create a variable duration per task on a machine and multiply that figure with the presence_literal? I work with OR-tools 9.8 and Python.


Solution

  • presence_literal * interval makes no sense. The example in the video uses presence_literal * fixed_size.

    And this is done automatically when you use multiple workers. If you have a max_lp, reduced_costs worker active, then these linear equations will be added both statically when the model is loaded, and dynamically with linear cuts when the makespan is reduced.