This section contains PROC CAS code.
Note: Input data must be accessible in your CAS session, either as a CAS table or as a transient-scope table. A CAS table has a two-level name: the first level is your CAS engine libref, and the second level is the table name. You refer to this table in the CAS procedure by specifying only the second level. For more information about two-level names, see Chapter 2, Shared Concepts (SAS Viya: Machine Learning Procedures). A transient-scope table is called directly from the action and exists in memory for the duration of the action. For more information about accessing data, see SAS Viya: System Programming Guide. For more information about PROC CAS and programming in CASL, see SAS Cloud Analytic Services: CASL Programmer’s Guide and SAS Cloud Analytic Services: CASL Reference.
Consider the following road network between a SAS employee’s home in Raleigh, North Carolina, and SAS headquarters nearby in Cary. In this road network (graph), the links are the roads and the nodes are intersections of the roads. For each road, you assign a link attribute in the variable time_to_travel to describe the number of minutes that it takes to drive from one node to another. The following data were collected using Google Maps (Google 2011), which gives an approximate number of minutes to travel between two nodes based on the length of the road and the typical speed during normal traffic patterns.
data LinkSetIn;
input start_inter $1-20 end_inter $21-40 miles miles_per_hour;
time_to_travel = miles * 1/miles_per_hour * 60;
datalines;
614CapitalBlvd Capital/WadeAve 0.6 25
614CapitalBlvd Capital/US70W 0.6 25
614CapitalBlvd Capital/US440W 3.0 45
Capital/WadeAve WadeAve/RaleighExpy 3.0 40
Capital/US70W US70W/US440W 3.2 60
US70W/US440W US440W/RaleighExpy 2.7 60
Capital/US440W US440W/RaleighExpy 6.7 60
US440W/RaleighExpy RaleighExpy/US40W 3.0 60
WadeAve/RaleighExpy RaleighExpy/US40W 3.0 60
RaleighExpy/US40W US40W/HarrisonAve 1.3 55
US40W/HarrisonAve SASCampusDrive 0.5 25
;
The following DATA step loads the LinkSetIn data set into a CAS data table named mylib.LinkSetIn. These statements assume that the CAS engine libref is named mylib, but you can substitute any appropriately defined CAS engine libref.
data mylib.LinkSetIn;
set LinkSetIn;
run;
You want to find the route that yields the shortest path between two locations. You can do this by first loading the graph by using the loadGraph action as follows:
proc cas;
loadactionset "network";
action network.loadGraph result=rl status=s /
links = {name = "LinkSetIn"}
linksVar = {from = "start_inter",
to = "end_inter",
weight = "time_to_travel"}
outGraphList = {name = "OutGraphList1", replace=true};
run;
action table.fetch / table = "OutGraphList1"; run;
The results variable rl.graph indicates that the graph identifier for the in-memory graph is 0. The graph identifier and several other pieces of summary information about the in-memory graph are also contained in the output data table OutGraphList1, as shown in Output 28.9.1.
Output 28.9.1: Summary Information about the In-Memory Graphs
| Selected Rows from Table OUTGRAPHLIST1 | |||||||||
|---|---|---|---|---|---|---|---|---|---|
| _Index_ | graph | createTime | loaded | direction | nodes | links | multiLinks | selfLinks | standardizedLabels |
| 1 | 0 | 23AUG2022:09:02:17 | 1 | Undirected | 10 | 11 | 1 | 1 | 0 |
Next, the following statements use the in-memory graph that was loaded in the previous action call to find the route that yields the shortest path between source="614CapitalBlvd" and sink="SASCampusDrive":
action network.shortestPath result=r status=s /
graph = rl.graph
source = "614CapitalBlvd"
sink = "SASCampusDrive"
outPaths = {name = "ShortPath1", replace=true};
run;
action table.fetch / table = "ShortPath1"; run;
These statements point to the in-memory graph that is referenced by identifier rl.graph=0, build any additional data structures needed (because this is the first call to the shortest path algorithm), and then calculate the shortest path.
Output 28.9.2 displays the output data table ShortPath1, which shows the best route to take in order to minimize travel time between 614 Capital Boulevard and SAS Campus Drive.
Output 28.9.2: Shortest Path for Road Network between 614 Capital Boulevard and SAS Campus Drive
| Selected Rows from Table SHORTPATH1 | ||||||
|---|---|---|---|---|---|---|
| _Index_ | source | sink | order | start_inter | end_inter | time_to_travel |
| 1 | 614CapitalBlvd | SASCampusDrive | 0 | 614CapitalBlvd | Capital/WadeAve | 1.44 |
| 2 | 614CapitalBlvd | SASCampusDrive | 1 | Capital/WadeAve | WadeAve/RaleighExpy | 4.5 |
| 3 | 614CapitalBlvd | SASCampusDrive | 2 | WadeAve/RaleighExpy | RaleighExpy/US40W | 3 |
| 4 | 614CapitalBlvd | SASCampusDrive | 3 | RaleighExpy/US40W | US40W/HarrisonAve | 1.4181818182 |
| 5 | 614CapitalBlvd | SASCampusDrive | 4 | US40W/HarrisonAve | SASCampusDrive | 1.2 |
Next, to calculate the shortest path between source="US70W/US440W" and sink="SASCampusDrive", use the following statements:
action network.shortestPath result=r status=s /
graph = rl.graph
source = "US70W/US440W"
sink = "SASCampusDrive"
outPaths = {name = "ShortPath2", replace=true};
run;
action table.fetch / table = "ShortPath2"; run;
These statements again point to the same in-memory graph (with no additional setup work required) and calculate the shortest path.
Output 28.9.3 displays the output data table ShortPath2, which shows the best route to take in order to minimize travel time between US70W/US440W and SAS Campus Drive.
Output 28.9.3: Shortest Path for Road Network between US70W/US440W and SAS Campus Drive
| Selected Rows from Table SHORTPATH2 | ||||||
|---|---|---|---|---|---|---|
| _Index_ | source | sink | order | start_inter | end_inter | time_to_travel |
| 1 | US70W/US440W | SASCampusDrive | 0 | US70W/US440W | US440W/RaleighExpy | 2.7 |
| 2 | US70W/US440W | SASCampusDrive | 1 | US440W/RaleighExpy | RaleighExpy/US40W | 3 |
| 3 | US70W/US440W | SASCampusDrive | 2 | RaleighExpy/US40W | US40W/HarrisonAve | 1.4181818182 |
| 4 | US70W/US440W | SASCampusDrive | 3 | US40W/HarrisonAve | SASCampusDrive | 1.2 |
Finally, to delete the first in-memory graph (rl.graph=0), you can use the following statements:
action network.unloadGraph result=r status=s /
graph = rl.graph
outGraphList = {name = "OutGraphList2", replace=true};
run;
action table.fetch / table = "OutGraphList2"; run;
quit;
The output data table OutGraphList2, shown in Output 28.9.4, now indicates that the in-memory graph that has identifier 0 is no longer loaded.
Output 28.9.4: Summary Information about the In-Memory Graphs
| Selected Rows from Table OUTGRAPHLIST2 | |||||||||
|---|---|---|---|---|---|---|---|---|---|
| _Index_ | graph | createTime | loaded | direction | nodes | links | multiLinks | selfLinks | standardizedLabels |
| 1 | 0 | 23AUG2022:09:02:17 | 0 | . | . | . | . | . | |
This section contains Lua code for the analysis in the CASL version of this example, which contains details about the results.
Note: In order to run this code, the data that are described in the CASL version need to be accessible to the CAS server. One way to do this is to convert the LinkSetIn data to the comma-separated-value (CSV) file LinkSetIn.csv and then use the following code to load the CSV file into CAS:
s:loadtable{casLib="casuser", path="LinkSetIn.csv"}
For more information about coding in Lua, see Getting Started with SAS Viya for Lua and SAS Viya: System Programming Guide.
r = s:network_loadGraph{
links = {name = "LinkSetIn"},
linksVar = {from = "start_inter",
to = "end_inter",
weight = "time_to_travel"},
outGraphList = {name = "OutGraphList", replace=true}}
s:network_shortestPath{
graph = r.graph,
source = "US70W/US440W",
sink = "SASCampusDrive",
outPaths = {name = "ShortPath2", replace=true}}
This section contains Python code for the analysis in the CASL version of this example, which contains details about the results.
Note: In order to run this code, the data that are described in the CASL version need to be accessible to the CAS server. One way to do this is to convert the LinkSetIn data to the comma-separated-value (CSV) file LinkSetIn.csv and then use the following code to load the CSV file into CAS:
s.upload_file('LinkSetIn.csv')
For more information about coding in Python, see Getting Started with SAS Viya for Python and SAS Viya: System Programming Guide.
r = s.network.loadGraph(
links = {"name": "LinkSetIn"},
linksVar = {"from": "start_inter",
"to": "end_inter",
"weight": "time_to_travel"},
outGraphList = {"name": "OutGraphList", "replace":True})
s.network.shortestPath(
graph = r.graph,
source = "US70W/US440W",
sink = "SASCampusDrive",
outPaths = {"name" : "ShortPath2", "replace":True})
This example is not available for the R programming language.