------------------------------------------
------------------------------------------
----- A System Matrix Implementation -----
----- using Sparse Matrix Methods,   -----
----- and Energy Flow Processing     -----
-----                                -----
----- By John Ringland               -----
----- 2004/11/22                     -----
------------------------------------------
------------------------------------------

-- this file uses sparse matrix energy flow methods
-- to implement an ergodic pure metric sysWrapped SMN framework

with trace
include ergodicSysMSMN.e

---------------------------------
---------------------------------
-----     Test Model of a   -----
-----  Drink Machine system -----
---------------------------------
---------------------------------

-- The previous model drink machine (ergodicSysMSMN_DrinkMachine00.ex) had the problem that
-- its outputs disapeared if one didn't take them immediately,
-- Not very good for slow movers...
-- So that has been fixed in this model


--                         1   2   3   4   5   6   7   8   9  10  11  12  13
--                    -------------------------------------------------------
--1   chosen          |    0   1   0   1   0   0   0   0   0   0   0   0   1
--                    | 
--2   available       | F2 0   0  F23  1   0   0   1   0   0   0   0   0   0
--                    |
--3   drink reservoir | F3 F31 0   1   0   0   0   0   0   0   1   0   0   0
--                    |
--4   drink prices    |    0   0   0   0   0   0   0   0   0   0   0   0   0
--                    |
--5   change calc     |   F51  0   0   0   0   0   1   0   0   0   0   0   0
--                    |
--6   coin adder      |    0   0   0   0  F65  0   0   0   0   0   0  F612 0
--                    |
--7   coin total      | F7 0   0   0   0   0   1   1   0   0   0   0   0   0
--                    |
--8   coin reservoir  | F8 0   0   0   0  F85  0   0   0   0   0   0   1   0
--                    |
--9   change shute    | F9 0   0   0   0   0   0   0   1   1   0   0   0   0
--                    |
--10  drink shute     |F10 0   0   1   0   0   0   0   0   0   1   0   0   0
--                    |
--11  lights          |    0   1   0   0   0   0   0   0   0   0   0   0   0
--                    |
--12  coin slot       |    0   0   0   0   0   0   0   0   0   0   0   0   0
--                    |
--13  buttons         |    0   0   0   0   0   0   0   0   0   0   0   0   0
--                    |

-- used when printing out the system state vector
sequence sv_names
sv_names = {"chosen","available","drink reservoir","drink prices","change calc",
    "coin adder","coin total","coin reservoir","change shute","drink shute","lights",
    "coin slot","buttons"}

-- F(2,3) takes the state of the drink_reservoir and extracts its inventory
function F23_(sequence in) --{inventory, dispensed_drink}
    return in[1]  -- inventory
end function

integer F23
F23 = routine_id("F23_")

-- F(3,1) extracts the button_id from chosen's input and sends this to drink_reservoir
function F31_(sequence in) --{availability vector, drink prices list, button id}
    return in[3]  -- button_id if it is available
end function

integer F31
F31 = routine_id("F31_")

-- F(5,1) extracts the price that corresponds to drink_id from drink_prices and sends to change_calc
function F51_(sequence in) --{availability_vector, drink_prices:{price,..}, button_id}
    integer button_id
    button_id = in[3]
    if button_id and in[1][button_id] then
        return in[2][button_id]  -- price that corresponds to button_id=drink_id only if available
    end if
    return 0
end function

integer F51
F51 = routine_id("F51_")

-- F(6,5) if change_calc's input (price) is non-zero then reset=1
function F65_(sequence in) --{price, coin_total}
    return in[1] != 0 -- price!=0
end function

integer F65
F65 = routine_id("F65_")

-- F(6,12) for the coin in the slot it determines the value of the coin
function F612_(sequence in) --{value} where a coin is a sequence containing value coin:{value}
    return in[1]  -- value
end function

integer F612
F612 = routine_id("F612_")

-- F(8,5) calculates the difference between price and coin_total to determine required change
function F85_(sequence in) --{price, coin_total}
    integer price
    price = in[1]
    if price then
        return in[2] - price  -- coin_total-price
    end if
    return 0
end function

integer F85
F85 = routine_id("F85_")

-- F2 takes drink_prices, drink inventory and coin_total and produces an availability vector
function F2_(sequence in) --{ inventory, drink_prices:{price,..}, coin_total}
    sequence vect, price, inv
    integer len, total
    len = length(in[1])
    vect = repeat(0, len)
    inv = in[1]
    price = in[2]
    total = in[3]
    for i = 1 to len do
        if inv[i][2] and price[i]<= total then
            vect[i] = 1
        end if
    end for
    return vect  -- {0,1,1,0} for example if the second and third drinks are available 
