packages feed

hgg-analyze-bridge-0.1.0.0: examples/ThreeRoutesDemo.hs

-- | Phase 2 A6: 3 ルート並列出力 demo。
--
-- 同じ 'ModelGraph' を 3 種類の出力ルート (Mermaid HTML / Graphviz DOT /
-- hgg SVG) で同時生成し、 ユーザが用途別に比較できるようにする。
--
-- @
-- cabal run three-routes-demo
-- @
-- → @design/three-routes/@ に下記 3 形式 × 3 model (= 計 9 ファイル) を出力。
--
-- Demo モデル: 単純 LM / 階層 LM (= 2 plate) / nested plate (= 多重所属) の 3 種。
--
-- 注: 本 demo は analyze 自体に置けない (= analyze は hgg に依存しない、
-- 計画 §4.1 依存方向規律)。 bridge package 内 demo として配置。
{-# LANGUAGE OverloadedStrings #-}
module Main where

import qualified Data.Map.Strict     as Map
import qualified Data.Set            as Set
import qualified Data.Text           as T
import qualified Data.Text.IO        as TIO
import           System.Directory    (createDirectoryIfMissing)

import           Hanalyze.Model.HBM        (ModelGraph (..), Node (..),
                                            NodeKind (..))
import qualified Hanalyze.Viz.ModelGraph   as Mermaid
import qualified Hanalyze.Viz.ModelGraphDot as Dot

import           Graphics.Hgg.Bridge.Analyze
                                           (renderModelGraphSVG)

-- ===========================================================================
-- Demo モデル (= A2 test fixture と同じ、 再利用)
-- ===========================================================================

simpleLM :: ModelGraph
simpleLM = ModelGraph
  { mgNodes =
      [ Node "alpha" LatentN          "Normal"   Set.empty []
      , Node "beta"  LatentN          "Normal"   Set.empty []
      , Node "y"     (ObservedN 100)  "Normal"   Set.empty []
      ]
  , mgEdges  = [("alpha", "y"), ("beta", "y")]
  , mgPlates = Map.empty
  }

hierLM :: ModelGraph
hierLM = ModelGraph
  { mgNodes =
      [ Node "mu_g"  LatentN           "Normal"     Set.empty []
      , Node "sig_g" LatentN           "HalfCauchy" Set.empty []
      , Node "mu"    LatentN           "Normal"     Set.empty ["group"]
      , Node "y"     (ObservedN 200)   "Normal"     Set.empty ["record"]
      ]
  , mgEdges  = [("mu_g", "mu"), ("sig_g", "mu"), ("mu", "y")]
  , mgPlates = Map.fromList [("group", 5), ("record", 200)]
  }

nestedPlate :: ModelGraph
nestedPlate = ModelGraph
  { mgNodes =
      [ Node "mu"   LatentN          "Normal" Set.empty []
      , Node "mu_c" LatentN          "Normal" Set.empty ["condition"]
      , Node "y"    (ObservedN 200)  "Normal" Set.empty ["record", "condition"]
      ]
  , mgEdges  = [("mu", "mu_c"), ("mu_c", "y")]
  , mgPlates = Map.fromList [("record", 200), ("condition", 3)]
  }

-- ===========================================================================
-- Runner
-- ===========================================================================

main :: IO ()
main = do
  let outDir = "design/three-routes"
  createDirectoryIfMissing True outDir
  mapM_ (renderAllRoutes outDir)
    [ ("simple-lm",   "Simple LM (= 3 node、 plate 無し)",   simpleLM)
    , ("hier-lm",     "Hierarchical LM (= 2 plate、 disjoint)", hierLM)
    , ("nested-plate","Nested plate (= y が 2 plate に属す)",  nestedPlate)
    ]
  putStrLn ""
  putStrLn $ "Wrote 9 files to " <> outDir <> "/"
  putStrLn "  *-mermaid.html  (= Mermaid CDN 経由ブラウザ描画)"
  putStrLn "  *-graphviz.dot  (= dot CLI で SVG/PNG 化用)"
  putStrLn "  *-hgg.svg   (= hgg 直 SVG、 依存ゼロ)"

renderAllRoutes :: FilePath -> (String, T.Text, ModelGraph) -> IO ()
renderAllRoutes outDir (slug, titleTxt, mg) = do
  let base = outDir <> "/" <> slug

  -- Route 1: Mermaid HTML
  Mermaid.renderModelGraph (base <> "-mermaid.html") titleTxt mg

  -- Route 2: Graphviz DOT (= .dot 中間 text)
  TIO.writeFile (base <> "-graphviz.dot") (Dot.renderModelGraphDot mg)

  -- Route 3: hgg SVG (= 依存ゼロの直描画)
  renderModelGraphSVG (base <> "-hgg.svg") titleTxt mg

  putStrLn $ "  " <> slug <> ": 3 形式 出力 (mermaid.html / graphviz.dot / hgg.svg)"