Optimization Nurse Assignment - oop

I'm new in CPLEX Optminization and at the moment, I'm writing a model that should assign nurses to surgery cases that fit their competences, specialty…
Actually I thought that the model is working correctly, but when I am trying it, it assigns nurses to cases, in which they are not allowed to work.
I hope somebody here will make time to look at the model and can help me. So here is the existing model (very easy at the moment with 5 nurses and one case):
.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 ;
}
dat.
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 ;
When I run it, it assigns the second nurse to the case, but actually the nurse 2 is not allowed to work in this case because a RN is needed. I already tried different possibilities to write it, but I don't find the reason why…
At the moment, nurse 1 and nurse 4 are assigned as RN (which is right) and additionally also Nurse 2.
Can anybody give me some tipps or help to solve the optimization problem correctly? I would be very grateful, thank you in advance.

Your model is not feasible and CPLEX relaxed it. It relaxed some labeled constraints and gave you the relaxed solution. Having a look at the relaxed solution will help you debug your model.
In cplex documentation you could have a look at:
IDE and OPL > CPLEX Studio IDE > IDE Tutorials
Relaxing infeasible models

Related

How to iterate complex numbers on the Riemann sphere in Maxima CAS?

I try to iterate complex numbers ( also inf and zero) in Maxima CAS
I use rational function and it's derivative
The only one attracting cycle is the period 3-cycle consisting of the points 0, −1, and infinity.
kill(all);
display2d:false;
ratprint : false; /* remove "rat :replaced " */
define(f(z), (1 -z^2)/(z^2));
F(z0):= block(
[z],
if is(z0 = 0) then z: limit(f(z),z,0)
elseif is(z0 = infinity) then z: limit(f(z),z,inf)
else z:f(z0),
return(z)
)$
define( dz(z), ratsimp(diff(f(z),z,1)));
Dz(z0) := block(
[m],
if is(z0 = 0) then m: limit(dz(z),z,0)
elseif is(z0 = infinity) then m: limit(dz(z),z,inf)
else m:dz(z0),
return(m)
)$
GiveStability(z0, p):=block(
[z,d],
/* initial values */
d : 1,
z : z0,
for i:1 thru p step 1 do (
d : Dz(z)*d,
z: F(z),
print("i = ", 0, " d =",d, " z = ", z)
),
return (d)
)$
GiveStability(-1,3);
The simple computations work fine:
F(0);
(%o10) inf
(%i11) F(-1);
(%o11) 0
(%i12) F(infinity);
(%o12) -1
(%i13) Dz(0);
(%o13) infinity
(%i14) Dz(infinity);
(%o14) 0
(%i15) Dz(-1);
(%o15) 2
But when I try to use the las t functionL
a:GiveStability(-1,3);
i = 0 d = 2 z = 0
expt: undefined: 0 to a negative exponent.
#0: dz(z=0)
#1: Dz(z0=0)
#2: GiveStability(z0=-1,p=3)
-- an error. To debug this try: debugmode(true);
How should I do it properly ?

numpy return indices using multiple conditions of UNKNOWN number

Consider two arrays (X and Y), X is a 2D data array (grayscale image), and Y is an array of conditions where array X needs to be filtered based on, as follows:
X = np.array([[0,0,0,0,4], [0,1,1,2,3], [1,1,2,2,0], [0,0,2,2,3], [0,0,0,0,0]])
Y = np.array([1,2,3])
X:
[[0 0 0 0 4]
[0 1 1 2 3]
[1 1 2 2 0]
[0 0 2 2 3]
[0 0 0 0 0]]
Y:
[1 2 3]
I need to select the elements/indices of array X based on the values in array Y, such that:
Z = np.argwhere((X == Y[0]) | (X == Y[1]) | (X == Y[2]))
Z:
[[1 1]
[1 2]
[1 3]
[1 4]
[2 0]
[2 1]
[2 2]
[2 3]
[3 2]
[3 3]
[3 4]]
This can be done using a loop over the items of array Y, is there a numpy function to achieve this?
It is also achievable using multiple conditions in a np.argwhere function, however, the number of conditions (length of array Y ) is unknown beforhand.
Thanks
The key is to prepare the correct mask. For that, use numpy.isin:
np.isin(X, Y)
You'll get a boolean mask as a result, of the same shape X has. Now you can get the indices using an appropriate method.

How do I put values od dataframe column in 2d matrix?