end function

integer F2
F2 = routine_id("F2_")

-- F3 takes a drink_id and its previous state and subtracts one from its inventory then outputs this tally plus any required drinks
function F3_(sequence in) --{drink_id, {inventory, dispensed_drink}, drink_dispensed}
    sequence inv, dispensed_drink
    integer drink_id
    drink_id = in[1]
    inv = in[2][1]
    if drink_id then
        inv[drink_id][2] -= 1
        return {inv,inv[drink_id][1]}  -- {inventory, dispensed_drink}
    end if
    if not equal(in[3],"none") then -- if drink_dispensed
        dispensed_drink = "none"
    else
        dispensed_drink = in[2][2]
    end if
    return {inv,dispensed_drink}
end function

integer F3
F3 = routine_id("F3_")

-- F7 takes {{the reset bool and any new coin values} and the previous total} and
-- determines a new total
function F7_(sequence in) --{{reset, new_value}, coin_total}
    if in[1][1] then
        return in[1][2] -- new_value if reset=1  
    else
        return in[1][2]+in[2]  -- new_value + coin_total if reset=0
    end if
end function

integer F7
F7 = routine_id("F7_")

sequence coin_tally, values
values     = { 5,  10,  20,  50,  100, 200}
coin_tally = {100, 100, 100, 100, 100, 100}
-- F8 takes a change_value and an input coin, it adds the coin to its internal tally
-- and subtracts the change from its internal tally and outputs the requested change coins.
function F8_(sequence in) --{change_value, new_coin}
    integer val, chng, coin
    sequence output
    coin = in[2][1]
    if coin then
        val = find(in[2][1], values)
        coin_tally[val] += 1
    end if
    chng = in[1]
    output = {}
    if chng then
        while chng do
            if chng - 200 >= 0 then
                if values[6] then
                    chng -= 200
                    coin_tally[6] -= 1
                    output = output & {{200}}
                end if
            elsif chng - 100 >= 0 then
                if values[5] then
                    chng -= 100
                    coin_tally[5] -= 1
                    output = output & {{100}}
                end if
            elsif chng - 50 >= 0 then
                if values[4] then
                    chng -= 50
                    coin_tally[4] -= 1
                    output = output & {{50}}
                end if
            elsif chng - 20 >= 0 then
                if values[3] then
                    chng -= 20
                    coin_tally[3] -= 1
                    output = output & {{20}}
                end if
            elsif chng - 10 >= 0 then
                if values[2] then
                    chng -= 10
                    coin_tally[2] -= 1
                    output = output & {{10}}
                end if
            elsif chng - 5 >= 0 then
                if values[1] then
                    chng -= 5
                    coin_tally[1] -= 1
                    output = output & {{5}}
                end if
            else
                exit
            end if
        end while
    end if
    return output  -- {change_coins} where change coins is a sequence of coins of particular denominations.
end function

integer F8
F8 = routine_id("F8_")

-- F9 takes the output of the coin_reservoir and the shute_state and manages the shute_state
function F9_(sequence in) --{{coin,...}, shute_state}
    sequence shute, chng
    chng = in[1]
    shute = in[2]
    if length(shute) then
        return shute
    end if
    return chng
end function

integer F9
F9 = routine_id("F9_")

-- F10 takes the state of the drink_reservoir and the shute_state and manages the shute_state
function F10_(sequence in) --{{inventory, dispensed_drink}, shute_state}
    sequence shute
    shute = in[2]
    if equal(shute,"none") then
        return in[1][2]  -- dispensed_drink
    end if
    return shute
end function

integer F10
F10 = routine_id("F10_")


-- Assembling all the model components...

sequence st, sm, sv, model, cUpdate, result

-- constructing the singular transform vector
st = {-1,F2,F3,-1,-1,-1,F7,F8,F9,F10,-1,-1,-1}

-- constructing the Metric System Matrix element by element
sm = sparse_SM(13,13)
sm = set_SM(sm, {1,2}, 1)
sm = set_SM(sm, {1,4}, 1)
sm = set_SM(sm, {1,13}, 1)
sm = set_SM(sm, {2,3}, {{F23},1})
sm = set_SM(sm, {2,4}, 1)
sm = set_SM(sm, {2,7}, 1)
sm = set_SM(sm, {3,1}, {1,{F31}})
sm = set_SM(sm, {3,3}, 1)
sm = set_SM(sm, {3,10}, 1)
sm = set_SM(sm, {5,1}, {1,{F51}})
sm = set_SM(sm, {5,7}, 1)
sm = set_SM(sm, {6,5}, {1,{F65}})
sm = set_SM(sm, {6,12}, {{F612},1})
sm = set_SM(sm, {7,6}, 1)
sm = set_SM(sm, {7,7}, 1)
sm = set_SM(sm, {8,5}, {1,{F85}})
sm = set_SM(sm, {8,12}, 1)
sm = set_SM(sm, {9,8}, 1)
sm = set_SM(sm, {9,9}, 1)
sm = set_SM(sm, {10,3}, 1)
sm = set_SM(sm, {10,10}, 1)
sm = set_SM(sm, {11,2}, 1)

