ダイクストラ法による交通配分プログラム

ダイクストラ法による交通配分プログラムです。プログラム言語はRubyを使用しています。

道路の末端から発生したOD交通量を最短経路で道路上に配分します。交差点を示す各ノードにもコストを設定していて、直進に比べて、右折、左折は時間がかかるなどの設定もできるようにしています。最短経路に1回配分するだけなので需要配分になります。

リンク上でQV曲線を設定して、交通量を分割して配分するようにすれば分割配分のプログラムになりますが、今回はそこまではやってません。実行はコマンドプロンプトで下記のように実行すればよいです。

下記の場合はoutput.txtに結果が出力されます。

ruby route_search.rb DATA.txt > output.txt

結果は各起終点間の最短経路と各リンクの交通量、交差点の方向別交通量の算出するようにしています。

#! /usr/local/bin/ruby -Ks
require "csv"
class ODdata
def initialize(znum = 0,zname = '',od_dat = 0)
 @znum = znum
 @zname = zname
 @od_dat = od_dat
end
attr_accessor :znum, :zname, :od_dat
end
#
class Ndata
def initialize(node_num=0,node='',ldn=0,lnk='',st=0,jj='',tsum=0.0,nchk=0,spath='',nlc=0.0)
 @node_num = node_num
 @node = node
 @ldn = ldn
 @lnk = lnk
 @st = st
 @jj = jj
 @tsum = tsum
 @nchk = nchk
 @spath =spath
 @nlc = nlc
end
 attr_accessor :node_num, :node, :ldn, :lnk,:st, :jj, :tsum, :nchk, :spath, :nlc
end
#
class Ldata
def initialize(lnum =0,lname = '',node1 = '',node2 = '',linklen =0,linkspeed =0.0,linkcost =0.0,linkqdat=0.0)
 @lnum = lnum
 @lname = lname
 @node1 = node1
 @node2 = node2
 @linklen = linklen
 @linkspeed = linkspeed
 @linkcost = linkcost
 @linkqdat = linkqdat
end
attr_accessor :lnum, :lname, :node1, :node2, :linklen, :linkspeed, :linkcost, :linkqdat
end
#
class Crdata
def initialize(crnum =0,crname = '',status = '',node1 = '',node2 = '',cost = 0.0,crqdat = 0.0,crlnk1 = '',crlnk2 = '')
  @crnum = crnum
  @crname = crname
  @status = status
  @node1 = node1
  @node2 = node2
  @cost = cost
  @crqdat = crqdat
  @crlnk1 = crlnk1
  @crlnk2 = crlnk2
end
 attr_accessor :crnum, :crname, :status, :node1, :node2, :cost, :crqdat, :crlnk1, :crlnk2
end
#
def rdata(fld,oddata,ldata,crdata) # データの読み込み
file = open(fld)

 l = file.gets
 data = l.split(/\t/s)
 oddata.znum = data[1].to_i # zone数

 l = file.gets
 data = l.split(/\t/s)
 oddata.zname = data

 onum = oddata.znum
 $od = Array.new(onum){Array.new(onum)}
 for i  in 1..onum
  l = file.gets
  data = l.split(/\t/s)
  $od[i] = data
 end
 oddata.od_dat = $od
 l = file.gets
 data = l.split(/\t/s)

 ldata.lnum = data[1].to_i # link数

 l = file.gets
 ln = Array.new(ldata.lnum)
 n1 = Array.new(ldata.lnum)
 n2 = Array.new(ldata.lnum)
 len = Array.new(ldata.lnum)
 sp = Array.new(ldata.lnum)
 lco =  Array.new(ldata.lnum)
 qdat =  Array.new(ldata.lnum)
 for i in 1..ldata.lnum
  l = file.gets
 data = l.split(/\t/s)
  ln[i] = data[0]
  n1[i] = data[1]
  n2[i] = data[2]
  len[i] = data[3].to_f
  sp[i] = data[4].to_f
  if sp[i] != 0 then
   lco[i] = (len[i]*0.001/sp[i])*3600
  else
   lco[i] = 0
  end
 end
 ldata.lname = ln
 ldata.node1 = n1
 ldata.node2 = n2
 ldata.linklen = len
 ldata.linkspeed = sp
 ldata.linkcost =lco
 ldata.linkqdat = qdat
 l = file.gets
 data = l.split(/\t/s)
 crdata.crnum = data[1].to_i
  l = file.gets
  cn = Array.new(crdata.crnum)
  st = Array.new(crdata.crnum)
  cn1 = Array.new(crdata.crnum)
  cn2 = Array.new(crdata.crnum)
  cc = Array.new(crdata.crnum)
  cqdat = Array.new(crdata.crnum)
  crdata.crlnk1 = Array.new(crdata.crnum)
  crdata.crlnk2 = Array.new(crdata.crnum)
  for i in 1..crdata.crnum
   l = file.gets
   data = l.split(/\t/s)
   cn[i] = data[0]
   st[i] = data[1]
   cn1[i] = data[2]
   cn2[i] = data[3]
   cc[i] = data[4].to_f
  end
   crdata.crname = cn
   crdata.status = st
   crdata.node1 = cn1
   crdata.node2 = cn2
   crdata.cost = cc
   crdata.crqdat = cqdat
  for i in 1..crdata.crnum
   for j in 1..ldata.lnum
      if (crdata.node1[i]== ldata.node1[j]) && (crdata.crname[i] == ldata.node2[j]) then
       crdata.crlnk1[i] = ldata.lname[j] # 上流側のリンク
      end
      if (crdata.crname[i]== ldata.node1[j]) && (crdata.node2[i] == ldata.node2[j]) then
        crdata.crlnk2[i] = ldata.lname[j] # 下流側のリンク
      end
   end
  end