I have the pandas dataframe with 3 columns value, row_index, column_index. I would like to create a matrix, where values of dataframe placed at relevant rows and columns and unknown elements are zeros.
I have made a for-cycle like this:
N_rows = df.row_index.max()
N_cols = df.column_index.max()
A = np.zeros((N_rows, N_cols))
for i in df.row_index:
for j in df.column_index:
np.put(A, i*N_cols+j, df['value'][(df.row_index==i) &
(df.column_index==j)])
but it works very slow.
How can I do it faster?
I think you need pivot with fillna and for missing values of columns and rows add reindex, last for numpy array add values:
df = pd.DataFrame({'value':[2,4,5],
'row_index':[2,3,4],
'col_index':[0,2,3]})
print (df)
col_index row_index value
0 0 2 2
1 2 3 4
2 3 4 5
rows = np.arange(df.row_index.max()+1)
cols = np.arange(df.col_index.max()+1)
print (df.pivot('row_index', 'col_index', 'value')
.fillna(0)
.reindex(index=rows, columns=cols, fill_value=0))
col_index 0 1 2 3
row_index
0 0.0 0.0 0.0 0.0
1 0.0 0.0 0.0 0.0
2 2.0 0.0 0.0 0.0
3 0.0 0.0 4.0 0.0
4 0.0 0.0 0.0 5.0
a = df.pivot('row_index', 'col_index', 'value')
.fillna(0)
.reindex(index=rows, columns=cols, fill_value=0)
.values
print (a)
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 2. 0. 0. 0.]
[ 0. 0. 4. 0.]
[ 0. 0. 0. 5.]]
Another solution with set_index and unstack:
print (df.set_index(['row_index', 'col_index'])['value']
.unstack(fill_value=0)
.reindex(index=rows, columns=cols, fill_value=0))
col_index 0 1 2 3
row_index
0 0 0 0 0
1 0 0 0 0
2 2 0 0 0
3 0 0 4 0
4 0 0 0 5
a = df.set_index(['row_index', 'col_index'])['value']
.unstack(fill_value=0)
.reindex(index=rows, columns=cols, fill_value=0)
.values
print (a)
[[0 0 0 0]
[0 0 0 0]
[2 0 0 0]
[0 0 4 0]
[0 0 0 5]]
Just modifying a minor part in #jezrael's solution. You can actually use Pandas as_matrix() functions to get the arrays:
df = pd.DataFrame({'value':[2,4,5],
'row_index':[2,3,4],
'col_index':[0,2,3]})
df.pivot('row_index', 'col_index', 'value').fillna(0).as_matrix()
# array([[ 2., 0., 0.],
# [ 0., 4., 0.],
# [ 0., 0., 5.]])

awk code to calculate throughput for some nodes

In ns-2 trace files for wireless nodes, I want to calculate throughput for some nodes at once. How to make if condition for specific nodes? The problem is because of "_" between node number. It is very time consuming if I check node one by one because of thousands number of nodes. Here the example of trace files :
r 1.092948833 _27_ MAC --- 171 tcp 1560 [0 1a 19 0] ------- [4194333:0 4194334:0 32 4194334] [37 0] 1 0 [-]
r 1.092948833 _28_ MAC --- 172 tcp 1560 [0 1a 19 0] ------- [4194333:0 4194334:0 32 4194334] [38 0] 1 0 [-]
r 1.092948833 _25_ MAC --- 173 tcp 1560 [0 1a 19 0] ------- [4194333:0 4194334:0 32 4194334] [39 0] 1 0 [-]
r 1.092948833 _21_ MAC --- 174 tcp 1560 [0 1a 19 0] ------- [4194333:0 4194334:0 32 4194334] [40 0] 1 0 [-]
r 1.092948833 _36_ MAC --- 175 tcp 1560 [0 1a 19 0] ------- [4194333:0 4194334:0 32 4194334] [41 0] 1 0 [-]
r 1.092948833 _29_ MAC --- 176 tcp 1560 [0 1a 19 0] ------- [4194333:0 4194334:0 32 4194334] [42 0] 1 0 [-]
My awk code :
action = $1;
sta = $3;
time = $2;
dest = $4;
app = $7;
pkt_size = $8;
if ( action == "r" && dest == "MAC" && app == "tcp" && time > 1 && ((sta >= "_6_"
&& sta <= "_30_") || (sta >= "_36_"))) {
if (start_ == 0) start_ = time;
if (time > end_) end_ = time;
sum_ = sum_ + pkt_size;
}
But it doesn't work
You appear to be doing something like:
if ($1=="r" && $7=="cbr" && $3=="_1_") {
sec[int($2)]+=$8;
};
from the fil2.awk in a paper titled "ns-2 for the impatient".
Though you want to match on different fields, and match on a range of nodes, I'm going to assume you want output similar to:
sec[i] throughput[i]
from the same paper where sec[i] is the second and throughput[i] here would be like your sums for each second's worth of packet sizes.
The sec array from that snippet is storing packet sums for rounded seconds (rounding provided by int()) which means you don't need a start_ or end_.
Since you want to compare multiple nodes, _ can be added to FS to make comparisons easier. Here's a version of your script modified to produce an output over seconds for the nodes you want to compare binned by seconds:
#!/usr/bin/awk -f
BEGIN {FS="[[:space:]]|_"} # use posix space or underscore for FS
{
action = $1
time = $2
sta = $4 # shifted here because underscores are delimiters
dest = $6
app = $10
pkt_size = $11
if( action == "r" && dest == "MAC" && app == "tcp" &&
time > 1 && ((sta >= 6 && sta <= 30) || (sta >= 36))) {
sec[int(time)]+=pkt_size
}
}
END { for( i in sec ) print i, sec[i] }
Notice that the sta tests are numeric now instead of string comparisons. If I put that into an executable awk file called awko and run as awko data against your data I get:
1 9360
as the output.

