--A buffer

data module Data
begin
  parameters
    Data
      begin
        sorts
          D
      end Data
end Data

process module Buffer
begin
  exports
    begin
      atoms
        r,s : D
      processes
        Buffer
    end
  imports
    Data
  definitions
    Buffer = sum(d in D, r(d) . s(d)) . Buffer
end Buffer

data module TheData
begin
  exports
    begin
      sorts
        TheData
      functions
        d1 : -> TheData
        d2 : -> TheData
        d3 : -> TheData
    end
end TheData

--Instantation of a buffer (fitted for simulation)

process module DataSet
begin
  exports
    begin
      sets of TheData
        DataSet = {d1,d2,d3}
    end
  imports
    TheData
end DataSet

process module SimBuffer
begin
  parameters
    DSet
      begin
        sets of D
          DSet
      end DSet
  exports
    begin
      atoms
        r,s : D
      processes
        Buffer
    end
  imports
    Data
  definitions
    Buffer = sum(d in DSet, r(d) . s(d)) . Buffer
end SimBuffer

process module BoundBuffer
begin
  imports
    SimBuffer
      {Data bound by [D -> TheData] to TheData
       DSet bound by [DSet -> DataSet] to DataSet}
end BoundBuffer

--A collection of buffers

data module BufferId
begin
  parameters
    BufferId
      begin
        sorts
          BufferId
        functions
          next : BufferId -> BufferId
          first : -> BufferId
          last : -> BufferId
      end BufferId
end BufferId

process module Buffers
begin
  exports
    begin
      atoms
        r,s,c : BufferId # D
      processes
        System
	Buffer : BufferId
    end
  imports
    BufferId, Data
  sets
    of atoms
      H = {r(i,d),s(i,d)| i in BufferId, d in D} \
          {r(first,d), s(last,d) | d in D}
    of BufferId
      BufferSet = BufferId\{last}
  communications
    r(i,d) | s(i,d) = c(i,d) for i in BufferId, d in D
  variables
    id : -> BufferId
  definitions
    Buffer(id) = sum(d in D, r(id,d) . s(next(id),d)) . Buffer(id)
    System = encaps(H, merge(id in BufferSet, Buffer(id)))
end Buffers

--Instantiation of a collection of buffers (fitted for simulation)

data module TheId
begin
  exports
    begin
      sorts
        TheId
      functions
        b1 : -> TheId
        b2 : -> TheId
        b3 : -> TheId
        first : -> TheId
        last : -> TheId
        next : TheId -> TheId
    end
  equations
  [1] next(b1) = b2
  [2] next(b2) = b3
  [3] next(b3) = b3
  [4] first = b1
  [5] last = b3
end TheId

process module BufferSet
begin
  exports
    begin
      sets of TheId
	BufferSet = {b1,b2}
    end
  imports
    TheId
end BufferSet

process module SimBuffers
begin
  parameters
    DSet
      begin
        sets of D
          DSet
      end DSet,
    BSet
      begin
	sets of BufferId
	  BufferSet
      end BSet
  exports
    begin
      atoms
        r,s,c : BufferId # D
      processes
        System
    end
  imports
    BufferId, Data
  processes
    Buffer : BufferId
  sets
    of atoms
      H = {r(i,d),s(i,d)| i in BufferId, d in D} \
          {r(first,d), s(last,d) | d in D}
  communications
    r(i,d) | s(i,d) = c(i,d) for i in BufferId, d in D
  variables
    id : -> BufferId
  definitions
    Buffer(id) = sum(d in DSet,
                    r(id,d) . s(next(id),d)) . Buffer(id)
    System = encaps(H, merge(id in BufferSet, Buffer(id)))
end SimBuffers

process module BoundBuffers
begin
  imports
    SimBuffers
      {Data bound by [D -> TheData] to TheData
       DSet bound by [DSet -> DataSet] to DataSet
       BufferId bound by
         [BufferId -> TheId, next -> next, first -> first, last -> last]
                to TheId
       BSet bound by [BufferSet -> BufferSet] to BufferSet}
end BoundBuffers

--Two buffers without data (fitted for verification)

process module TwoBuffers
begin
  exports
    begin
      atoms
        r1,s2,r2,s3,c2
      processes
        System
        TBB
    end
  processes
    Buffer1, Buffer2     -- two One Bit Buffers
    TBB', TBB''          -- one Two Bit Buffer
  sets of atoms
    H = {s2,r2}
    I = {c2}
  communications
    s2 | r2 = c2
  definitions
    Buffer1 = r1 . s2 . Buffer1
    Buffer2 = r2 . s3 . Buffer2
    System = hide(I, encaps(H, Buffer1 || Buffer2))

    TBB = r1 . TBB' 
    -- + r1 . TBB''
    --add the previous line to get an incorrect specification
    TBB' = s3 . TBB + r1 . TBB''
    TBB'' = s3 . TBB'
end TwoBuffers

--Testing:

-- psf -vm Buffer buf
-- psf -vsm BoundBuffer buf
-- initial -c BoundBuffer.til
-- sim BoundBuffer.til
-- psf -vm Buffers buf
-- psf -vsm BoundBuffers buf
-- initial -c BoundBuffers.til
-- sim BoundBuffers.til
-- psf -vsm TwoBuffers buf
-- sim TwoBuffers.til
-- trans TwoBuffers.til
-- equiv -d -t System,TBB TwoBuffers.lts
