------------------------------------------ ------------------------------------------ ----- A System Matrix Implementation ----- ----- using Sparse Matrix Methods, ----- ----- and Energy Flow Processing ----- ----- ----- ----- John Ringland ----- ----- 2004/11/21 ----- ------------------------------------------ ------------------------------------------ -- this file uses sparse matrix energy flow methods -- to implement an ergodic pure metric sysWrapped SMN framework -- using System Transforms. -- Sparse matrix elements are either scalar multipliers or they are function Id's -- and these are stored in both row and column entries of the sparse matrix. with trace include misc.e -- for the pretty_print function include SparseSM.e -- for sparse system matrices --without type_check --with profile_time --with profile -- some constants to make the data accessing more human readable -- -- System Model components global constant model_ = 1 global constant ST_ = 1 -- operator list global constant SM_ = 2 -- system matrix global constant SV_ = 3 -- state vector global constant CU_ = 4 -- update list --global constant MD_ = 4 -- matrix element components global constant con_ = 1 -- converging global constant div_ = 2 -- diverging function union_SET(sequence set1, sequence set2) -- set1 and set2 are ordered lists of atoms with no duplicates -- this function performs the operation of the Union of the two sets by adding the -- elements of the smallest set to to the largest set if they are not already present. -- It takes advantage of the ordering of the sets to optimise the procedure. sequence result, set, data integer rId, slen1, slen2, slen, dlen rId = 1 slen1 = length(set1) slen2 = length(set2) if slen1 < slen2 then -- so that we iterate over the smallest set for efficiency data = set1 set = set2 slen = slen2 dlen = slen1 else data = set2 set = set1 slen = slen1 dlen = slen2 end if for i = 1 to dlen do -- uses rId so we search only that part of the set that the datum may be in -- this is possible because of the ordering of both sets. if rId > slen then set = set & data[i..dlen] exit end if result = BSearch(set[rId..slen],data[i]) rId += result[index_]-1 if not result[found_] then -- insert data[i] -- if new head if rId = 0 then set = {data[i]} & set slen += 1 rId += 2 -- if tail elsif rId = slen then -- because data is ordered the remainder can be appended set = set & data[i..dlen] exit -- if body else set = set[1..rId] & {data[i]} & set[rId+1..slen] slen += 1 rId += 2 end if else -- data[i] already in set rId += 1 end if end for return set end function global function step_Model(sequence mdl, integer nSteps) -- steps the model forwards by nSteps sequence st, sm, sv, rUpdate, cUpdate, row, rowData, new_sv object acc, col, data, rUr, interfaces, output, input st = mdl[ST_] sm = mdl[SM_] sv = mdl[SV_] new_sv = sv cUpdate = mdl[CU_] -- for each moment in time for n = 1 to nSteps do rUpdate = {} -- cUpdate is an ordered list of colId’s which require updating -- for each element of cUpdate for c = 1 to length(cUpdate) do -- find the matrix column col = get_col_SM(sm,cUpdate[c]) -- if the column existed in the matrix; for global outputs col=0 if sequence(col) then col = col[elemId_] -- to keep only the rowIds -- form the union of each column with rUpdate rUpdate = union_SET(rUpdate,col) end if end for cUpdate = {} -- empty cUpdate now that it has been used -- rUpdate is now an ordered list of rowId’s which require updating -- for each element of rUpdate for r = 1 to length(rUpdate) do -- retrieve the Row from the sm rUr = rUpdate[r] row = get_row_SM(sm, rUr) acc = {} -- for each matrix element in that row rowData= row[Data_] for e = 1 to length(rowData) do interfaces = rowData[e] if sequence(interfaces) then -- process the interface function pipelines -- separate input from output pipelines output = interfaces[div_] input = interfaces[con_] if sequence(output) then data = sv[row[elemId_][e]] for f = length(output) to 1 by -1 do data = call_func(output[f], {data}) end for else data = output * sv[row[elemId_][e]] end if if sequence(input) then for f = length(input) to 1 by -1 do data = call_func(input[f], {data}) end for else data = input * data end if else data = interfaces * sv[row[elemId_][e]] end if acc = acc & {data} end for -- here we apply the system transform to the merged input if st[rUr] >= 0 then acc = call_func(st[rUr], {acc}) elsif length(acc)=1 then -- prevent the accumulation of brackets around single datums acc = acc[1] end if -- compare the accumulated result with the sv element -- if different then if not equal(acc, sv[rUr]) then -- store the accumulated result in the corresponding sv element new_sv[rUr] = acc -- insert the rowId into cUpdate to indicate that the sv element has changed cUpdate = cUpdate & rUr end if end for sv = new_sv end for return {{st,sm,sv,cUpdate},nSteps} end function global procedure print_sv(sequence sv, sequence sv_names) for i = 1 to length(sv) do puts(1,"\n# ") puts(1, sv_names[i]) puts(1, " #####\n") pretty_print(1,sv[i],{}) end for end procedure