Initializing help system before first use

update_duration_with_idle_times

Purpose
When having previously set a start-based duration (through setduration or set_start_based_duration), this method will update the start-based durations to simulate idle time windows.
Warning: when adding several idle time windows for a resource and a task, they must be added in increasing time order and all time windows must be disjoint. If not done this way, durations might be inconsistent. Also, propagation should not be called between successive calls.
When developing the model, it is recommended to check the start-based duration constraint by printing the constraint: cp_show_var_constraints(getduration(task))
Synopsis
procedure update_duration_with_idle_times(resource: cpresource, task:cptask, t1:integer, t2:integer, allow_start_in_idle:boolean)
Arguments
resource 
a resource
task 
a task
t1 
The idle time window start
t2 
The idle time window end
allow_start_in_idle 
If true, the task will be able to start in the idle time window.
Example
The following example shows how to use update_duration_with_idle_times for stating a scheduling problem with resource choice and variable durations:
model "Scheduling with alternative resources"
 uses "kalis", "mmsystem"

 setparam("KALIS_DEFAULT_LB", 0)
 setparam("KALIS_VERBOSE_LEVEL", 1)

 declarations
  JOBS: set of string                       ! Index set of jobs
  TEAMS: set of string                      ! Index set of teams (resources)
  DURATIONS: array(JOBS, TEAMS) of integer  ! Durations of JOBS for each team
  POSSIBLE_TEAMS: array(JOBS) of set of string  ! Possible team for each task
  PRECEDENCES: list of list of string       ! Pairs of precedence constraints
  SOFT_BREAKS: array(TEAMS) of list of list of integer  ! Start and end times
                                            ! of soft breaks for each team
  ALLOW_START_IN_IDLE: boolean

  job: array(JOBS) of cptask                ! Jobs
  team: array(TEAMS) of cpresource          ! Teams

  procedure print_and_check_solution
  function get_actual_duration(j: string, t: string, start: integer): integer
 end-declarations

 ! **************** Data ****************
 ! -1 duration indicates the team cannot process the task
 DURATIONS::(["J0", "J1", "J2", "J3", "J4", "J5", "J6", "J7", "J8", "J9",
     "J10", "J11", "J12", "J13", "J14", "J15", "J16", "J17"],
    ["T1", "T2", "T3"])[
       2, -1,  2,
      16, 14, 15,
       9, -1,  8,
       8,  5,  8,
      10, 11,  8,
       6,  5,  7,
      -1,  3,  4,
       2,  1,  2,
       9,  6,  9,
       5,  7, -1,
       3, -1,  1,
       2,  3,  3,
       1, -1,  1,
       7,  4,  7,
       4,  6,  4,
       3,  2,  1,
       9,  9, -1,
       1,  2,  3]

 forall(j in JOBS)
  POSSIBLE_TEAMS(j) := union(t in TEAMS | DURATIONS(j, t) <> -1) {t}

 PRECEDENCES:= [ ["J1", "J0"], ["J2", "J1"], ["J3", "J1"], ["J13", "J1"],
       ["J4", "J2"], ["J5", "J3"], ["J6", "J3"], ["J8", "J3"],
       ["J9", "J3"], ["J14", "J3"], ["J5", "J4"], ["J7", "J5"],
       ["J8", "J5"], ["J10", "J5"], ["J12", "J6"], ["J15", "J7"],
       ["J11", "J8"], ["J15", "J10"], ["J16", "J11"],
       ["J14", "J13"], ["J15", "J13"], ["J17", "J16"]]

 SOFT_BREAKS::(["T1", "T2", "T3"]) [[[10, 25], [42, 52]], [[15, 37]],
       [[25, 35], [45, 58]]]
 ALLOW_START_IN_IDLE := true

 ! **************** Problem formulation ****************
 ! Define discrete resources
 forall(t in TEAMS) do
  set_resource_attributes(team(t), KALIS_DISCRETE_RESOURCE, 1)
  team(t).name := t
 end-do

 ! Define possible teams for each task
 forall(j in JOBS) do
  job(j).name := j
  requires(job(j), union(t in POSSIBLE_TEAMS(j)) {resusage(team(t), 1)})
 end-do

 ! Define associated duration for each task
 forall(j in JOBS) do
  ! Initialize duration bounds
  setdomain(getduration(job(j)),
      min(t in POSSIBLE_TEAMS(j)) DURATIONS(j, t),
      max(t in POSSIBLE_TEAMS(j)) DURATIONS(j, t))

  forall(t in POSSIBLE_TEAMS(j)) do
   ! Set nominal duration
   setduration(team(t), job(j), DURATIONS(j, t))
   ! Update the actual duration with idle times
   forall(b in SOFT_BREAKS(t))
    update_duration_with_idle_times(team(t), job(j), b.first, b.last,
     ALLOW_START_IN_IDLE)
  end-do
 end-do
 ! Display all constraints involving the duration of task 'J0'
 cp_show_var_constraints(getduration(job("J0")))

 ! Define precedences
 forall(j in JOBS)
  setpredecessors(job(j), union(p in PRECEDENCES | p(1) = j) {job(p.last)})

 cp_close_schedule

 ! **************** Solving ****************
 ! Perform constraint propagation
 if not cp_propagate then
  writeln("Problem is infeasible")
  exit(1)
 end-if

 setparam("KALIS_MAX_COMPUTATION_TIME", 10)

 ! Solve the problem
 if cp_schedule(getmakespan)=0 then
  writeln("No solution")
  exit(0)
 end-if

 ! Solution printing
 print_and_check_solution

! **************** Subroutine definitions ****************
 procedure print_and_check_solution
  declarations
   starts: array(JOBS) of integer
   ends: array(JOBS) of integer
   operating_teams: array(JOBS) of string
  end-declarations

  ! Display the solution
  writeln("makespan=", getsol(getmakespan))
  forall(j in JOBS) do
   starts(j) := getsol(getstart(job(j)))
   ends(j) := getsol(getend(job(j)))
   forall(t in POSSIBLE_TEAMS(j) | getsol(getassignment(job(j),team(t)))>0) do
    operating_teams(j) := t
    break
   end-do
   writeln(formattext("%3s: %2d - %2d team=%s", j, starts(j), ends(j),
    operating_teams(j)))
  end-do

  ! Check solution
  forall(j in JOBS | operating_teams(j) not in TEAMS)
   writeln("Error: ", j, " doesn't have an operating team.")

  forall(p in PRECEDENCES | starts(getfirst(p)) < ends(getlast(p)))
   writeln("Error: Precedence constraint ", p, " is violated.")

  forall(j in JOBS | starts(j) + get_actual_duration(j, operating_teams(j),
                     starts(j)) <> ends(j))
   writeln("Error: Job ", j, " has a wrong duration.")

  if max(j in JOBS) ends(j) <> getsol(getmakespan) then
   writeln("Error: Objective value is different from computed makespan value.")
  end-if
 end-procedure

 ! **** Return the actual duration of a job given its team and start
 function get_actual_duration(j: string, t: string, start: integer): integer
  expected_end := start + DURATIONS(j, t)
  forall(b in SOFT_BREAKS(t)) do
    if start >= b.last then
     next
    end-if
    ! Adding soft break duration
    if expected_end > b.first then
     expected_end += b.last - maxlist(start, b.first)
    end-if
  end-do
  returned := expected_end - start
 end-function

end-model

Related topics

© 2001-2024 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.