end
#
def dijkstra(org,dst,ldata,crdata,ndata) # 最短経路探査(ダイクストラ法)
$zlnk.clear
$zjj.clear
$znode.clear
$zcos.clear
cost = []
ndata.spath = []
for i in 1..ndata.node_num
ndata.jj[i] = ''
ndata.tsum[i] = 0.0
ndata.st[i] = 3
end # i

# 発ノードの判定
for i in 1..ndata.node_num
  if(ndata.node[i] == org) then
#   print "発ノード = ",org,"着ノード = ",dst,"\n"
    ndata.jj[i] = 'ZZ' # 発ノードを示す 
    ndata.tsum[i] = 0.0
    ndata.st[i] = 1
  end # if
end # i
#
$zcc=[]
iflg = 0
while iflg == 0
iflg = 1
$zlnk.clear
$znode.clear
$zcos.clear
for i in 1..ndata.node_num
ndata.nchk[i] = 0
end # i
for i in 1..ndata.node_num
$zlnk.clear
$znode.clear
$zcos.clear
if (ndata.st[i] == 1) && (ndata.nchk[i] ==0) then
  for j in 1..ndata.ldn[i]
    for l in 1..ldata.lnum
      if( ndata.lnk[i][j] == ldata.lname[l] ) then
        $znode.push(ldata.node2[l]) # 下流側のノード
        $zcos.push(ldata.linkcost[l]) # リンクの所要時間
      end # if
    end # l
        $zlnk.push(ndata.lnk[i][j]) # 下流側リンク
  end # j

  for l in 1..ldata.lnum
    if(ndata.jj[i] == ldata.node1[l]) && (ndata.node[i] == ldata.node2[l])
      ulnk = ldata.lname[l] # ulnk 上流側リンク
    end # if
  end # l
  ncc = 0
  for n in 0..$znode.length-1
   for nn in 1..ndata.node_num
    if $znode[n] == ndata.node[nn]
      ncc = nn
    end
   end # nn
   if ndata.st[ncc] !=1 then
   ndata.st[ncc] = 2
   ndata.jj[ncc] = ndata.node[i]
   end
  end # n
  for n in 0..$znode.length-1
    $zcc[n] = 0.0
  end # n
  for n in 0..$znode.length-1
   for m in 1..crdata.crnum
    if(crdata.crlnk1[m] == ulnk) && (crdata.crlnk2[m] == $zlnk[n]) then
     $zcc[n] = crdata.cost[m] # 交差点通過時の所要時間
    end # if
   end # m
  end # n
  ncc = 0
  for n in 0..$znode.length-1
   for nn in 1..ndata.node_num
    if $znode[n] == ndata.node[nn]
      ncc = nn
    end
   end # nn
  if ndata.st[ncc] !=1 then
    ndata.tsum[ncc] += $zcos[n]+$zcc[n]
  end
  end # n
  ndata.nchk[i] = 1
end # if
end # i

#
fast_i = 0
$fast_tsum = 9999.9
$fchk = 0
for i in 1..ndata.node_num
if ndata.st[i] == 2 then
 if($fast_tsum > ndata.tsum[i]) then
   $fast_tsum = ndata.tsum[i]
   fast_i = i
 end # if
end # if
end # i

ndata.st[fast_i] = 1
iflg = 1
for i in 1..ndata.node_num
if ndata.st[i] > 1 then
 iflg = 0
end # if
end # i
end # while

# 最短経路の抽出

$nc = []
$rpath = []

for i in 1..ndata.node_num
$nc[i] = 0
end # i
$echk = dst
iflg = 0
#
while iflg == 0
for i in 1..ndata.node_num
if(ndata.node[i] == $echk) then
 $rpath.push(ndata.node[i])
 $echk = ndata.jj[i]
 $nc[i] = 1
 if $echk == org then
   iflg = 1
   break
 end # if
