global Arguments
  int n, w
  string[20] fname
body Arguments
  getarg(1, n); getarg(2, w); getarg(3, fname)
end

global Shared
  import Arguments
  op bag(int path[1:*], int hops, int length)  # partial tours
  int dist[1:n,1:n]                # distances
  int  shortest = 2**30            # best so far
  op update(int path[1:*], int length)     # update shortest
body Shared
  file fd = open(fname, READ)
  for [ i = 1 to n, j = 1 to n ] { read(fd, dist[i,j]) }
  int  shortest_path[1:n]
  sem mutex = 1

  proc update(path, length)  {
    P(mutex)
      if (length < shortest) {
	shortest = length; shortest_path = path
      }
    V(mutex)
  }

  final {
    write("the shortest path has length", shortest)
    write("the cities on the shortest path are:")
    writes("  ")
    for [ i = 1 to n ] { writes(shortest_path[i], " ") }
    write()
  }
end

resource Worker()
  import Arguments, Shared

  # extend path to include city if city has not yet been visited
  procedure extend_path(int city, var int path[1:*], int hops, int length)
			returns int newlength {
    for [ i = 2 to hops st path[i] == city ] { newlength = 0; return }
    newlength = length + dist[path[hops], city]; path[hops+1] = city
  }

  process worker  {
    int  path[1:n], hops, length, newlength
    while (true) {
      receive bag(path, hops, length)
      for [ city = 2 to n ] {
	newlength = extend_path(city, path, hops, length)
	if (newlength == 0) { next }    # city has been visited
	if (hops+1 < n and newlength < shortest) {
	    # put partial tour back into bag for further processing
	    send bag(path, hops+1, newlength)
	} else if (hops+1 == n ) {
	    # add distance back to city 1
	    newlength = newlength + dist[path[n],1]
	    if (newlength < shortest) {
	      # this tour is possibly the best
	      update(path, newlength)
	    }
	}
      }
    }
  }
end Worker

resource Main()
  import Arguments, Shared, Worker
  # generate first set of partial tours and put them into bag
  int  path[1:n] = (1, [n-1] 0)
  for [ i = 2 to n ] {
    path[2] = i
    send bag(path, 2, dist[1,i])
  }
  # create worker processes
  for [ i = 1 to w ] { create Worker() }
end Main
