Enhancing Rowing Performance Through Data: Insights from Okeanos' SAS Integration
Recent Library Articles
Recently in the SAS Community Library: Ready to dive into the future of rowing? @Nazira shows you how Okeanos, Amsterdam's top rowing club, is making waves with SAS sports analytics.
Hi, I'm working on a code based on VRP and I have got answer that is making sense with the following code proc optmodel;
/* Sets and Parameters */
set P = 1..5; /* Set of 5 patients */
NUM n = card(P);
number d{P,P} = [
0 42.00467295 44.15950104 23.43200516 41.38762733
42.00467295 0 3.50018558 18.70469082 0.767077531
44.15950104 3.50018558 0 21.17540754 3.583323032
23.43200516 18.70469082 21.17540754 0 18.13469416
41.38762733 0.767077531 3.583323032 18.13469416 0
]
; /* Distance between patients */
number service{P}; /* Service time for each patient */
number w1 = 23.25; /* Telehealth wage per hour */
number w2 = 26; /* Fixed wage for traveling nurse (for 40 hours) */
number speed = 60; /* Vehicle speed (km/h) */
number c_fuel = 0.2; /* Fuel cost per km */
number T_max = 40; /* Maximum working hours */
service[1] = 21; service[2] = 21.5; service[3] = 17;
service[4] = 19.5; service[5] = 13;
/* Decision Variables */
var x{P} binary; /* 1 if telehealth nurse serves patient, 0 otherwise */
var y{P,P} binary; /* 1 if traveling nurse route used between patients i and j */
var u{P} >= 0; /* Order of visits for each location */
/* Objective Function: Minimize total cost */
minimize TotalCost =
/* Telehealth nurse cost: service time * hourly wage */
sum{i in P} x[i] * service[i] * w1 +
/* Traveling nurse fixed wage */
sum{i in P} (1 - x[i]) * 40 * w2 +
/* Fuel cost for traveling routes */
sum{i in P, j in P: i < j} y[i,j] * d[i,j] * c_fuel;
/* Constraints */
/* Each patient must be assigned to either a telehealth or traveling nurse */
con AssignPatient{i in P}:
x[i] + sum{j in P: i ne j} y[i,j] = 1;
/* Limit total working hours */
con WorkingHours_travelling:
sum{i in P, j in P: i ne j} y[i,j] * (d[i,j] / speed) + sum{i in P} (1 - x[i]) * (service[i] / 2) <= T_max;
con WorkingHours_tele:
sum{i in P} x[i] * service[i] <= T_max;
/* Vehicle capacity constraint: no more than 8 traveling nurses */
con VehicleLimit:
sum{i in P} (1 - x[i]) <= 8;
/* Solve the problem */
solve;
/* Print results */
print TotalCost;
print x y u;
quit; However, the current code doesn't tell me what is the order of vehicle travelling so I am adding another variable u in for the order plus some flow conservation and sub tour elimination. What I added in worked well before with a simple VRP problem. However, it seems to mess up and make my model give Infeasible solution. I am not sure if what i have added is incorrect or it was my original code that is somehow wrong so it is not compatible with what I've added in. NUM n = card(P); var u{P} >= 0; /* Order of visits for each location */ /* Flow constraints for VRP */
/* Define flow in and out of all nodes */
impvar FlowOut {i in P} = sum {j in P: i ne j} y[i,j];
impvar FlowIn {j in P} = sum {i in P: i ne j} y[i,j];
/* Arrival and Departure Constraints */
con Arrival_con {i in P}: FlowIn[i] = 1;
con Departure_con {j in P}: FlowOut[j] = 1;
/* Subtour elimination constraints */
con Subtour_elimination_con {i in P, j in P: i ne j}:
u[i] - u[j] + n * y[i,j] <= n - 1;
con u_restrict1_con {i in P}: u[i] >= 1;
con u_restrict2_con {i in P}: u[i] <= n - 1; print x y u;
... View more
Hello SAS Community,
I am working on a project where I need to match subjects based on age using PROC PSMATCH.
However, I require some flexibility in the matching criteria. Specifically, I need to match subjects such that their ages can differ by up to 0.1 years.
I found that the EXACT statement in PROC PSMATCH specifies classification variables to be matched exactly, but this does not meet my requirement for age matching with a small tolerance.
Does anyone know how to implement this in PROC PSMATCH? Any guidance or examples would be greatly appreciated!
Thank you in advance for your help!
... View more
My SAS code is generating semantic error. It is saying ERROR: The array element 'travel_time[1,2]' has no value at line 228 column 57. I am not sure what that means. I believe the data is completed and has been loaded in correctly. /* Patient data: duration of treatment and revenue */
data patient_data;
input i duration revenue;
datalines;
1 12 200
2 45 181
3 90 255
4 26 150
5 75 220
6 60 200
7 45 180
8 120 300
9 90 250
10 30 158
;
run;
/* Travel times between patients (symmetric for simplicity) */
data travel_times;
input i j t;
datalines;
1 2 15
1 3 20
1 4 25
1 5 30
1 6 3.5
1 7 11
1 8 26
1 9 12
1 10 26
2 3 10
2 4 18
2 5 22
2 6 10
2 7 3
2 8 4
2 9 5.5
2 10 15
3 4 12
3 5 15
3 6 10
3 7 25
3 8 30
3 9 22
3 10 12
4 5 8
4 6 23
4 7 10
4 8 7.5
4 9 6.5
4 10 48
5 6 28
5 7 10
5 8 15
5 9 16
5 10 45
6 7 28
6 8 45
6 9 30
6 10 25
7 8 12
7 9 10
7 10 4
8 9 3.5
8 10 15
9 10 30
1 1 0
2 2 0
3 3 0
4 4 0
5 5 0
6 6 0
7 7 0
8 8 0
9 9 0
10 10 0
;
run;
/* Generate full travel time matrix */
data travel_times_full;
set travel_times;
output;
t_temp = t;
t = t_temp;
i_temp = i;
i = j;
j = i_temp;
output;
run;
/* Add diagonal elements (travel time to self = 0) */
data travel_times_final;
set travel_times_full;
do i = 1 to 10;
j = i;
t = 0;
output;
end;
run;
/* Nurse and vehicle data */
data nurse_data;
input H_t H_c c_t c_c c_v n_t;
datalines;
480 480 30 40 20 8
;
run;
/* Macro to set the number of telehealth nurses */
%let n_t = 20;
/* Use PROC OPTMODEL to solve the problem */
proc optmodel;
/* Define sets */
set PATIENTS = 1..10;
set TELEHEALTH_NURSES = 1..&n_t;
set TRAVEL_CAREGIVERS = 1..8;
set VEHICLES = 1..4;
/* Define parameters */
number d{PATIENTS};
number travel_time{PATIENTS, PATIENTS};
number H_t;
number H_c;
number r{PATIENTS};
number c_t;
number c_c;
number c_v;
/* Read data */
read data patient_data into [i] d=duration r=revenue;
read data travel_times_final into [i j] travel_time=t;
read data nurse_data into H_t H_c c_t c_c c_v;
/* Define variables */
var X{PATIENTS, TELEHEALTH_NURSES} binary;
var Y{PATIENTS, TRAVEL_CAREGIVERS} binary;
var Z{PATIENTS, PATIENTS, TRAVEL_CAREGIVERS, VEHICLES} binary;
var U{PATIENTS} integer >= 1 <= card(PATIENTS);
/* Objective function */
max Profit = sum{i in PATIENTS} (r[i] * (sum{tn in TELEHEALTH_NURSES} X[i,tn] +
sum{c in TRAVEL_CAREGIVERS} Y[i,c]))
- sum{tn in TELEHEALTH_NURSES} (c_t * sum{i in PATIENTS} d[i] * X[i,tn])
- sum{c in TRAVEL_CAREGIVERS} (c_c * (sum{i in PATIENTS} d[i] * Y[i,c] +
sum{i in PATIENTS, j in PATIENTS, v in VEHICLES} travel_time[i,j] * Z[i,j,c,v]))
- sum{v in VEHICLES} (c_v * sum{c in TRAVEL_CAREGIVERS, i in PATIENTS, j in PATIENTS}
travel_time[i,j] * Z[i,j,c,v]);
/* Constraints */
con Patient_Assignment{i in PATIENTS}:
sum{tn in TELEHEALTH_NURSES} X[i,tn] + sum{c in TRAVEL_CAREGIVERS} Y[i,c] = 1;
con Telehealth_Hours{tn in TELEHEALTH_NURSES}:
sum{i in PATIENTS} d[i] * X[i,tn] <= H_t;
con Travel_Caregiver_Hours{c in TRAVEL_CAREGIVERS}:
sum{i in PATIENTS} d[i] * Y[i,c] +
sum{i in PATIENTS, j in PATIENTS, v in VEHICLES} travel_time[i,j] * Z[i,j,c,v] <= H_c;
con Vehicle_Capacity{v in VEHICLES}:
sum{c in TRAVEL_CAREGIVERS, i in PATIENTS, j in PATIENTS} Z[i,j,c,v] <= 2;
con Flow_Conservation{i in PATIENTS, c in TRAVEL_CAREGIVERS}:
sum{j in PATIENTS, v in VEHICLES} Z[i,j,c,v] = Y[i,c];
con Flow_Conservation_Reverse{i in PATIENTS, c in TRAVEL_CAREGIVERS}:
sum{j in PATIENTS, v in VEHICLES} Z[j,i,c,v] = Y[i,c];
con Subtour_Elimination{i in PATIENTS, j in PATIENTS, c in TRAVEL_CAREGIVERS: i ne j}:
U[i] - U[j] + 1 <= card(PATIENTS) * (1 - sum{v in VEHICLES} Z[i,j,c,v]);
con Ordering_Link{i in PATIENTS, c in TRAVEL_CAREGIVERS}:
U[i] >= 1 + card(PATIENTS) * (Y[i,c] - 1);
/* Solve the model */
solve;
/* Print results */
print X Y Z U;
quit;
... View more
In SAS, column length is critical. SAS numeric columns have a default length of 8 bytes, allowing the storage of up to 16 digits. In contrast, SAS character columns can vary from 1 to 32,767 bytes, with 1 byte typically equating to 1 character. *Note: This applies to single-byte encoding. If using UTF-8 encoding, some characters may require up to 3 bytes. This variability is common with non-English characters.
While numeric columns generally don't need length adjustments, character columns often do to prevent truncation of values. The usual approach to altering column length involves the LENGTH statement in the DATA step. However, this method can disrupt the order of your columns. Why does this happen, and how can we fix it while maintaining the original column order? The issue stems from the Program Data Vector (PDV), but don't worry—we can resolve it using PROC SQL.
... View more
Ready to join fellow brilliant minds for the SAS Hackathon?
Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.