0

我是 CPLEX 优化的新手,目前,我正在编写一个模型,该模型应该将护士分配给适合其能力、专业的手术病例……</p>

实际上我认为该模型工作正常,但是当我尝试它时,它会将护士分配给不允许他们工作的病例。

我希望这里有人能抽出时间来看看这个模型并能帮助我。所以这是现有的模型(目前非常简单,有 5 名护士和 1 个病例):

.mod:

  // indices

    tuple nurses {
      key int number_nurses ;
      string roles ;
      string specialty ;
      string compentency ;
      int shift_start ;
      int shift_end ;
      }  

 tuple shifts {
 int shift_start ;
 int shift_end ;
 }
 {shifts} shift = ... ;

 {nurses} nurse = ... ;

 int  j = ... ;
 range available_ORs = 1..j ;


 {string} roles = ... ;

 {string} specialty = ... ;

 tuple cases {
  key int number_cases ;
  int start_time ;
  int end_time ;
  int duration ;
  int demand_RN ;
  int demand_ST ;
  int available_ORs ;
  string specialty_needed ;
  string competency_needed ;
}
 {cases} case = ... ;

 //{string} shifts = ... ;

 {string} competency = ... ;

 int h = ... ;
 range time_intervals = 1..h ;

 // parameters

 int P1 [nurse][shift] = ... ;
 int P2 [nurse][roles][specialty][competency] = ... ;
 int P3 [case][available_ORs] = ... ;
 int P4 [time_intervals][case][specialty][competency] = ... ;    // Auf Complexity innerhalb des Cases zugreifen
 int P5 [time_intervals][case][roles] = ... ;
 int P6 [case][time_intervals] = ... ;
 int P7 [case] = ... ;
 int P8 [time_intervals][shift] = ...;
 int M = ... ;

 // decision variables

 dvar boolean y [nurse][case][roles][time_intervals] in 0..1 ;      // 1: Nurse is assigened to case to perform role in time interval, 0: otherwise
 dvar boolean x [nurse][case][roles] in 0..1 ;

 dvar int de [time_intervals][case][roles] in 0..1 ;      
 dvar int dev [time_intervals][nurse] in 0..1  ;
 dvar int dev2 [nurse][time_intervals] in 0..1 ;
 dvar int xdev [nurse][available_ORs] in 0..1  ;
 dvar int nc [nurse][case] in 0..1  ;
 dvar int cd [nurse][case] in 0..1  ;

  // deviation variable

  dvar int DE ;
  dvar int DS ;
  dvar int DF ;
  dvar int XDEV ;
  dvar int NCT ;
  dvar int CDT ;


 // Objective function

  minimize (DE+DF+DS+XDEV+NCT+CDT) ;

 // Hard Constraints

  subject to {

   forall (i in nurse, h in time_intervals)
     cons_01:      // each nurse is assigned to at most one case in each time interval and performs a single role
     sum (c in case,k in roles) y[i][c][k][h] <= 1 ;

   forall (i in nurse, c in case, k in roles, h in time_intervals)
    cons_02:      // in each shift, cases will be assigned to the nurses who are working during their regular or authorized overtime hours
     y[i][c][k][h] <= sum (s in shift) ((P1[i][s])*P8[h][s]) ;

   forall (i in nurse)
     cons_03:      //total working hours for a nurse each day must be less than his or her total regular and overtime working hours
     sum (c in case, k in roles, h in time_intervals) y[i][c][k][h] <= sum (s in shift, h in time_intervals) ((P1[i][s])*P8[h][s]) ;

   forall (i in nurse, c in case, k in roles, h in time_intervals)
     cons_04:      // assigned to a case only if their skill level is high enough to handle the specialty requirements and have sufficient competency to deal with its procedural complexities
     y[i][c][k][h] <= P6[c][h]*sum (q in specialty, p in competency) (P4[h][c][q][p]*P2[i][k][q][p]) ;

   forall (c in case, k in roles, h in time_intervals)
     cons_05:      // see cons_04
     sum (i in nurse) y[i][c][k][h] >= P6[c][h] ;

   forall (i in nurse, c in case, k in roles)
     cons_06:      //nurses perform the same role for the entire duration of a case
     sum (h in time_intervals) y[i][c][k][h] <= M * x[i][c][k] ;

   forall (i in nurse, c in case)
     cons_07:      // see cons_06
     sum (k in roles) x[i][c][k] <= 1 ;

  }


  // soft constraints 
  subject to {


    forall (c in case, k in roles, h in time_intervals)
     cons_08:      // permit undercoverage, preferred that nurses work continuously during their regular hours rather than having idle perijjjods
     sum (i in nurse) y[i][c][k][h] * de[h][c][k] >= P5[h][c][k] * P6[c][h] ; //momentan zu viele nurses, daher zu viele Zuordnungen

   forall (c in case, k in roles)
     cons_09:      // see cons_08
     DE >= sum (h in time_intervals) de[h][c][k] ;

   /*forall (i in nurse, h in time_intervals)
     cons_10:      // avoid idle times: maximum number of times that nurses work nonconsecutive hours will be minimized along with idle time hours during the shift
   -dev[h][i] <= sum (c in case, k in roles) y[i][c][k][h+1] - sum (c in case, k in roles) y[i][c][k][h] <=dev[h][i] ;*/


 forall (i in nurse)
   cons_11:      // see cons_10
     DS >= sum (h in time_intervals) dev[h][i] ;

   forall(i in nurse, j in available_ORs)
     cons_12:      // account for the preference that nurses work continuously in one operating room: maximum number of ORs is reduced as much as possible
     sum (c in case, k in roles, h in time_intervals) (y[i][c][k][h] * P3[c][j]) <= M * xdev[i][j] ;

   forall (i in nurse)
     cons_13:     // see cons_12
     sum (j in available_ORs) xdev[i][j] <= XDEV ;

   forall (i in nurse, h in time_intervals)
     cons_14:      // record overtime: maximum number of times a nurse is working during overtime is as low as possible
     sum (s in shift) P1[i][s] * 1 * sum (c in case, k in roles) y [i][c][k][h] <= dev2[i][h] ;

   forall (i in nurse)
     cons_15:      // see cons_14
     DF >= sum (h in time_intervals) dev2[i][h] ;

   forall (i in nurse, c in case)
     cons_16:      // if nurse assigned to surgery, (s)he will stay for entire duration of the case unless there is a greater need for that nurse elseway, limit the movement of nurses between cases
     sum (k in roles, h in time_intervals) y[i][c][k][h] - P7[c] + M * cd[i][c] + M * (1 - nc[i][c]) >= 0 ;

   forall (i in nurse, c in case)
     cons_17:      // see cons_16
     sum (k in roles, h in time_intervals) y[i][c][k][h] <= M * nc[i][c] ;

   forall (i in nurse)
     cons_18:      // see cons_16
     sum (c in case) nc[i][c] <= NCT ;

   forall (i in nurse)
     cons_19:      // see cons_16
     sum (c in case) cd[i][c] <= CDT ;

  }

