はてなキーワード: Graphvizとは
効用関数 U: X → ℝ が消費者の選好を定義し、効用空間 X 上のレベルセットが無差別曲線を形成する。無差別曲線 U⁻¹(c) は効用関数 U のレベルセットとして定義される。
無差別曲線は効用空間内でのプレーンに対応し、その勾配 ∇U は無差別曲線に直交する。
ゲーム理論では、プレイヤー i の戦略空間を多様体 S_i とし、全プレイヤーの戦略空間を S = ∏_i S_i とする。プレイヤーの利得関数 π_i: S → ℝ はゲームの結果として得られる。
プレイヤーの戦略の選択は戦略空間 S 上の点で表現され、ゲームの均衡は戦略空間上での最大化問題としてモデル化される。
完全ベイズ均衡では、情報の不完全性を考慮し、プレイヤーの信念と戦略を統合する。プレイヤー i のタイプ空間を Θ_i とし、信念空間を Δ(Θ_i) とする。信念 μ_i はプレイヤー i のタイプ θ_i に対する確率分布を示す。
情報理論の要素をゲーム理論に統合するために、以下のように対応させる:
1. エントロピーと不確実性:
ゲーム理論と情報理論を統合するために、以下の枠組みを考える:
1. 共通の多様体: 効用空間 X、戦略空間 S、信念空間 Δ(Θ)、情報空間 ℙ を統一的な多様体としてモデル化する。
2. ファイバーバンドル: 各理論の構造をファイバーバンドルとして表現し、効用、戦略、信念、情報を抽象的に結びつける。
3. リーマン計量: 各多様体上のリーマン計量を用いて、効用、戦略、信念、情報の変化を統一的に扱う。
digraph G { // グラフの設定 rankdir=LR; node [shape=box, color=lightgrey]; // ノードの定義 UtilitySpace [label="効用空間\n(X, U)", shape=ellipse]; StrategySpace [label="戦略空間\n(S, π)", shape=ellipse]; BeliefSpace [label="信念空間\n(Δ(Θ), μ)", shape=ellipsel]; InformationSpace [label="情報空間\n(ℙ, H)", shape=ellipse]; // ノード間の関係 UtilitySpace -> StrategySpace [label="効用関数\nU(x)"]; StrategySpace -> BeliefSpace [label="戦略の期待値\nE[π_i | θ_i]"]; BeliefSpace -> InformationSpace [label="エントロピー\nH(μ)"]; InformationSpace -> UtilitySpace [label="情報の多様体\nℙ"]; // フォーマット設定 edge [color=black, arrowhead=normal]; }
digraph G { rankdir=LR; node [shape=ellipse, style=filled, color=white, fontcolor=black, penwidth=2, fillcolor=white, color=black]; // Nodes UtilitySpace [label="Utility Space (X)"]; StrategySpace [label="Strategy Space (S)"]; BeliefSpace [label="Belief Space (Δ(Θ))"]; InformationSpace [label="Information Space (ℙ)"]; FiberBundle [label="Fiber Bundle"]; RiemannMetric [label="Riemannian Metric"]; KL_Divergence [label="Minimize D_{KL}(μ_i || ν_i)"]; ParetoOptimality [label="Pareto Optimality"]; Constraints [label="Constraints"]; Optimization [label="Optimization"]; // Edges UtilitySpace -> FiberBundle; StrategySpace -> FiberBundle; BeliefSpace -> FiberBundle; InformationSpace -> FiberBundle; FiberBundle -> RiemannMetric; RiemannMetric -> KL_Divergence [label="Measure Change"]; KL_Divergence -> Optimization; Constraints -> Optimization; Optimization -> ParetoOptimality [label="Achieve"]; // Subgraph for constraints subgraph cluster_constraints { label="Constraints"; node [style=filled, color=white, fontcolor=black, penwidth=2]; StrategyChoice [label="Strategy Choice"]; BeliefUpdate [label="Belief Update"]; StrategyChoice -> BeliefUpdate; BeliefUpdate -> Constraints; } }
厚生経済学の基本定理を多様体の言葉で定式化することにより、経済的効率性と市場均衡の概念を幾何学的に表現することができる。以下にその試みを示す。
厚生経済学の第1基本定理は、「完全競争市場において、すべての市場均衡はパレート効率的である」というものである。これを多様体の言葉で表現する。
消費者の選択空間を多様体 𝑀 とする。ここで、各点 𝑥 ∈ 𝑀 は異なる消費バンドルを表す。消費者の効用関数は、𝑈: 𝑀 → ℝ として定義され、多様体上で滑らかな関数とする。
生産者の技術集合を多様体 𝑁 とし、各点 𝑦 ∈ 𝑁 が異なる生産計画を示す。生産技術は、技術制約関数 𝑇: 𝑁 → ℝⁿ により記述される。
市場均衡は、消費者と生産者の選択が整合する点として、多様体 𝑀 × 𝑁 上の点 (𝑥*, 𝑦*) により表される。この点は、需要と供給が一致し、価格ベクトル 𝑝 により支持される。
パレート効率性は、選択空間 𝑀 と技術空間 𝑁 上の接ベクトル場により定義される。具体的には、任意の改善方向が存在しないことを意味し、接ベクトル場がゼロとなる点 (𝑥*, 𝑦*) がパレート最適である。
厚生経済学の第1基本定理を多様体の言葉で表現すると、以下のようになる:
定理: 多様体 𝑀 × 𝑁 上の市場均衡点 (𝑥*, 𝑦*) は、接ベクトル場がゼロとなる点であり、パレート効率的である。
この定式化により、厚生経済学の基本定理を幾何学的に理解することが可能になる。
市場均衡がパレート効率性を持つことは、選択空間と技術空間の接ベクトル場の観点から、改善の余地がないことを示している。
digraph WelfareEconomics { node [shape=ellipse]; // Nodes for main concepts M [label="選択空間 (M)"]; N [label="技術空間 (N)"]; Utility [label="効用関数 (U)"]; TechConstraint [label="技術制約 (T)"]; MarketEquilibrium [label="市場均衡"]; ParetoEfficiency [label="パレート効率性"]; Cohomology [label="コホモロジー条件"]; // Edges to show relationships M -> Utility [label="スカラー場"]; N -> TechConstraint [label="技術写像"]; M -> MarketEquilibrium; N -> MarketEquilibrium; MarketEquilibrium -> ParetoEfficiency [label="接ベクトル場"]; MarketEquilibrium -> Cohomology [label="整合性保証"]; ParetoEfficiency -> Cohomology [label="ホモトピー同値"]; } |<
1. こんな感じで使います。
$ python parser.py sample.py
import parser code = ''' a = 1 + 1 print(a) ''' graph = parser.create_graph(code) graph.render("sample")
import ast import sys import graphviz def create_graph(lines): graph = graphviz.Graph(format='png') root = ast.parse(lines) node_list = [root] _setup(graph, node_list) return graph def _setup(graph, node_list): # node node = node_list[-1] node_identity = str(len(node_list)) node_name = type(node).__name__ graph.node(node_identity, node_name) # children for child in ast.iter_child_nodes(node): node_list.append(child) child_identity = str(len(node_list)) graph.edge(node_identity, child_identity) _setup(graph, node_list) if __name__ == '__main__': file_name = sys.argv[1] with open(file_name) as file: lines = file.read() graph = create_graph(lines) graph.render(file_name)
発祥: http://ex23.2ch.net/test/read.cgi/morningcoffee/1188654905/
Scheme という Lisp 語族の言語を用いて ℃-ute の相関関係をプログラムし、様々な角度から関係性を分析する手法を紹介していきます(ソースコードは最後に張ります)。
まずは、メンバー間の関係を「リスト」というデータ型で表現します。例えば「栞菜->愛理」という関係は
(kanna . airi)
という形で表すことができます。これに、「大好き」という情報を付加し、ついでにその関係の性質を数値化したものを加えると
((kanna . airi) (desc "大好き") (score . 1))
のようになり、関係図における一つの矢印の情報をデータ化できたことになります(暫定的に、好意は 1、良好・中立は 0、険悪は -1 の3段階で表すことにします)。
メンバー間の全ての関係性をこのデータ単位で定義し、データベース化しておくことで、色んな条件に基づいた検索やスコア計算などが可能となります。
ここで相関関係図における矢印を「リンク」と呼ぶことにして、あるメンバーから他のメンバーへどのようにリンクし、またリンクされているかを調べることができます。
(sort-nodes (number-list (from-links)))
結果:
((kanna . 6) (saki . 5) (maimi . 4) (erika . 3) (mai . 3) (chisato . 3) (airi . 2))
栞菜ちゃんがメンバー全員にリンクを張っていることが分かり、℃-ute ラブっぷりが伺えます。なっきーにも同様の事が言えます。例の「女の子が好き」発言を数値的に裏付ける結果と言えるかもしれません。
ただ、データ不足でリンク件数がまだ少ないのと、リンクの性質(好意/反感など)までは分からない点を考慮する必要があるでしょう。
同様に、リンクの終点の件数を調べてみます。
(sort-nodes (number-list (to-links)))
((chisato . 5) (erika . 5) (kanna . 4) (maimi . 4) (airi . 4) (mai . 3) (saki . 1))
えりかちゃんと千聖ちゃんが高ポイントです。メンバーからの人気や注目度の高さを示すデータですが、千聖ちゃんの場合敵対的なリンクが2件含まれている点に注意してください。
なっきーの被リンク数が極端に少ないですが、単純にデータ不足のためだと思われます。はぶら(ryとか言わないようにお願いします。
リンクに付随するスコアを計算することで、愛情の度合いを測ることができるのではないか、という考えに基づく研究です。
まず、全ての関係性を対象として、スコアがマイナスの関係を抽出してみます。
(filter-nodes (lambda (n) (< (score-relation n) 0)))
結果:
(((kanna . chisato) (desc "愛理に手出すんじゃねぇよ") (score . -1)) ((saki . chisato) (desc "愛理に手出すんじゃねぇよ") (score . -1)))
件数だけを得ると
(length (filter-nodes (lambda (n) (< (score-relation n) 0))))
2
僅か2件です。
良好・中立的な関係は
(length (filter-nodes (lambda (n) (= (score-relation n) 0))))
8
愛に満ちた関係は
(length (filter-nodes (lambda (n) (> (score-relation n) 0))))
16
非常に多いです。舞美ちゃんの「℃-ute同士でラブラブなんですよ」発言(例のラジオ)を数値的に裏付ける結果と言えるんじゃないでしょうか。
次に、メンバーごとのスコアを算出してみます。Lisp 的には以下のようにフィルタリングと畳み込み (fold) で計算することができます。例えば
(foldr (lambda (n acc) (+ (get-score n) acc)) 0 (filter-nodes (cut to? <> 'kanna)))
3
上式を一般化して一挙にメンバー全員に適用してみると
(sort-nodes (map (lambda (x) (cons x (score-loved x))) (all-members)))
結果:
((airi . 4) (kanna . 3) (mai . 2) (erika . 2) (maimi . 2) (saki . 1) (chisato . 0))
愛理ちゃんが好意を寄せられやすい傾向が伺えます。
今度は逆方向のスコアを計算してみると
(sort-nodes (map (lambda (x) (cons x (score-loving x))) (all-members)))
((kanna . 3) (maimi . 3) (chisato . 2) (airi . 2) (saki . 2) (mai . 1) (erika . 1))
まいまいとえりかちゃんが特に堅い・一途だという傾向を読み取ることができます。
今度は組み合わせ(カップリング)の評価です。
2点間相互のリンク・スコアを加算したものを「相性」と考えられるものとします。最大値 (互いに好意を寄せている場合の数値) は現在のスコアリング方式では 2 です。例えば
(score-between 'kanna 'airi)
の値は
2
となります。1 であれば一方通行と考えます。
関係性が未定義の場合もあるので 0 のものを除外して算出すると
(sort-nodes (filter (lambda (n) (not (= (cdr n) 0))) (map (lambda (n) (cons n (apply score-between n))) (all-combinations))))
(((chisato mai) . 2) ((chisato airi) . 2) ((airi kanna) . 2) ((saki kanna) . 2) ((kanna maimi) . 2) ((erika maimi) . 2) ((saki airi) . 1) ((saki erika) . 1) ((kanna mai) . 1) ((maimi airi) . 1) ((saki chisato) . -1) ((kanna chisato) . -1))
となります。若干ピンとこない部分もあるかも知れませんが、計算上は矛盾無くデータの内容を表しています。
(map (lambda (p) (find-relation (cons (caar p) (cadar p)) identity)) (filter (lambda (n) (= (cdr n) 1)) (map (lambda (n) (cons n (apply score-between n))) (all-combinations))))
(((kanna . mai) (desc "喰ってやるよ") (score . 1)) ((saki . airi) (desc "好き") (score . 1)) ((maimi . airi) (desc "良き妹") (score . 1)) ((saki . erika) (desc "彼氏にしたい") (score . 1)))
のようになります。
以上の調査を経て気になった問題点を列挙してみます。
特に最初の点に関して、「百合的」なるものの質的評価がなかなか難しいと感じました。例えば「大好き」も「良き妹」も同じ 1 と評価してしまっているのが妥当かどうか、といったことです。
また、スレにて与えられた情報を評価・分析する方法としては有効だとしても、逆方向のフィードバックの手段がなかなか見つからないというのが三つ目の問題です(技術力不足とも言います)。(注:画像化の方法が分かりました。追記参照)
最後に、プログラムのソースを示します。実行には PLT Scheme が必要です。文字コードは UTF-8 で保存した上で、(load "c-ute.ss") としてください。文字化けする場合はターミナルが UTF-8 を表示できるよう設定する必要があります。がんばってください。
c-ute.ss:
(require (lib "etc.ss") (lib "list.ss") (lib "26.ss" "srfi") (lib "delete.ss" "srfi" "1")) ;;; Utilities (define true? (compose not not)) (define (ignore _) #f) (define fif (case-lambda ((predicate consequent) (fif predicate consequent ignore)) ((predicate consequent alternative) (lambda (x) (if (predicate x) (consequent x) (alternative x)))))) (define (concat! xs) (apply append! xs)) (define (mapconcat f lst sep) (let lp ((str (f (car lst))) (lst (cdr lst))) (if (null? lst) str (lp (string-append str sep (f (car lst))) (cdr lst))))) (define (slice-string str len) (let lp ((res '()) (str str)) (if (<= (string-length str) len) (reverse! (cons str res)) (lp (cons (substring str 0 len) res) (substring str len))))) (define (break-string str len) (mapconcat identity (slice-string str len) "\\n")) ;; NOTE: input and output ports have to be either file-stream or #f ;; (i.e., cannot be a string port) (define (run exe opt in out) (let-values (((p p-i p-o p-e) (subprocess out in #f exe opt))) (subprocess-wait p) (close-input-port p-e))) ;;; Database ;; http://ja.wikipedia.org/wiki/%E2%84%83-ute (define names '((erika . "えりか") (maimi . "舞美") (saki . "早貴") (airi . "愛理") (chisato . "千聖") (mai . "舞") (kanna . "栞菜"))) (define (symbol->name sym) ((fif true? cdr) (assq sym names))) (define nodes '()) (define edges '()) (define (relate from to desc score) (let ((n (cons from to))) (or (find-relation n (lambda (r) (let ((d (assq 'desc r)) (s (assq 'score r))) (set-cdr! d (cons desc (cdr d))) (set-cdr! s (+ score (cdr s)))))) (begin (set! nodes (cons n nodes)) (set! edges (cons (cons n `((desc ,desc) (score . ,score))) edges)))))) (define (find-relation n k) ((fif true? k) (assoc n edges))) (define (related? x y) (find-relation (cons x y) (lambda (_) #t))) (define (from? n x) (eq? (car n) x)) (define (to? n x) (eq? (cdr n) x)) (define flip-relation (case-lambda ((n) (and (related? (cdr n) (car n)) (cons (cdr n) (car n)))) ((n k) ((fif true? k) (flip-relation n))))) (define (get-score n) (cdr (assq 'score n))) (define (get-description n) (cdr (assq 'desc n))) (define (describe-relation n) (find-relation n get-description)) (define (score-relation n) (or (find-relation n get-score) 0)) (define (print-node . ns) (for-each (cute find-relation <> (lambda (r) (display (format "| ~a => ~a (~a)~%" (caar r) (cdar r) (mapconcat (lambda (s) (string-append "\"" s "\"")) (cdr (assq 'desc r)) ", "))))) ns)) (define (iter-nodes k) (let lp ((nodes nodes)) (unless (null? nodes) (k (car nodes)) (lp (cdr nodes))))) (define (filter-nodes p) (let ((ns '())) (iter-nodes (fif p (cut find-relation <> (lambda (n) (set! ns (cons n ns)))))) ns)) (define (from-links) (map car nodes)) (define (to-links) (map cdr nodes)) (define (all-members) (delete-duplicates! (from-links))) (define (all-pairs) nodes) (define (ordered-pairs) (concat! (map (lambda (x) (map car (sort (filter-nodes (cute to? <> (car x))) (lambda (x y) (> (get-score x) (get-score y)))))) (sort-nodes (map (lambda (x) (cons x (score-loved x))) (all-members)))))) (define (all-combinations) (let lp ((cs '()) (ns nodes)) (if (null? ns) cs (let ((n (car ns))) (lp (if (member (list (cdr n) (car n)) cs) cs (cons (list (car n) (cdr n)) cs)) (cdr ns)))))) ;; number-list :: [a] -> [(a . Int)] (define (number-list ls) (let lp ((ns '()) (ls ls)) (if (null? ls) ns (let ((x (car ls))) (lp ((fif not (lambda (_) (cons (cons x 1) ns)) (lambda (n) (set-cdr! n (add1 (cdr n))) ns)) (assq x ns)) (cdr ls)))))) ;; sort-nodes :: [(a . Int)] -> [(a . Int)] (define (sort-nodes ns) (sort ns (lambda (x y) (> (cdr x) (cdr y))))) (define (diff-nodes ms ns) (let lp ((ds '()) (ns ns)) (if (null? ns) (sort-nodes ds) (lp (let* ((n (car ns)) (m (assq (car n) ms))) (cons (cons (car n) (- (cdr m) (cdr n))) ds)) (cdr ns))))) (define (get-total-score x p) (foldr (lambda (n acc) (+ (get-score n) acc)) 0 (filter-nodes (cut p <> x)))) (define (score-loved x) (get-total-score x to?)) (define (score-loving x) (get-total-score x from?)) (define (score-between x y) (+ (score-relation (cons x y)) (score-relation (cons y x)))) (define (-> x) (display (format "~%Links from [~a]~%" x)) (iter-nodes (fif (cut from? <> x) print-node))) (define (<- x) (display (format "~%Links towards [~a]~%" x)) (iter-nodes (fif (cut to? <> x) print-node))) (define (<-> x) (display (format "~%Reciprocal links for [~a]~%" x)) (iter-nodes (fif (cut to? <> x) (lambda (n) (flip-relation n (lambda (m) (print-node m n))))))) (define (<=> x) (display (format "~%Reciprocal matches for [~a]~%" x)) (iter-nodes (fif (cut to? <> x) (lambda (n) (flip-relation n (lambda (m) (if (ormap (lambda (x) (ormap (lambda (y) (equal? x y)) (describe-relation m))) (describe-relation n)) (print-node m n)))))))) (define (<?> x) (let ((to (assq x (number-list (from-links)))) (from (assq x (number-list (to-links))))) (display (string-append (format "~%Link statistics for [~a]~%" x) (format "| ~a => ~a (love ~a)~%" x (cdr to) (score-loving x)) (format "| ~a => ~a (love ~a)~%" (cdr from) x (score-loved x)))))) (define (info x) (for-each (cut <> x) (list <- <-> <=> -> <?>))) ;;; GraphViz (http://www.graphviz.org/) support (define graphviz "C:/Program Files/ATT/Graphviz/bin/dot.exe") (define (nodes->dot ns) (string-append "digraph cute {\n" ;;"\tordering=out;\n" ;;"\trankdir=LR;\n" "\toverlap=true;\n" "\tnode[fontname=\"msgothic.ttc\"];\n" "\tedge[fontname=\"msgothic.ttc\",fontsize=9];\n" (let lp ((str "") (ns ns)) (if (null? ns) str (let* ((n (car ns)) (s (score-relation n))) (lp (string-append str (format "\t\"~a\" -> \"~a\"" (symbol->name (car n)) (symbol->name (cdr n))) (format "[label=\"~a\",color=\"~a\"," (break-string (car (describe-relation n)) 7) (cond ((> s 0) "red") ((= s 0) "green") (else "blue"))) (format "style=\"bold~a\"];\n" (if (and (not (= s 0)) (< s 1) (> s -1)) ",dashed" ""))) (cdr ns))))) "}")) (define (write-dotfile dot file) (and (file-exists? file) (delete-file file)) (with-output-to-file file (lambda () (display dot))) file) (define (dot->png dot png) (call-with-input-file (write-dotfile dot "c-ute.dot") (lambda (in) (and (file-exists? png) (delete-file png)) (call-with-output-file png (lambda (out) (run graphviz "-Tpng" in out))))) 'done) ;;; Setup database ;; Based on: ;; http://ex23.2ch.net/test/read.cgi/morningcoffee/1188654905/116-142 (begin (relate 'maimi 'erika "大好き" 1) (relate 'maimi 'kanna "良き妹" 1) (relate 'maimi 'airi "良き妹" 1) (relate 'maimi 'mai "姉妹" 0) (relate 'erika 'maimi "一番可愛いよ" 1) (relate 'erika 'kanna "仲間" 0) (relate 'erika 'chisato "おソロパジャマ" 0) (relate 'kanna 'erika "仲間" 0) (relate 'kanna 'maimi "好き" 1) (relate 'kanna 'saki "喰ってやるよ" 1) (relate 'kanna 'mai "喰ってやるよ" 1) (relate 'kanna 'airi "大好き" 1) (relate 'kanna 'chisato "愛理に手出すんじゃねぇよ" -1) (relate 'saki 'maimi "荷物整理" 0) (relate 'saki 'erika "彼氏にしたい" 1) (relate 'saki 'kanna "興味がある" 0.5) (relate 'saki 'chisato "愛理に手出すんじゃねぇよ" -1) (relate 'saki 'airi "好き" 1) (relate 'airi 'kanna "受け入れる" 1) (relate 'airi 'chisato "最近親密" 1) (relate 'mai 'erika "保護者" 0) (relate 'mai 'maimi "姉妹" 0) (relate 'mai 'chisato "恋人" 1) (relate 'chisato 'erika "おソロパジャマ" 0) (relate 'chisato 'mai "恋人" 1) (relate 'chisato 'airi "最近親密" 1)) ;; query relations / draw graphs (if (file-exists? graphviz) (dot->png (nodes->dot (ordered-pairs)) "c-ute.png") (for-each info (all-members)))
Graphviz というソフトによって関係図を可視化できる、ということを教えていただきました(既に上プログラムを実行すると自動的に関係図画像を作成するようにしてあります)。ここでは技術的な観点から幾つか注意点を挙げておきます。
まず、Scheme プログラムから Graphviz を動かす方法について。コマンドラインからの起動のように、プログラムへのオプション文字列で入出力ファイルを指定する方法ではどうも上手く行きませんでした。調査の結果、入出力ファイルのポートを Scheme 側で用意しておく必要があるようです。処理系によって異なりますが、PLT Scheme の場合 subprocess という関数を次のように呼び出します。
(subprocess output-port input-port #f "/path/to/dot.exe" "-Tpng")
ここで output-port は png 等画像ファイルへの出力ポート。input-port は dot ファイル(グラフの定義ファイル)の入力ポートです。エラーポートは必要無いでしょう (#f)。
dot という名前の実行ファイルが、関係図のような有向グラフを描画するプログラムです。最後にオプション文字列として出力形式を指定します(png, jpeg, gif, etc.)。
次に dot ファイルを Scheme で書く方法ですが、以下の基本的な有向グラフの書式
digraph g { A -> B; B -> C; C -> A; }
を理解すれば、後は実直に Scheme のデータを当てはめて format 関数等で変換するだけです。
(string-append "digraph g {" (format "~a -> ~a;" (car node) (cdr node)) "}")
問題は、ノードを配置する順番によって出来上がる画像が変わってくる、ということです。
より見た目に分かりやすくするための工夫としては、相互にリンクするノード同士が dot ファイル上でも近接して出力されるようにすると良いでしょう。関連の強いものが画像の上でも近くに表示されるようになります。
また上述(特に例3)のスコアの概念を応用し、スコアの低いものが後に出力されるようにすることで、重力感覚に一致するような関係図を得ることができるでしょう。