Alloyで出力したXMLをいじりやすくする

Alloyにも一応Evaluatorっていう対話的に値を観察するコンソールが付いているけども、出力された値をコピペ出来ないとか色々めんどくさくて、個人的にはもういっそJythonコンソールを突っ込んでしまえよと言いたくなるけど「お前がやれ」って言われそうでめんどくさいので、とりあえずXMLでエクスポートしたのをいじるライブラリを作りました。

ipythonで対話的に使うことを想定しています。

In [29]: load("a.xml")

In [30]: get("flag")
Out[30]: 
[[u'Memory$0', u'0', u'0', u'Time$0'],
 [u'Memory$0', u'0', u'0', u'Time$1'],
 [u'Memory$0', u'0', u'0', u'Time$2'],
 [u'Memory$0', u'0', u'1', u'Time$3'],
 [u'Memory$0', u'0', u'1', u'Time$4'],
 [u'Memory$0', u'0', u'1', u'Time$5'],
 [u'Memory$0', u'0', u'1', u'Time$6'],
 [u'Memory$0', u'1', u'0', u'Time$0'],
 [u'Memory$0', u'1', u'1', u'Time$1'],
 [u'Memory$0', u'1', u'1', u'Time$2'],
 [u'Memory$0', u'1', u'1', u'Time$3'],
 [u'Memory$0', u'1', u'1', u'Time$4'],
 [u'Memory$0', u'1', u'1', u'Time$5'],
 [u'Memory$0', u'1', u'1', u'Time$6']]

In [31]: get("flag").to_int(1, 2, 3)
Out[31]: 
[[u'Memory$0', u'0', u'0', u'Time$0', 0, 0, 0],
 [u'Memory$0', u'0', u'0', u'Time$1', 0, 0, 1],
 [u'Memory$0', u'0', u'0', u'Time$2', 0, 0, 2],
 [u'Memory$0', u'0', u'1', u'Time$3', 0, 1, 3],
 [u'Memory$0', u'0', u'1', u'Time$4', 0, 1, 4],
 [u'Memory$0', u'0', u'1', u'Time$5', 0, 1, 5],
 [u'Memory$0', u'0', u'1', u'Time$6', 0, 1, 6],
 [u'Memory$0', u'1', u'0', u'Time$0', 1, 0, 0],
 [u'Memory$0', u'1', u'1', u'Time$1', 1, 1, 1],
 [u'Memory$0', u'1', u'1', u'Time$2', 1, 1, 2],
 [u'Memory$0', u'1', u'1', u'Time$3', 1, 1, 3],
 [u'Memory$0', u'1', u'1', u'Time$4', 1, 1, 4],
 [u'Memory$0', u'1', u'1', u'Time$5', 1, 1, 5],
 [u'Memory$0', u'1', u'1', u'Time$6', 1, 1, 6]]

In [32]: get("flag").to_int(1, 2, 3).trans(6, 4, 5)
Out[32]: 
[[0, 0, 0],
 [1, 0, 0],
 [2, 0, 0],
 [3, 0, 1],
 [4, 0, 1],
 [5, 0, 1],
 [6, 0, 1],
 [0, 1, 0],
 [1, 1, 1],
 [2, 1, 1],
 [3, 1, 1],
 [4, 1, 1],
 [5, 1, 1],
 [6, 1, 1]]

In [33]: get("flag").to_int(1, 2, 3).trans(6, 4, 5).sort(0)
Out[33]: 
[[0, 0, 0],
 [0, 1, 0],
 [1, 0, 0],
 [1, 1, 1],
 [2, 0, 0],
 [2, 1, 1],
 [3, 0, 1],
 [3, 1, 1],
 [4, 0, 1],
 [4, 1, 1],
 [5, 0, 1],
 [5, 1, 1],
 [6, 0, 1],
 [6, 1, 1]]

In [34]: get("flag").to_int(1, 2, 3).trans(6, 4, 5).sort(0).map(lambda t, x, y: "%d: flag[%d] = %d" % (t, x, y))
Out[34]: 
['0: flag[0] = 0',
 '0: flag[1] = 0',
 '1: flag[0] = 0',
 '1: flag[1] = 1',
 '2: flag[0] = 0',
 '2: flag[1] = 1',
 '3: flag[0] = 1',
 '3: flag[1] = 1',
 '4: flag[0] = 1',
 '4: flag[1] = 1',
 '5: flag[0] = 1',
 '5: flag[1] = 1',
 '6: flag[0] = 1',
 '6: flag[1] = 1']

あとgroup_byとか欲しいかなぁ。Alloy的な結合演算も入れてもいいかも。

https://github.com/nishio/learning_alloy/blob/master/show.py

joinつけた

結合演算入れたよ!

In [16]: get("flag").trans(3, 1, 2)
Out[16]: 
[[u'Time$0', u'0', u'0'],
 [u'Time$1', u'0', u'0'],
 [u'Time$2', u'0', u'0'],
 [u'Time$3', u'0', u'1'],
 [u'Time$4', u'0', u'1'],
 [u'Time$5', u'0', u'1'],
 [u'Time$6', u'0', u'1'],
 [u'Time$0', u'1', u'0'],
 [u'Time$1', u'1', u'1'],
 [u'Time$2', u'1', u'1'],
 [u'Time$3', u'1', u'1'],
 [u'Time$4', u'1', u'1'],
 [u'Time$5', u'1', u'1'],
 [u'Time$6', u'1', u'1']]