日期。

 nurse = {                          
    < 1, "RN", "cardio", "high", 6, 14 > ,
    < 2, "ST", "cardio", "high", 10, 18 > ,
    < 3, "RN", "neuro", "high", 14, 22 > ,
    < 4, "RN", "cardio", "intermediate", 14, 22 > ,
    < 5, "RN", "cardio", "high", 22, 6 > ,
    } ;

 j = 2 ;

 roles = { "RN" , "ST" } ; // RN can work as ST if necessary, but a ST can not work as RN

 specialty = { "ortho", "neuro", "cardio" } ;

 case = {                       
    < 1, 8, 15, 7, 1, 0, 1, "cardio", "intermediate" > , 
    } ;

  shift = { < 6, 14 > < 10, 18 > < 14, 22 > < 22, 6 >} ;

  competency = { "low", "intermediate", "high" } ;  

  h  = 24 ;     

  // Parameter

  P1 = [
  [1 0 0 0]
  [0 1 0 0]
  [0 0 1 0]
  [0 0 1 0]
  [0 0 0 1]
  ] ;

  P2 = [
  [[[1 1 1][0 0 0][0 0 0]][[1 1 1][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]][[1 1 1][0 0 0][0 0 0]]]
  [[[0 0 0][1 1 1][0 0 0]][[0 0 0][1 1 1][0 0 0]]]
  [[[1 1 0][0 0 0][0 0 0]][[1 1 0][0 0 0][0 0 0]]]
  [[[1 1 1][0 0 0][0 0 0]][[1 1 1][0 0 0][0 0 0]]]
  ] ;

  P3 = [
  [1 0]
  ] ;

  P4 = [
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 1 0][0 0 0][0 0 0]]]
  [[[0 1 0][0 0 0][0 0 0]]]
  [[[0 1 0][0 0 0][0 0 0]]]
  [[[0 1 0][0 0 0][0 0 0]]]
  [[[0 1 0][0 0 0][0 0 0]]]
  [[[0 1 0][0 0 0][0 0 0]]]
  [[[0 1 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  [[[0 0 0][0 0 0][0 0 0]]]
  ] ;

  P5 = [
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[1 0]]
  [[1 0]]
  [[1 0]]
  [[1 0]]
  [[1 0]]
  [[1 0]]
  [[1 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  [[0 0]]
  ] ;

  P6 = [
  [0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 ]
  ] ;

  P7 = [7] ;



  P8 = [
  [0 0 0 1]
  [0 0 0 1] 
  [0 0 0 1] 
  [0 0 0 1] 
  [0 0 0 1] 
  [1 0 0 0] 
  [1 0 0 0] 
  [1 0 0 0] 
  [1 0 0 0] 
  [1 1 0 0] 
  [1 1 0 0] 
  [1 1 0 0] 
  [1 1 0 0] 
  [0 1 1 0] 
  [0 1 1 0] 
  [0 1 1 0] 
  [0 1 1 0] 
  [0 0 1 0] 
  [0 0 1 0] 
  [0 0 1 0] 
  [0 0 1 0] 
  [0 0 0 1] 
  [0 0 0 1] 
  [0 0 0 1] 
  ] ;

  M = 10 ;

当我运行它时,它会将第二名护士分配给该案例,但实际上在这种情况下不允许护士 2 工作,因为需要 RN。我已经尝试了不同的可能性来写它,但我找不到原因……</p>

目前,护士 1 和护士 4 被分配为 RN(这是正确的),另外还有护士 2。

任何人都可以给我一些提示或帮助正确解决优化问题吗?我将不胜感激,在此先感谢您。

4

1 回答 1

0

您的模型不可行,CPLEX 放宽了它。它放宽了一些标记的约束,并为您提供了轻松的解决方案。查看轻松的解决方案将帮助您调试模型。

在 cplex 文档中,您可以查看:

  • IDE 和 OPL > CPLEX Studio IDE > IDE 教程

  • 放松不可行的模型

于 2018-06-13T07:43:01.640 回答