2014-11-14 70 views
0

下面是R的公司製造和銷售的流動模型圖形的簡化重複的例子多級製造和銷售模型

library(igraph) 

# Create graph 
graph= graph.formula(
    R --+ P1, 
    P1 --+ M1, 
    R --+ P2, 
    P2 --+ M2, 
    P1 --+ P3, 
    P2 --+ P3, 
    P3 --+ M2, 
    R --+ P4, 
    P3 --+ P5, 
    P4 --+ P5, 
    P5 --+ M3, 
    P5 --+ M4 
) 

# Change colors for pretty plot 
V(graph)$color= "gray" 
V(graph)[name== "R"]$color= "cyan" 
V(graph)[grepl(x= name, pattern= "M")]$color= "green" 
V(graph)[name %in% c("P1", "P2", "P4")]$color= "red" 

# Add sales volume as attribute and add to edge label in plot 
E(graph)[4]$sales= 100 
E(graph)[4]$label= paste("Sales:\n", E(graph)[4]$sales, "tons") 
E(graph)[6]$sales= 200 
E(graph)[6]$label= paste("Sales:\n", E(graph)[6]$sales, "tons") 
E(graph)[8]$sales= 500 
E(graph)[8]$label= paste("Sales:\n", E(graph)[8]$sales, "tons") 
E(graph)[11]$sales= 1000 
E(graph)[11]$label= paste("Sales:\n", E(graph)[11]$sales, "tons") 
E(graph)[12]$sales= 2000 
E(graph)[12]$label= paste("Sales:\n", E(graph)[12]$sales, "tons") 

# Add bill of material share as attribute and add to edge label in plot 
E(graph)[1:3]$share= 1.0 
E(graph)[1:3]$label= paste("Share:\n", E(graph)[1:3]$share*100, "%") 
E(graph)[7]$share= 0.8 
E(graph)[7]$label= paste("Share:\n", E(graph)[7]$share*100, "%") 
E(graph)[5]$share= 1 - 0.8 
E(graph)[5]$label= paste("Share:\n", E(graph)[5]$share*100, "%") 
E(graph)[9]$share= 0.4 
E(graph)[9]$label= paste("Share:\n", E(graph)[9]$share*100, "%") 
E(graph)[10]$share= 1 - 0.4 
E(graph)[10]$label= paste("Share:\n", E(graph)[10]$share*100, "%") 

# Add preliminary NA vol attribute to nodes and add label in plot 
V(graph)$vol= NA 
V(graph)$label= paste(V(graph)$name, "\nVolume:\n", V(graph)$vol, "tons") 

# Plot 
E(graph)$label.cex=0.8 
V(graph)$label.cex=0.8 
V(graph)$size=20 
layout= layout.reingold.tilford(graph, root=1) 
layout[3,2]=0 
layout[5,2]=0 
plot(graph, layout= layout) 

enter image description here

模型網絡包括以下組件:

  • R:製成產品所需的青色原料P1, P2, P4
  • P1...P5:紅色產品直接從RP1, P2, P4)或多級製造產品(P3, P5)中一步完成。每種產品都有一份配方材料清單。
  • M...:產品P1...5銷往的綠色市場。唯一的例外是P4這是沒有出售,它只是作爲P5(組合其中P3)的前身。

已知屬性在此網絡的邊緣:

  • Sales:銷量噸P1, P2, P3, P5市場M1, M2, M3, M4
  • 配方Share:製造特定產品所需的前體量(%)。例如:要製造1噸的P1, P2, P4需要1噸原材料(因此需要100%)。要製造10噸P3 8噸(= 80%)P2和2噸(= 20%)需要P1

我要尋找一個解決方案來計算體積爲節點產品P1 ... P5和原材料R屬性vol。目前它們設置爲NAvol應與銷售量和產品配方的份額保持一致。

評論:我正在尋找一個適用於這個簡化示例的廣義解決方案,但也適用於更復雜(更多節點和更多製造階段)真實世界模型。我正在考慮一種多級傳播算法。首先sales數據將被彙總,以產生出售給市場的產品的產品頂點vol屬性。然後,另一個步驟將根據share計算上游產品的產量以達到上一步產量的要求等等。一般化的解決方案超出了我的知識範圍R。任何想法如何完成任務?

回答

0

經過大量的實驗,看起來像我有第一個解決方案。可重現的例子可以用它來解決。到目前爲止還沒有在現實世界複雜的案例中進行測試。

1。重新編碼任務了一下:

library(igraph) 

# Create graph 
graph= graph.formula(
    R --+ P1, 
    P1 --+ M1, 
    R --+ P2, 
    P2 --+ M2, 
    P1 --+ P3, 
    P2 --+ P3, 
    P3 --+ M2, 
    R --+ P4, 
    P3 --+ P5, 
    P4 --+ P5, 
    P5 --+ M3, 
    P5 --+ M4 
) 