sequence inv, prices
-- 100 each of four types of drinks
inv = {{"cola",100},{"lemonade",100},{"juice",100},{"water",100}}

-- prices in cents for the four drink types
prices = {120,120,100,80}

-- constructing the final State Vector
sv = {{{0,0,0,0},prices,0},{0,0,0,0},{inv,"none"},prices,{0,0},{0,0,0},0,{},{},"none",0,{100},0}

-- flagging the initial inputs for processing by the energy flow algorithm
cUpdate = {12}

-- combining all of the above into a single system model
model = {st,sm,sv,cUpdate}

puts(1,"\n\nDrink Machine System\n\n")
puts(1,"initial model\n")
? model

puts(1,"\nWe have inserted a one dollar coin in the coin_slot\n")
puts(1,"\n\nfirst iteration\n")
result = step_Model(model, 1)
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nIt is now registered in coin_tally and in the coin adders new_value\n")
puts(1,"\n\nNow setting coin slot = {0} for no coin\n")
result[model_][SV_][12] = {0}
result[model_][CU_] = result[model_][CU_] & {12}
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\n\nsecond iteration\n")
result = step_Model(result[model_], 1)
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nIt is now registered in coin_total\n")
puts(1,"\n\nthird iteration\n")
result = step_Model(result[model_], 1)
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nNow the availability vector has been created, coin_total has been registered\n")
puts(1,"by change_calc and the new zero coin_value has been registered by coin_adder\n")
puts(1,"\n\nfourth iteration\n")
result = step_Model(result[model_], 1)
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nThe new availability vector has been registered by chosen and the lights have\n")
puts(1,"come on for juice and water.\n")
puts(1,"\n\nfifth iteration\n")
result = step_Model(result[model_], 1)
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nNow it has reached a steady state and is waiting for more input\n")
puts(1,"\n\nSo now we can choose some water by pressing the fourth button.\n")
result[model_][SV_][13] = 4
result[model_][CU_] = result[model_][CU_] & {13}
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\n\nsixth iteration\n")
result = step_Model(result[model_], 1)
puts(1,"\nI now take the finger off the button\n")
result[model_][SV_][13] = 0
result[model_][CU_] = result[model_][CU_] & {13}
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nThe button press has been registered by chosen\n")
puts(1,"\n\nseventh iteration\n")
result = step_Model(result[model_], 1)
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nA water has been dispensed by drink_reservoir, the price has been registered\n")
puts(1,"by change_calc and the button release has been registered by chosen\n")
puts(1,"\n\neighth iteration\n")
result = step_Model(result[model_], 1)
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nA reset has been registered by coin_adder, the change has been dispensed\n")
puts(1,"by the coin_reservoir and a water is now present in the drink shute\n")
puts(1,"\n\nninth iteration\n")
result = step_Model(result[model_], 1)
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nThe drink_reservoir has finished dispensing the drink, the price has been cleared\n")
puts(1,"from change_calc, the coin_total has been reset to zero and the change is now\n")
puts(1,"present in the change shute\n")
puts(1,"\n\ntenth iteration\n")
result = step_Model(result[model_], 1)
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nThe availability vector has gone dormant (no money so none available), the reset\n")
puts(1,"coin_total has been registered by change_calc, the reset coin_total has been registered\n")
puts(1,"by coin_adder and the coin_reservoir has finished dispensing the change\n")
puts(1,"\n\neleventh iteration\n")
result = step_Model(result[model_], 1)
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nThe Null availability vector has been registered\n")
puts(1,"by chosen and the lights have turned off\n")
puts(1,"\n\ntwelfth iteration\n")
result = step_Model(result[model_], 1)
print_sv(result[model_][SV_], sv_names)
puts(1,"\n# Coin Tally  #####\n")
? coin_tally
puts(1,"# Update List  #####\n")
? result[model_][CU_]
puts(1,"\nThe Drink Machine is now in a dormant state waiting for input,\n")
puts(1,"there is one less water in the inventory, one extra dollar coin\n")
puts(1,"and one less 20c coin in the coin_tally, one water in the drink shute\n")
puts(1,"and one 20c coin in the change shute.\n")

www.Anandavala.info