DSAGV Guide
In this post, we’ll examine all important cpp files of DSAGV app, and then continue to explore ways to re-implement them in a state-of-the-art fashion. In order to make sense of the things I’ve written below, you need to read comments before each method definition in the related cpp source code.
The link to the trello is here.
In the future, I will move into the doxygen
for better documentation!
The structure of PortApp1_0_10.cpp
The PortApp1_0_10.cpp
file uses the following forms and translation units:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
USERES("PortApp1_0_10.res");
//Forms
USEFORM("Main1_0_5.cpp", MainForm);
USEFORM("MCFModel1_3.cpp", MCFAlgorithmForm);//MCFModel1_3 also uses HCDVRP.cpp for Heuristic approach of Simulated Annealing (SA)
USEFORM("OpenPort.cpp", OpenPortForm);
USEFORM("PortAbout.cpp", AboutForm);
USEFORM("PortAGV.cpp", PortAGVForm);
USEFORM("PortContainer.cpp", PortContainerForm);
USEFORM("PortLayout.cpp", PortLayoutForm);
USEFORM("PortBenchmark.cpp", BenchOptionForm);
///////
USEUNIT("PBEAMPP4.cpp");
USEUNIT("PFLOWUP.cpp");
USEUNIT("TREEUP.cpp");
USEUNIT("PSIMPLEX1_3.cpp");
USEUNIT("Dijkstra.cpp");
//stand-alone cpp!
USEUNIT("READMIN.Cpp");
USEUNIT("PREPAIR.cpp");// not included anywhere!
USEUNIT("OUTPUT.cpp");
USEUNIT("PBLA1_3.cpp"); //included as "PBLA.h" in PSIMPLEX
USEUNIT("Mcfutil.cpp");//included in MCFLIGHT and PSIMPLEX
USEUNIT("MCFLIGHT1_0_6.Cpp");
USEUNIT("PSTART.cpp");
USEFORM("Splash.cpp", SplashForm); //The starting screen
//USEUNIT("PBEAMPP1.cpp");
//USEUNIT("PBEAMPP2.cpp");
//USEUNIT("PBEAMPP3.cpp");
- Note that the keyword
extern
(explained here) is used for private global variables (or external linkage). It is not necessary for free functions and non-const variables. Theextern
keyword is used in"MCFModel1_3.cpp"
to referenceMCF_NSA_Solve(...)
method defined inMCFLIGHT1_0_6.Cpp
. - Remember that the
portdatabase
is in theOpenport.cpp
. - I might need
mcfutil
for the implementation of the nodes
Fundamental Port-related Entities
- Fundamental entities (defined in
Global.h
) are the following:
Struct port_buff
String Port ;
int NumberOfBlockYard;
int NumberOfWorkingPosition;
int NumberOfAGVs ;
int NumberOfJobs ;
int NumberOfJunctions ;
int NumberOfLanes ;
int NumberOfZones ;
long TotalEarlyTimes;
long TotalLateTimes;
long TotalQCWTimes;
long TotalVWTimes;
long TotalVTTimes;
long TotalDoneJobs;
long TotalEarlyJobs;
long TotalLateJobs;
double TotalDfApAc;
FILE *Fout3;
Struct Container_Buff [Maximum_Container_Jobs]
String IDStr ;
String SourcePointStr;
String DestPointStr ;
long int ReadyTime ;
long int QCraneTime ;
int Vehicle ;
unsigned char Empty ;
unsigned char Done ;
Struct Vehicle_Buff
String StartLoc;
int Last_Completed_Temp;
int Number_Of_Jobs;
int Last_Completed_Time;
int Number_Of_Done_Jobs;
int Lane_No ; // <=Number_of_Lanes
int Time_in_Lane ;
int Number_of_Lanes ;
int Lane [Maximum_Number_Lanes];
int Cost_Temp;
int PreJob_Temp;
int No_Job_Temp;
Struct Route_Buff
int Junction ;
String Location ;
int NextJunc1;
int NextLane1;
int DurationLane1;
int NextJunc2;
int NextLane2;
int DurationLane2;
int NextJunc3;
int NextLane3;
int DurationLane3;
Struct Route_Buff2
int Duration;
int Busy ;
int Vehicle ; // [Maximum_NAGV_In_Lan];
mcfdefs.h
, mcf.h
- The
mcfdefs.h
contains the fields (parameters and nodes) of theMCFModel
andmcf.h
contains methods. Examples of the components ofmcfdefs.h
: (A description of Nodes can be found here)1 2 3 4 5 6 7 8
struct MCF_node{ ///MCF_node_p is the alias (or typeof) of MCF_node int indent; int pre_indent; MCF_node_p child; MCF_node_p right_sibling; MCF_node_p left_sibling; .... }
- Examples of the components of
mcf.h
:1 2 3
extern long MCF_write_intermediate2(MCF_network_p net); extern long MCF_primal_start_artificial (MCF_network_p net); extern long MCF_primal_net_simplex (MCF_network_p net);
Please note that the comments (“documentation”) are actually good and pretty important in these two cpp files!
PBLA1_3.cpp
, PXIMPLEX1_3.cpp
, TREEUPS.cpp
, MCFLIGHT1_0_6.cpp
PBLA
andPSIMPLEX1_3
andMCFLIGHT1_0_6
are closely related! There are some useful comments in them, none of which I understand as I still haven’t reviewed the mcf problem and NSA algorithm thoroughly.
PBLA1_3.cpp
and PSIMPLEX.cpp
- The
PBLA
(which most likely stands for “problem of best leaving arc”) only contains the mysterious:1 2 3 4 5
MCF_node_p MCF_primal_iminus(MCF_flow_p delta, long *xchange, MCF_node_p iplus, MCF_node_p jplus, MCF_node_p *w );
- The
PSIMPLEX
(The bigger cpp file with"mcfdefs.h
”,"pbeadef.h"
,"pbea.h"
,"pbla.h"
,"pflowup.h"
,"treeup.h"
,"mcfutil.h"
) only contains the mysterious:1
long MCF_primal_net_simplex(MCF_network_p net);
TREEUP
is used inPSIMPLEX1_3
.
Mcfutil.cpp
, MCFLIGHT1_0_6.cpp
, and MCFModel1_3.cpp
- portappdatabase is updated within MCFModel1_3.cpp.
- The part that uses
HCDVRP
</a>
1
void TMCFAlgorithmForm::Handle_Multi_Load_AGVS();
- Important method in
mcfmodel
:Set_Table4_For_New_Schedule()
Container
,Vehicle
andTour
ofHCDVRP
is used inIntialize_SA_By_NSA_Solution()
!MCF_NSA_Solve(...)
fromMCFLIGHT1_0_6.cpp
andRead_NSA_Solution(...)
is used inRepairGraphModel(...)
inMCFModel1_3.cpp
.DBGrid4
is the AGV table in the Solution groupbox.DBGrid5
is the one that _I think_ updates thePortDoneJobTable.db
. The columns ofDBGrid5
are exactly the same asPortDoneJobTable
.- The
BenchOptionForm
recurs multiple times in the source code ofMCFModel1_3
. Pay Attention to it!
openport.cpp
, portAGV.cpp
, PortLayout
and PortContainer.cpp
- In
openport
, there is thePortTable
that’s referenced inportAGV
,PortContainer
,PortLayout
, andMCFModel1_3
.
Job generator (Generate Button in MCFModel1_3)
- It exists as an
MCFModel1_3.cpp
method:1
void __fastcall TMCFAlgorithmForm::Generate_Button11Click(TObject *Sender)
- If you right click on Port and Container Job (static) Form, you will find a
PopupMenu1
with two itemsGenerate Schedule
andReset Schedule
.Generate Schedule
Event points to the above cpp line! WHY??
HCDVRP.cpp
Heuristic approach using Simulated Annealing
HCDVRP
consists of:
- This file uses the already known parameters of the
MCFModel1_3
such as Container Jobs and Time windows. - It is also very much dependent of some kind of an initial solution. This initial solution can be attained by the use of
MCF_NSA_Solution
method inMCFModel1_3
.
Simulation parameters are as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct Container:
{
int JobNo ;
int Demand ;
int AppointmentTime; // ReadyTime
int QCraneTime ;
int DueTime ;
int ServiceTime;
int SourceDone ; // 1 if the job has been pick up, otherwise 0
int DestDone ; // 1 if the job has been put down, otherwise 0
String SourceLocation;
String DestLocation ;
int UseConstraintTime ;
};
struct Vehicle
{
int Capacity;
String StartLoc;
};
//Three Important properties in this file, used in other places.
Container *CJob;
Vehicle *AGV;
Tour *TAGV,*TempT,*BestT;
- It also generates Trips, Tours, and Destination information.
- It’s declared as
VRP_2
inMCFModel1_3
.
PortLayout.cpp
- I really don’t understand what the use of this really is. I guess, it just **loads information about ports (using
openport.cpp
) and the distance of each AGV and - It modifies the
PortLayoutTable
db. - It then shows them in the “Route Table”, specifying consecutive junction location and TimeLanes(??)
Miscellaneous Notes
DataSource
type is defined inOpenPort
filetable2
is defined inPortAGV
file.Defines.h
contains all constants (such asMAXJOB_0 50, Maximum_Container_Jobs 40
etc.), andGlobal_ext.h
contains simulation variables (such asSOURCEpOINT, dESTpOINT
etc.)PSIMPLEX.h
Only consists of an interfaceMCF_primal_net_simplex(MCF_network_p net)
.PSIMPLEX1_3.cpp
implements it.- BEA could stand for “Best Entering Arc”.
Borland Paradox DB files
- For edditting Paradox DB files: use
pdxEditor
in the GDrive. - Your reference for tables is this
TTables
are descendents ofTDataSets
, which is a virtual class.TTable.post()
writes a modified record to the database andTTable.delete()
deletes the active record and positions the dataset on the next record.- To open DB files, download this
- There are various tables, but PortLayoutTable is the one generated with the HCDVRP.cpp </a>
MCFAlgorithmForm->Table4
andMCFAlgorithmForm->Table5
arePortAGVTTable.DB
in the database.PortAGVForm->Table2
andPortAGVForm->Table1
areportAGVTable.db
in the database.PortContainerForm->Table1
andPortContainerForm->Table2
arePortContainerTable.db
in the database.- ` MCFAlgorithmForm->Table1
is
PortDoneJobTable.db` in database. - In BDE,
TTable
is the type for creating table objects. - Comparing the three tables used mostly in
MCFModel1_3.cpp
, What I think of what theportAGVTable.db
(AKAMCFAlgorithmForm->Table4
) consists of is the combination ofportAGVTable.db
andportContainer.db
, creating a dynamic table for manipulating container job schedules on demand (completely deleting and then re-constructing it).
More on Databases used in the program
9 Databases is used in the program. We’ll talk more about from which files they are created and accessed and modified!
AlgorithmTable.db
PortAGVTable.db
andPortAGVTTable.db
PortContainerTable.db
:PortDoneJobTable.db
PortLayoutTable.db
PortRouteTable.db
: It specifies Location of Junctions (تقاطع) in each port.- Modified in:
PortLayout.cpp
by the methodBitBtn2Click
- Modified in:
PortStatusJobTable.db
PortTable.db
Deficiencies of the DSAGV
- The App resets form sizes after close.
- App opens multiple windows for different forms, why?!
Some C++ Builder 5 tips:
- when opening a builder project, move cursor on a resource and right click and select
open file under cursor
to open the corresponding file, in place! - a way of printing bugs! stupid Builder 5!!!!!
1 2 3 4
std::stringstream ss; ss << Port_Buff.NumberOfAGVs; std::string str = ss.str(); Application->MessageBox(str.c_str(),"bug",MB_OK);
Unanswered Questions:
- What is the use of
MCF_primal_iminus
(and henceMCF_primal_net_simplex
)? what are jplus and iplus in them? - Why are there 2 tables pointing to the same DB in
PortAGV.cpp
andPortContainer.cpp
? (Maybe looking atSet_Empty_Table4_For_Specific_Port(AnsiString PortNameStr)
inMCFModel1_3.cpp
might help!) - Not sure why there are so many
MCFAlgorithmForm->Table4->Delete();
inMCFModel1_3
? it deletes them, and the loop ends, at the end of the method,MCFAlgorithmForm->Table4->refresh()
gets called!! why?? - (Very Important Question): How container jobs database (PortContainerTable.db) is created and updated??
- It’s interesting, When you run the installed app, the solutions are displayed. However, when you compile the version 10, no solutions are appeared!
Update:
I have switched to a very old commit of repo since .dfm
files used in this era are binary (newer versions aren’t!) and, hence, un-nameable!! Many names, (tables, lables, buttons, etc) are now deleted and should be found according to their context.
Update 1/23/2025:
- The method associated to
Button11
, which is Generate button in static fashion, is the Heart of theMCFModel1_3.cpp
file containing the schedule generation for the job and connecting all previously written methods inMCFModel1_3.cpp
. - Similarly, there is
Button7Click
, which is the intention of Dr. Rashidi to give out the source code. - In static fashion, the data (container jobs, the network graph and number of QCs and AGVs) are fed into a method named
MCF_NSA_Solve
in the button11click method ofMCFModel1_3.cpp
. The output is the either 0,1,-1, with 0 being success. - The reason why we don’t see generated jobs: because they are not generated as there is a line in the
MCFModel1_3
, in button11Click method, written as:1
bool b = PortContainerForm->Table1->Locate("Portname", VarArrayOf(locvalues, 0), Opts);
This code basically tell the program to not generate the jobs, if the port name exists in the
PortContainerTable.DB
, which is not an interesting trait!!
At least the original coder could’ve written some comments, telling “If you like to generate it, set this bool to false yourself”. NOT COOL!
The structure of MC_FNetwork:
MCF_network
struct MCF_network
{
/** Number of nodes.
*
* This variable stands for the number of originally defined nodes without
* the artificial root node.
*
*/
long n;
/** Number of arcs.
*
* This variable stands for the number of arcs (without the artificial slack
* arcs).
*
*/
long m;
/** Options for candidate arc group.
*
* This variable will be set to 0 (Fixed candidate group) or 1 (Random Candidate Group)
*
*/
int algorithm_opt;
/** Block size of the model.
*
* This variable will be set to the size of block in arcs calssification.
*
*/
int block_size;
/** CPU time to solve the model.
*
* This variable will be set to the consumed time to solve the moedl, iff the model is fesaible.
*
*/
double cpu_time;
/** maximum cost of arcs in the model.
*
* This variable will be set to maximum cost in the model.
*
*/
long max_cost;
/** the arc in maximum cost.
*
*
*/
MCF_arc_p max_cost_arc;
/** Primal unbounded indicator.
*
* This variable is set to one iff the problem is determined to be primal
* unbounded.
*
*/
long primal_unbounded;
/** Dual unbounded indiciator.
*
* This variable is set to one iff the problem is determined to be dual
* unbounded.
*
*/
long dual_unbounded;
/** Feasible indicator.
*
* This variable is set to zero if the problem provides a feasible solution.
* It can only be set by the function primal\_feasible() or dual\_feasible()
* and is not set automatically by the optimization.
*
*/
long feasible;
/** Costs of current basis solution.
*
* This variable stands for the costs of the current (primal or dual) basis
* solution. It is set by the return value of primal\_obj() or dual\_obj().
*
*/
double optcost;
/** Vector of nodes.
*
* This variable points to the $n+1$ node structs (including the root node)
* where the first node is indexed by zero and represents the artificial
* root node.
*
*/
MCF_node_p nodes;
/** First infeasible node address.
*
* This variable is the address of the first infeasible node address,
* i.\,e., it must be set to $nodes + n + 1$.
*
*/
MCF_node_p stop_nodes;
/** Vector of arcs.
*
* This variable points to the $m$ arc structs.
*
*/
MCF_arc_p arcs;
/** First infeasible arc address.
*
* This variable is the address of the first infeasible arc address, i.\,e.,
* it must be set to $nodes + m$.
*
*/
MCF_arc_p stop_arcs;
/** Vector of artificial slack arcs.
*
* This variable points to the artificial slack (or dummy) arc variables and
* contains $n$ arc structs. The artificial arcs are used to build (primal)
* feasible starting bases. For each node $i$, there is exactly one dummy
* arc defined to connect the node $i$ with the root node.
* */
MCF_arc_p dummy_arcs;
/** First infeasible slack arc address.
*
* This variable is the address of the first infeasible slack arc address,
* i.\,e., it must be set to $nodes + n$.
*
*/
MCF_arc_p stop_dummy;
/** Iteration count.
*
* This variable contains the number of main simplex iterations performed to
* solve the problem to optimality.
*
*/
long iterations;
/** Dual pricing rule.
*
* Pointer to the dual pricing rule function that is used by the dual
* simplex code.
* */
MCF_node_p (*find_iminus) ( long n, MCF_node_p nodes,
MCF_node_p stop_nodes, MCF_flow_p delta );//this is not used anywhere in the codes!
/** Primal pricing rule.
*
* Pointer to the primal pricing rule function that is used by the primal
* simplex code.
* */
MCF_arc_p (*find_bea) ( MCF_arc_p max_cost_arc, int algorithm_opt,long m, MCF_arc_p arcs, MCF_arc_p stop_arcs,
MCF_cost_p red_cost_of_bea );
};
The Dynamic Approach
How dynamic approach implemented
Dynamic approach Bugs
TODO List:
- Bug in
Honk Kong
part inMCFModel1_3
inPort_Names_Static_ListBoxClick
method.- Fix: changed the
Maximum_Number_Vehicles
from 50 to 250
- Fix: changed the
- What optimzation problem is this program trying to solve? -> Read Ch 5 of Port Automation book by Rashidi.
- Fixing Gobgenerator Table view: When
Edit1
is set in theMCFModel1_3
form, the generatod container jobs aren’t shown. - The key violation error is caused by the program creating the same container jobs with the initials
C-BS-
. Fix that by clearing thePortContainerTable.DB
first. - In order to write doxygen, you should write documentation comments inside source codes.
- Urgent: line 2237,
NumContainers
looks bad! (it’s related toNumberOfContainers
inAGVTTable.DB
, which doesn’t make sense, if you check the DB.)