end # if
end # i
end # while
$rpath.push(org)
for i in 0..$rpath.length-1
k=$rpath.length-1-i
ndata.spath[k] = $rpath[i]
end # i
# 最短経路
print "org=",org,"\t","dst=",dst,"\t","spath=",ndata.spath,"\n"
end
#######################################################
# main
#######################################################
begin
doc = ARGV[0]
oddata=ODdata.new
ldata = Ldata.new
crdata = Crdata.new
ndata = Ndata.new
ndata.node = Array.new(1)

rdata(doc,oddata,ldata,crdata)
# puts crdata.crname
for i in 1..oddata.znum
# puts oddata.zname[i]
for j in 1..oddata.znum
$od[i][j] = oddata.od_dat[i][j].to_f
end # j
end # i
# STEP0 リンク表の作成############################
for i in 1..ldata.lnum
nflg = 0
  for j in 0..ndata.node_num
    if(ldata.node1[i] == ndata.node[j]) then
     nflg = 1
    end # if
  end # j
  if(nflg == 0) then
   ndata.node_num += 1
   ndata.node[ndata.node_num] = ldata.node1[i] 
  end # if
end # i
for i in 1..ldata.lnum
nflg = 0
  for j in 0..ndata.node_num
    if(ldata.node2[i] == ndata.node[j]) then
     nflg = 1
    end # if
  end # j
  if(nflg == 0) then
   ndata.node_num += 1
   ndata.node[ndata.node_num] = ldata.node2[i] 
  end # if
 ldata.linkqdat[i] = 0
end #i
for i in 1..crdata.crnum
crdata.crqdat[i] = 0.0
end # i
# puts ndata.node
# print 'node_num= ',ndata.node_num,"\n"
ndata.ldn = Array.new(ndata.node_num)
ndata.st = Array.new(ndata.node_num)
ndata.jj = Array.new(ndata.node_num)
ndata.tsum = Array.new(ndata.node_num)
ndata.nchk = Array.new(ndata.node_num)
ndata.nlc = Array.new(ndata.node_num){Array.new(10)}
for i in 1..ndata.node_num
ndata.tsum[i] = 9999.99
end # i
ndata.nchk[1] = 0
$nlink = Array.new(40){Array.new(10)}
$nlink[0][0] = 0
$zlnk = Array.new(0)
$znode = Array.new(0)
$zcos = Array.new(0)
$zjj = Array.new(0)
#
for i in 1..ndata.node_num
lnn = 0
for j in 1..ldata.lnum
  if(ndata.node[i] == ldata.node1[j]) then
    lnn += 1
    ndata.ldn[i]= lnn
    $nlink[i][lnn] = ldata.lname[j]
  end # if
end # j
end # i
# ndata.st : 1:起点ノードから最短経路が見つかったノード集合 2: 集合1の候補 3:残りのノード
ndata.lnk= $nlink
for i in 1..ndata.node_num
ndata.st[i] = 3 # 初期値の設定
ndata.nchk[i] = 0
end # i
# dijkstra法による最短経路の算出,リンク交通量の算出
for i in 1..oddata.znum
 org = oddata.zname[i]
for j in 1..oddata.znum
 if i != j then
  dst = oddata.zname[j]
  dijkstra(org,dst,ldata,crdata,ndata)
#  print "ndata.spath=",ndata.spath,"\n"
#  print "oddata= ",oddata.od_dat[i][j],"\n"
# リンク交通量の算出
  for k in 0..ndata.spath.length-2
   n1 = ndata.spath[k]
   n2 = ndata.spath[k+1]
    for h in 1..ldata.lnum
     if((n1==ldata.node1[h])&&(n2==ldata.node2[h])) then
       ldata.linkqdat[h] += oddata.od_dat[i][j]
     end # if
    end # h
  end # k
# 交差点方向別交通量の算出
  for l in 0..ndata.spath.length-3
      cn = ndata.spath[l+1]
      c1 = ndata.spath[l]
      c2 = ndata.spath[l+2]
    for m in 1..crdata.crnum
      if((crdata.crname[m] == cn)&&(crdata.node1[m]==c1)&&(crdata.node2[m]==c2)) then
        crdata.crqdat[m] += oddata.od_dat[i][j]
      end # if
    end # m
  end # l
 end # if
end # j
end # i

# リンク交通量の出力
print "リンク交通量算出結果\n"
print "リンク番号","\t","交通量","\n"
for i in 1..ldata.lnum
print ldata.lname[i],"\t",ldata.linkqdat[i],"\n"
end # i
# 交差点方向別交通量の出力
print "交差点方向別交通量の算出結果\n"
print "交差点","\t","node1","\t","node2","\t","status=","\t","方向別交通量","\t","上流リンク","\t","下流リンク","\n"
for i in 1..crdata.crnum
print crdata.crname[i],"\t",crdata.node1[i],"\t",crdata.node2[i],"\t",crdata.status[i],"\t",crdata.crqdat[i],"\t",crdata.crlnk1[i],"\t",crdata.crlnk2[i],"\n"
end # i


end

この記事が気に入ったらサポートをしてみませんか?