#include #include #include #include #include #include #include #include "link1.h" #include /* This code is intended to produce VRP/JSP instances based on real-life commercial data. The code is far from perfect. It is not optimized regarding size. Some of it may be substantially improved programming-wise but it works. The code assumes you have a data file in the following format: 1 postcode11 postcode21 x1 y1 2 postcode12 postcode22 x2 y2 ... i postcode1n postcode2n xn yn Here 1, 2, ..., i are indexes of your geografic locations. postcode1i, postcode2i are alphanumeric symbols representing postcodes in Great Britain xi, yi planar coordinates of your locations. The code iteratively (the number of iterations depends on the desired instance size) takes location data without replacement and creates VRP visits. Each visit is represented by a line in the output file. The format of the output file is this: # instance: test.txt //lines preceded with '#' are comments. # data file: g:/local/Source/Reformul/Generator/data/g5k.txt # generator seed: 5685768 # Rho: 1 # Slack: 0.9 VRP //problem type 2 5 //number of vehicles number of customers 2790.97 //vehicle speed, dm/min 0 1440 //startOfDay endOfDay in minutes: 24-hour shift 4696 4769 // x/y coordinates of the depot 1 20 1 G2 6BS 23 223 25867 66530 1 2 -1 //first visit, duration 20 min, requires 1 unit of veh capacity, postcodes, earliest start, latest finish, x/y coords, indexes of allowed resources followed by '-1' (ie end of list). 2 20 1 G22 5RU 1131 1331 25889 66739 1 2 -1 3 20 1 G4 0TL 709 909 26014 66474 1 2 -1 4 20 1 G51 3ST 621 821 25472 66530 1 2 -1 5 20 1 G21 1NS 874 1074 26014 66660 1 2 -1 0 82932 83163 83023 82537 83209 //these lines occupied by distance matrix, it is redundant in VRPs, but essential for job shop 82932 0 231 203 395 277 //dimension is n+1 x n+1 where n is the number of customers, first row/column correspond to depot 83163 231 0 390 626 204 83023 203 390 0 598 186 82537 395 626 598 0 672 83209 277 204 186 672 0 1 5 //resources section, index of resource followed by capacity 2 5 Diff 2 //side constraints section, there are 2 diff constraints specified below 3 1 5 4 Same 1 //there is only 1 same constraint 4 1 Precedence 3 //there are 3 precedence constraints 1 2 2 3 4 5 Diff side constraints specify that a pair of visits A and B should be on different vehicles, Same constraints specify that A and B should be on the same vehicle. Precedence constraints of type A -> B are saying that visit A should be completed before B starts on the same or different vehicle. E.g., in our file visit 4 should be finished before visit 5 starts. It is assumed that each visits takes up 1 unit of capacity. The instances generated may NOT be solvable (there are time windows for visits, while side constraints, if you have them, are generated independently). You have to check solubility. Our solubility checker is ILOG Scheduler. I don't know if you are licensed to use it. Time is measured in minutes from midnight. Distance in decameters. Never mind the unrealistic value for the vehicles speed (all vehicles are assumed to move at the same speed). You could adjust input parameters to suit your needs. For our purposes we just needed precedence side constraints. That is why in this version we don't generate diff or same constraints. You could easily extend the code to cope with that. Time windows are generated using random allocation of start times within a certain range, and then computing latest finish times based on the given temporal slack as defined in the paper "VRP/JSP, whats the difference?" The input parameters are: *.exe RandomSeed Rho Slack Spec NbResources NbVisits Dur XBase YBase NbJobs SizeOfJob 1. Type of problem: VRP or JSP 2. datafilename: path to the data file (I have hardcoded my own path, please change it accordingly) 3. RandomSeed to initialise the rand number generator 4. Rho, the ratio of operation duration to transition time. Based on rho, we compute vehicle speed, see our paper 5. Slack \in (0,1), we compute time windows according to slack. 6. Spec, specialisation of fleet, corresponds to parameter p in the paper, 1 - a p of 100%, 2 - 80%, etc. The more p gets, the more vehicles are allowed to perform a visit. 7. NbResources - number of vehicles; 8. NbVisits - number of visits; 9. Dur - duration in minutes, assumed constant for all visits; 10. X- coordinate of the depot; 11. Y- coordinate of the depot; 12. NbJobs: 0 for pure VRPs, >0 for VRPs with side constraints, a job is a sequence of visits 13. SizeOfJob: 0 for pure VRPs, >0 for VRPs with side constraints, says how many visits there are in a job */ const int StartOfDay = 0; const int EndOfDay = 1440; bool RandEarliestStarts = true; int NbJobs; int SizeOfJob; int NbVisits, NbResources; double Speed; double Rho, Slack, Spec; int ActDuration; int ESFactorMorning; //this is the range of earliest start times in the morning; //we should not disturb the given slack, so max earliest start //is between the startOfDay+80 in the morning, //i.e., between 540 and 620; int ESFactorEvening;//this is that range but in the evening. 1 hour more; /* double SpecialisationBag0[] = {1.0}; double SpecialisationBag1[] = {0.5}; double SpecialisationBag2[] = {0.25}; double SpecialisationBag3[] = {0.1}; double SpecialisationBag4[] = {0.05}; */ int * Capacities; int** DataArr; int** DistMatr; int** ResNumbers; int** storeArray; typedef int * Item; const int ESMinMorning = StartOfDay; //const int ESMinEvening = StartOfDay+240; inline int myRound(double x) { return (int) (x+0.5); } int getESRange(double slack, int duration, int PrecChainSize) { return myRound((EndOfDay*(1-slack) - PrecChainSize*duration)/(1-slack)) - ESMinMorning; // return myRound((EndOfDay - StartOfDay)*(1-slack) - PrecChainSize*duration); } int inline computeManhattanDistance(int x1, int y1, int x2, int y2) { return abs(x1-x2) + abs(y1-y2); } int inline computeEucledianDistance(int x1, int y1, int x2, int y2) { return myRound(sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2))); } void CreateLinkedList(int Length, Node*& loc_head_ptr) { Node *loc_prev_ptr, *loc_tail_ptr; list_head_insert(loc_head_ptr,1); loc_tail_ptr=loc_head_ptr; loc_prev_ptr = loc_head_ptr; for (int i=2;i<=Length;i++) { list_insert(loc_prev_ptr,i); loc_prev_ptr = loc_prev_ptr->link; } } void outputPair(int N, int PairNb, ofstream& fout) { int k = N-1, sum = 0, sumPrev = 0, ctr = 0; while (true) { sum += k; ctr++; if (sum >= PairNb) { //pair number is between 1 and N*(N-1)/2; // fout<<" ctr = "<data; loc_curr_ptr->data = loc_tail_ptr->data; loc_tail_ptr->data = dataSaved; if (loc_tail_ptr!=loc_head_ptr) { loc_prev_ptr = list_prev_locate(loc_head_ptr,loc_tail_ptr->data); list_node_remove(loc_prev_ptr); } else { list_head_remove(loc_head_ptr); } outputPair(N,dataSaved,fout); } list_clear(loc_head_ptr); } void createJobs(int N, int nbJobs, int sizeOfJob, ofstream& fout) { int K = nbJobs*sizeOfJob; if (K > N) { cout<<"the number of visits should be gr than or eq to that\n"; cout<<"of operations involved in side constraints\n"; exit(-1); } int i,j; Node * loc_head_ptr = NULL; CreateLinkedList(N,loc_head_ptr); // all the visits in the instance are here; storeArray = new int* [nbJobs]; for (i=0; i.exe \n"; cout<<" seed Rho Slack Spec"< XBase YBase"<data<data<data; // cout<<"ResNumbers["<data; loc_curr_ptr->data = loc_tail_ptr->data; loc_tail_ptr->data = dataSaved; if (loc_tail_ptr!=loc_head_ptr) { loc_prev_ptr = list_prev_locate(loc_head_ptr,loc_tail_ptr->data); list_node_remove(loc_prev_ptr); } else { list_head_remove(loc_head_ptr); } } list_clear(loc_head_ptr); ctr++; } ctr=1; while (ctr<=NbVisits) { DataArr[ctr][2] = (int) ActDuration; ctr++; } ctr = 1; srand(TWSeed); while (ctr<=NbVisits) { bool isInChain = false; for (int jjj=0;jjjEndOfDay) { cout<<"LatestEnd = "<0) { fout<>rubbish>>rubbish>>rubbish>>rubbish>>rubbish; ctr_++; } fin>>rubbish>>rubbish>>rubbish>>DataArr[ctr][0]>>DataArr[ctr][1]; if (open) { fin.close(); open = false; } } else {//i.e., if noTransitions DataArr[ctr][0] = DataArr[0][0]; DataArr[ctr][1] = DataArr[0][1]; } postcode1[ctr] = postcode1[0]; postcode2[ctr] = postcode2[0]; ctr++; } srand(PairsSeed); ctr = 1; srand(SpecSeed); srand(PairsSeed); createJobs(NbVisits,nbJobsCur,sizeOfJobCur,fout); int* resCtr; resCtr = new int[NbResources]; for (i=0;idata<data<data; int dataSaved = loc_curr_ptr->data; loc_curr_ptr->data = loc_tail_ptr->data; loc_tail_ptr->data = dataSaved; if (loc_tail_ptr!=loc_head_ptr) { loc_prev_ptr = list_prev_locate(loc_head_ptr,loc_tail_ptr->data); list_node_remove(loc_prev_ptr); } else { list_head_remove(loc_head_ptr); } } list_clear(loc_head_ptr); } } else { cout<<"maxNumberOfResources = "<data: "<data<data: "<data<data; int dataSaved = loc_curr_ptr->data; loc_curr_ptr->data = loc_tail_ptr->data; loc_tail_ptr->data = dataSaved; // fout<<"***"<data); list_node_remove(loc_prev_ptr); } else { list_head_remove(loc_head_ptr_arr[curr_ind]); } } list_clear(loc_head_ptr_arr[curr_ind]); } } } ctr=1; while (ctr<=NbVisits) { DataArr[ctr][2] = (int) ActDuration; ctr++; } ctr = 1; srand(TWSeed); while (ctr<=NbVisits) { DataArr[ctr][4] = StartOfDay; DataArr[ctr][5] = (int)((ActDuration + DataArr[ctr][4]*(1-Slack))/(1-Slack)); ctr++; } //check for slacks and EndOfDay for (ctr = 1;ctr <= NbVisits; ctr++) { if (DataArr[ctr][5]>EndOfDay) { cout<<"LatestEnd = "<0) { fout<