In [17]: get('Time$6').join(_)
Out[17]: [[u'0', u'1'], [u'1', u'1']]

集計的な意味ではgroup_byだの複数の関係の張り合わせ(UNIXのpasteコマンドみたいな)とかやりたくなるけど、型的には微妙だなぁ。どうしようかなぁ。

っていうかそもそもmapの返り値がAlloyListなのがおかしいのか。AlloyListの範囲内でゴニョゴニョいじったあと、mapもしくはgroup_byで可視化のための関数に渡す、という使い方がよいのかな。

group_by入れた

In [21]: get("flag").trans(1, 2, 3).map(lambda x, y, t: [t, "flag[%s] = %s" % (x, y)])
Out[21]: 
[[u'Time$0', u'flag[0] = 0'],
 [u'Time$1', u'flag[0] = 0'],
 [u'Time$2', u'flag[0] = 0'],
 [u'Time$3', u'flag[0] = 1'],
 [u'Time$4', u'flag[0] = 1'],
 [u'Time$5', u'flag[0] = 1'],
 [u'Time$6', u'flag[0] = 1'],
 [u'Time$0', u'flag[1] = 0'],
 [u'Time$1', u'flag[1] = 1'],
 [u'Time$2', u'flag[1] = 1'],
 [u'Time$3', u'flag[1] = 1'],
 [u'Time$4', u'flag[1] = 1'],
 [u'Time$5', u'flag[1] = 1'],
 [u'Time$6', u'flag[1] = 1']]

In [22]: get("flag").trans(1, 2, 3).map(lambda x, y, t: [t, "flag[%s] = %s" % (x, y)]).group_by(0)
Out[22]: 
[(u'Time$0', [[u'Time$0', u'flag[0] = 0'], [u'Time$0', u'flag[1] = 0']]),
 (u'Time$1', [[u'Time$1', u'flag[0] = 0'], [u'Time$1', u'flag[1] = 1']]),
 (u'Time$2', [[u'Time$2', u'flag[0] = 0'], [u'Time$2', u'flag[1] = 1']]),
 (u'Time$3', [[u'Time$3', u'flag[0] = 1'], [u'Time$3', u'flag[1] = 1']]),
 (u'Time$4', [[u'Time$4', u'flag[0] = 1'], [u'Time$4', u'flag[1] = 1']]),
 (u'Time$5', [[u'Time$5', u'flag[0] = 1'], [u'Time$5', u'flag[1] = 1']]),
 (u'Time$6', [[u'Time$6', u'flag[0] = 1'], [u'Time$6', u'flag[1] = 1']])]

In [24]: get("flag").trans(1, 2, 3).map(lambda x, y, t: [t, "flag[%s] = %s" % (x, y)]).group_by(0, lambda k, xs: (k, ", ".join(x[1] for x in xs)))
Out[24]: 
[(u'Time$0', u'flag[0] = 0, flag[1] = 0'),
 (u'Time$1', u'flag[0] = 0, flag[1] = 1'),
 (u'Time$2', u'flag[0] = 0, flag[1] = 1'),
 (u'Time$3', u'flag[0] = 1, flag[1] = 1'),
 (u'Time$4', u'flag[0] = 1, flag[1] = 1'),
 (u'Time$5', u'flag[0] = 1, flag[1] = 1'),
 (u'Time$6', u'flag[0] = 1, flag[1] = 1')]

In [33]: get("turn").trans(2, 1, 2).join(_)
Out[33]: 
[[u'Time$0', u'0', u'flag[0] = 0, flag[1] = 0'],
 [u'Time$1', u'0', u'flag[0] = 0, flag[1] = 1'],
 [u'Time$2', u'0', u'flag[0] = 0, flag[1] = 1'],
 [u'Time$3', u'0', u'flag[0] = 1, flag[1] = 1'],
 [u'Time$4', u'1', u'flag[0] = 1, flag[1] = 1'],
 [u'Time$5', u'1', u'flag[0] = 1, flag[1] = 1'],
 [u'Time$6', u'1', u'flag[0] = 1, flag[1] = 1']]

In [35]: _.map(lambda t, x, y: "%s: turn = %s, %s" % (t, x, y))
Out[35]: 
[u'Time$0: turn = 0, flag[0] = 0, flag[1] = 0',
 u'Time$1: turn = 0, flag[0] = 0, flag[1] = 1',
 u'Time$2: turn = 0, flag[0] = 0, flag[1] = 1',
 u'Time$3: turn = 0, flag[0] = 1, flag[1] = 1',
 u'Time$4: turn = 1, flag[0] = 1, flag[1] = 1',
 u'Time$5: turn = 1, flag[0] = 1, flag[1] = 1',
 u'Time$6: turn = 1, flag[0] = 1, flag[1] = 1']

In [37]: print "\n".join(_)
Time$0: turn = 0, flag[0] = 0, flag[1] = 0
Time$1: turn = 0, flag[0] = 0, flag[1] = 1
Time$2: turn = 0, flag[0] = 0, flag[1] = 1
Time$3: turn = 0, flag[0] = 1, flag[1] = 1
Time$4: turn = 1, flag[0] = 1, flag[1] = 1
Time$5: turn = 1, flag[0] = 1, flag[1] = 1
Time$6: turn = 1, flag[0] = 1, flag[1] = 1

わーいわーい