%%ampl_eval
# Donor Exchange
reset;
### SETS
param N;
set Blood; # set of blood types (b)
set PATIENTS := {1..N} ordered; # set of patients (i)
set DONORS; # set of donors (j)
set ALL:= PATIENTS union DONORS; # set of patients union donors (ij)
set Transpl; # type of transplant {tr}
set BLOOD within {Blood, Blood}; # possible transplant options by blood type compatibility
set PAT_DON within {PATIENTS, DONORS}; # donor-patient relationship
set TRANSPL_HUM within {ALL,Transpl}; # type of transplant assigned to a PATIENTS and DONORS
set BLOOD_HUM within {ALL, Blood}; # PATIENTS and DONORS blood type
# patients data: patient(i),type of transplant(tr), blood type(b)
set PATIENTS_:= setof {(i,tr) in TRANSPL_HUM, (i,b) in BLOOD_HUM: i in PATIENTS} (i,tr,b);
# donors data: relationship between patient(i) & donor(j), possible type of transplant(tr), blood type(b)
set DONORS_:= setof {(j,tr) in TRANSPL_HUM, (j,b) in BLOOD_HUM, (i,j) in PAT_DON:j in DONORS}(i,j,tr,b);
### a set of options for possible assignments:
# donor(j) of the patient(ii) who can be assigned to the patient(i) as it is compatible in type of transplantation(tr) and terms of blood type(b1 and b2)
set LINKS_:= setof {(ii,tr,b1) in PATIENTS_, (i,j,tr,b2) in DONORS_:(b1,b2) in BLOOD}(i,j,ii,tr,b1);
### a set of options for possible assignments:
# donor(j) of the patient(ii) who can be assigned to the patient(i) as it is compatible in type of transplantation(tr) and terms of blood type(b1 and b2)
set LINKS:= setof {(ii,tr,b1) in PATIENTS_, (i,j,tr,b2) in DONORS_:(b1,b2) in BLOOD}(i,j,ii,tr,b1,b2);
### a set of options for possible assignments TWO donors for ONE patient:
# a patient (i) with a blood type (b1) can receive 2 parts of the transplant (tr) from donors (j1 and j2) with a compatible blood type (b2, b3)
set PAT_2DON:= setof {(i,j1,ii,tr,b1,b2) in LINKS, (i,j2,tr,b3) in DONORS_:(b1,b3) in BLOOD and (b2,b3) in BLOOD and j1 != j2} (i,j1,j2,tr,b1,b2,b3);
### To simplify the model, the compatibility of donors and patients is checked only by blood type. If necessary, you can add a check of additional criteria for the compatibility of donors and patients. ###
### PARAMETERS
param Clusters:= last(PATIENTS); # create a transplantation cluster for each patient. The introduction of the cluster guarantees simultaneous operation for the donor and his patient.
param demand {(i,tr,b) in PATIENTS_} >= 0; # required number of surgeries for a patient
### VARIABLES
var X {PATIENTS, 1..Clusters} binary; # assigning a patient to an ceparate organ(s) transplant cluster. Clusters are introduced to ensure simultaneous operation for the donor and his client.
var Y {LINKS_, 1..Clusters} binary; # assignment of donors and transplant patients
### OBJECTIVE
# Maximize the number of transplants
maximize Total: sum {i in PATIENTS, c in 1..Clusters} X [i,c];
### REQUIREMENTS
subject to
# for each cluster, supply - demand >= 0;
A {c in 1..Clusters,tr in Transpl, b in Blood}: sum{(i,j,ii,tr,b) in LINKS_} Y[i,j,ii,tr,b,c] - sum {(i,tr,b) in PATIENTS_} demand[i,tr,b] * X[i,c] >= 0; # you can put =
# a patient can only be part of one cluster
A_1 {i in PATIENTS}: sum {c in 1..Clusters} X[i,c] <= 1;
# for each type of operation of the patient in all clusters, only one donor is assigned.
A_2 {ii in PATIENTS, tr in Transpl}:sum{c in 1..Clusters, (i,j,ii,tr,b) in LINKS_} Y[i,j,ii,tr,b,c] <= 1;
# Limiting the number of patients in 1 cluster.
A_3 {c in 1..Clusters}: sum {i in PATIENTS} X[i,c] <= 3;
# A donor can participate in an organ transplant operation only 1 time
A_4 {j in DONORS, tr in Transpl}: sum{c in 1..Clusters, (i,j,ii,tr,b) in LINKS_} Y[i,j,ii,tr,b,c] <= 1;
# Limiting the number of operations in the cluster (it is assumed that after assigning a donor for transplantation, another operation is performed with the patient)
A_5 {c in 1..Clusters}: sum{(i,j,ii,tr,b) in LINKS_} Y[i,j,ii,tr,b,c]*2 <= 6;