状態遷移表をLTSAスクリプトに変換する

Excel上に記述した状態遷移表をF#プログラムでLTSAスクリプトに変換する。

状態遷移表

f:id:borsalino:20161010161329p:plain

LTSAスクリプト

Process=S0,
S0=
  (_オン->S2
  |_強->S1),
S1=
  (_オン->S3
  |_弱->S0),
S2=
  (_オフ->S0
  |_強->S3),
S3=
  (_オフ->S1
  |_弱->S2).

LTSA状態遷移図

f:id:borsalino:20161010210918p:plain

変換ツール

open Microsoft.Office.Interop.Excel
open System.Runtime.InteropServices
open System.Text.RegularExpressions

type CellValue = string
type CellToValue = System.Object -> CellValue
type ColumnsToValues = Range -> CellValue[]
type RowsToValues = Range -> CellValue[]
type MatrixToValues = Range -> CellValue[][]

type State = CellValue
type Variable = CellValue
type Value = CellValue
type Action = CellValue
type Trans = CellValue

type TransExpPart = string
type TransExp = string
type Script = string

let CreateRange (cell:Range, rows:int, columns:int) =
  cell.Address() + ":" + cell.Offset(rows-1,columns-1).Address()
let CellToValue (cell:System.Object):CellValue = (cell:?>Range).Value2:?>CellValue
let ColumnsToValues (range:Range) =
  [|for i in 1..range.Columns.Count do yield (range.[1,i] |> CellToValue)|]
let RowsToValues (range:Range):CellValue[] =
  [|for i in 1..range.Rows.Count do yield (range.[i,1] |> CellToValue)|]
let MatrixToValues (range:Range):CellValue[][] =
  [|for i in 1..range.Rows.Count do 
      yield [|for j in 1..range.Columns.Count do 
                yield (range.[i,j] |> CellToValue)|]|]
module ltsa =
  let ToTransExpPart (action,trans):TransExpPart =
    let exp = sprintf"%s->%s" action trans
    match Regex.IsMatch("[a-z_].+",trans) with
    |true -> exp
    |_ -> "_" + exp

  let ToTransExp ((states:string[]),(actions:string[]),(transitions:string[][])):TransExp=
    [|for i in 0..states.Length-1 do
        let subpro = states.[i] + "=\n"
        let trans = 
          [|for j in 0..actions.Length-1 do
              match transitions.[i].[j] with
              |"×" -> yield ""
              |_ -> yield ((actions.[j],transitions.[i].[j])|>ToTransExpPart)|]
            |> Array.filter (fun x->x.Length>0) |> String.concat "\n  |"
        yield subpro + "  (" + trans + ")"          
    |] |> String.concat ",\n"
  
  let ToScript (transExp):Script =
    transExp |> sprintf "Process=S0,\n%s."

let excel = ApplicationClass(Visible = false)
let dir = System.IO.Directory.GetCurrentDirectory() 
let workbooks = excel.Workbooks.Open(dir + @"\sample.xlsx")
let worksheet = workbooks.Sheets.["Sheet1"] :?> Worksheet

let StateRange = worksheet.Range("A2:A5") // .Range("State")
let VariableRange = worksheet.Range("B1:D1") // .Range("Variable")
let ActionRange = worksheet.Range("E1:H1") // .Range("Action")
let ValueRange =
  (VariableRange.[2,1]:?>Range,
   StateRange.Rows.Count,
   VariableRange.Columns.Count) |> CreateRange
let TransitionsRange =
  (ActionRange.[2,1]:?>Range,
   StateRange.Rows.Count,
   ActionRange.Columns.Count) |> CreateRange
    
let ToRange address = worksheet.Range(address)

let script = 
  (StateRange |> RowsToValues,
   ActionRange |> ColumnsToValues,
   TransitionsRange |> ToRange |> MatrixToValues) 
      |> ltsa.ToTransExp
      |> ltsa.ToScript

excel.Quit()
excel |> Marshal.ReleaseComObject |> ignore
  
System.IO.File.WriteAllText("ltsa.txt",script)