# Change colors for pretty plot 
V(graph)$color= "gray" 
V(graph)[name== "R"]$color= "cyan" 
V(graph)[grepl(x= name, pattern= "M")]$color= "green" 
V(graph)[name %in% c("P1", "P2", "P4")]$color= "red" 

# Add sales volume as attribute and add to edge label in plot 
E(graph)$vol= NA # prefill 
E(graph)[4]$vol= 100 
E(graph)[6]$vol= 200 
E(graph)[8]$vol= 500 
E(graph)[11]$vol= 1000 
E(graph)[12]$vol= 2000 

# Add bill of material share as attribute and add to edge label in plot 
E(graph)[1:3]$share= 1.0 
E(graph)[7]$share= 0.8 
E(graph)[5]$share= 1 - 0.8 
E(graph)[9]$share= 0.4 
E(graph)[10]$share= 1 - 0.4 

# Add preliminary NA vol attribute to nodes and add label in plot 
V(graph)$vol= 0 

# Plot 
update.labels= function(graph){ 
    E(graph)[4]$label= paste("Vol:\n", E(graph)[4]$vol, "tons") 
    E(graph)[6]$label= paste("Vol:\n", E(graph)[6]$vol, "tons") 
    E(graph)[8]$label= paste("Vol:\n", E(graph)[8]$vol, "tons") 
    E(graph)[11]$label= paste("Vol:\n", E(graph)[11]$vol, "tons") 
    E(graph)[12]$label= paste("Vol:\n", E(graph)[12]$vol, "tons") 
    E(graph)[1:3]$label= paste("Share:\n", E(graph)[1:3]$share*100, "%", "\nVol:\n", E(graph)[1:3]$vol, "tons") 
    E(graph)[7]$label= paste("Share:\n", E(graph)[7]$share*100, "%", "\nVol:\n", E(graph)[7]$vol, "tons") 
    E(graph)[5]$label= paste("Share:\n", E(graph)[5]$share*100, "%", "\nVol:\n", E(graph)[5]$vol, "tons") 
    E(graph)[9]$label= paste("Share:\n", E(graph)[9]$share*100, "%", "\nVol:\n", E(graph)[9]$vol, "tons") 
    E(graph)[10]$label= paste("Share:\n", E(graph)[10]$share*100, "%", "\nVol:\n", E(graph)[10]$vol, "tons") 
    V(graph)$label= paste(V(graph)$name, "\nVolume:\n", V(graph)$vol, "tons") 
    graph 
} 
graph= update.labels(graph) 
E(graph)$label.cex=0.8 
V(graph)$label.cex=0.8 
V(graph)$size=20 
layout= layout.reingold.tilford(graph, root=1) 
layout[3,2]=0 
layout[5,2]=0 
plot(graph, layout= layout) 

enter image description here

解決方案:

# Aggregate sales volumes to markets 
this.vertices.names= V(graph)[grepl(x=name, pattern = "M")]$name 
for (i in this.vertices.names) { 
    V(graph)[name== i]$vol= sum(E(graph)[to(i)]$vol, na.rm=T) 
} 

# Calculate volumes along the network 
# do stepwise from farthest nodes to nearest (origin is "R") 
# 1.step: aggregate "from" edge vol attributes to product node vol attribute 
# 2.step: distribute node vol attribute to "to" edge vol attribute by vol of node * share of edge 

# Function to sort nodes even if they have same distance from root 
max.out.edges= function(graph, from.node.name) { 
    max(shortest.paths(graph= graph, v= V(graph)[name==from.node.name], mode="out") 
     [is.finite(shortest.paths(graph= graph, v= V(graph)[name==from.node.name], mode="out"))]) 
} 

# Function to create a list of nodes lists sorted with decending distance from root 
list.farthest.nodes= function(graph, from.node.name) { 
    ans= list() 
    sp= shortest.paths(graph= graph, v= V(graph)[name==from.node.name], mode="out") 
    max.distance= max(sp[is.finite(sp)]) 
    for (i in 0:max.distance-1) { 
    nodes= sapply(dimnames(sp)[[2]][which(sp==max.distance-i)], function(x) max.out.edges(graph, x), simplify= T) 
    ans= c(ans, list (names(nodes[order(nodes)]))) 
    } 
    ans[[1]]= NULL 
    ans[[max.distance+1]]= "R" 
    ans 
} 


farthest.nodes= list.farthest.nodes(graph, "R") 

for (i in farthest.nodes) { 
    print(paste("Levels:", i)) 
    for (j in i) { 
    print(paste("Single Level",j)) 
    if (!grepl(x=j, pattern="M")) { 
     V(graph)[name== j]$vol= V(graph)[name== j]$vol + sum(E(graph)[from(j)]$vol, na.rm=T) 
     if (!grepl(x=j, pattern="R")) { 
     E(graph)[to(j)]$vol= E(graph)[to(j)]$share * V(graph)[name== j]$vol   
     } 
    } 
    } 
} 

graph= update.labels(graph); plot(graph, layout=layout) 

enter image description here