How to create cartesian product [duplicate]

This question already has answers here:
Generate all possible n-character passwords
(4 answers)
Closed 1 year ago.
I have a list of integers, a = [0, ..., n]. I want to generate all possible combinations of k elements from a; i.e., the cartesian product of the a with itself k times. Note that n and k are both changeable at runtime, so this needs to be at least a somewhat adjustable function.
So if n was 3, and k was 2:
a = [0, 1, 2, 3]
k = 2
desired = [(0,0), (0, 1), (0, 2), ..., (2,3), (3,0), ..., (3,3)]
In python I would use the itertools.product() function:
for p in itertools.product(a, repeat=2):
print p
What's an idiomatic way to do this in Go?
Initial guess is a closure that returns a slice of integers, but it doesn't feel very clean.
For example,
package main
import "fmt"
func nextProduct(a []int, r int) func() []int {
p := make([]int, r)
x := make([]int, len(p))
return func() []int {
p := p[:len(x)]
for i, xi := range x {
p[i] = a[xi]
}
for i := len(x) - 1; i >= 0; i-- {
x[i]++
if x[i] < len(a) {
break
}
x[i] = 0
if i <= 0 {
x = x[0:0]
break
}
}
return p
}
}
func main() {
a := []int{0, 1, 2, 3}
k := 2
np := nextProduct(a, k)
for {
product := np()
if len(product) == 0 {
break
}
fmt.Println(product)
}
}
Output:
[0 0]
[0 1]
[0 2]
[0 3]
[1 0]
[1 1]
[1 2]
[1 3]
[2 0]
[2 1]
[2 2]
[2 3]
[3 0]
[3 1]
[3 2]
[3 3]
The code to find the next product in lexicographic order is simple: starting from the right, find the first value that won't roll over when you increment it, increment that and zero the values to the right.
package main
import "fmt"
func main() {
n, k := 5, 2
ix := make([]int, k)
for {
fmt.Println(ix)
j := k - 1
for ; j >= 0 && ix[j] == n-1; j-- {
ix[j] = 0
}
if j < 0 {
return
}
ix[j]++
}
}
I've changed "n" to mean the set is [0, 1, ..., n-1] rather than [0, 1, ..., n] as given in the question, since the latter is confusing since it has n+1 elements.
Just follow the answer Implement Ruby style Cartesian product in Go, play it on http://play.golang.org/p/NR1_3Fsq8F
package main
import "fmt"
// NextIndex sets ix to the lexicographically next value,
// such that for each i>0, 0 <= ix[i] < lens.
func NextIndex(ix []int, lens int) {
for j := len(ix) - 1; j >= 0; j-- {
ix[j]++
if j == 0 || ix[j] < lens {
return
}
ix[j] = 0
}
}
func main() {
a := []int{0, 1, 2, 3}
k := 2
lens := len(a)
r := make([]int, k)
for ix := make([]int, k); ix[0] < lens; NextIndex(ix, lens) {
for i, j := range ix {
r[i] = a[j]
}
fmt.Println(r)
}
}