{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "permutation_based-0",
   "metadata": {},
   "source": [
    "# Permutation-based search (BOSS / GRaSP)\n",
    "\n",
    "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Abel-ai-lab/andrey/blob/main/examples/permutation_based.ipynb)\n",
    "\n",
    "BOSS and GRaSP search over orderings of the variables. For an ordering, a BIC score chooses each\n",
    "variable's parents from the variables before it; the search keeps the ordering with the best score.\n",
    "Both return a CPDAG, like GES, and suit linear-Gaussian data."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7fb27b941602401d91542211134fc71a",
   "metadata": {},
   "source": [
    "## Start\n",
    "\n",
    "Choose a CPU runtime and run this cell first. In Colab it installs `andrey-core==0.9.0` from PyPI;\n",
    "local kernels use the installed environment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "acae54e37e7d407bbb7b55eff062a284",
   "metadata": {
    "tags": [
     "colab-setup"
    ]
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import sys\n",
    "\n",
    "IN_COLAB = \"google.colab\" in sys.modules\n",
    "\n",
    "if IN_COLAB:\n",
    "    os.environ[\"ANDREY_DEVICE\"] = \"cpu\"\n",
    "    !pip install --quiet \"andrey-core[viz]==0.9.0\" pandas"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "permutation_based-1",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from IPython.display import display\n",
    "\n",
    "import andrey\n",
    "import andrey.metrics as metrics\n",
    "import andrey.viz\n",
    "from andrey.data import benchmarks"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "permutation_based-2",
   "metadata": {},
   "source": [
    "## Data\n",
    "\n",
    "`linear_gauss_er` draws an Erdos-Renyi graph with linear mechanisms and Gaussian noise: here 10\n",
    "variables and 2,000 samples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "permutation_based-3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2000 observations, 10 variables, seed 7\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 464 332\" width=\"100%\" font-family=\"Inter, system-ui, sans-serif\"><rect width=\"464\" height=\"332\" fill=\"#fafbfc\"/><line x1=\"312.82\" y1=\"44.82\" x2=\"242.84\" y2=\"91.09\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"321.16,39.30 310.06,40.65 315.57,48.99\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"144.93\" y1=\"163.00\" x2=\"409.13\" y2=\"134.59\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.07,133.52 408.60,129.62 409.67,139.56\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"113.24\" y1=\"177.70\" x2=\"42.60\" y2=\"227.83\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"121.40,171.91 110.35,173.62 116.14,181.78\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"112.82\" y1=\"151.70\" x2=\"42.84\" y2=\"105.43\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"121.16,157.22 115.57,147.53 110.06,155.87\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"409.32\" y1=\"128.29\" x2=\"244.82\" y2=\"100.43\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.18,129.96 410.16,123.36 408.49,133.22\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"410.18\" y1=\"124.86\" x2=\"144.33\" y2=\"36.24\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.67,128.02 411.76,120.11 408.60,129.60\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"410.11\" y1=\"139.19\" x2=\"344.37\" y2=\"160.40\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.63,136.12 408.58,134.43 411.65,143.95\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"139.66\" y1=\"224.85\" x2=\"218.45\" y2=\"116.84\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"224.34,108.76 214.41,113.89 222.49,119.79\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"142.92\" y1=\"242.40\" x2=\"212.67\" y2=\"287.40\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"221.08,292.82 215.38,283.20 209.96,291.60\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"109.00\" y1=\"235.35\" x2=\"45.00\" y2=\"235.35\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"119.00,235.35 109.00,230.35 109.00,240.35\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"212.82\" y1=\"85.57\" x2=\"142.84\" y2=\"39.30\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"221.16,91.09 215.57,81.40 210.06,89.74\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"242.84\" y1=\"105.43\" x2=\"312.82\" y2=\"151.70\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"321.16,157.22 315.57,147.53 310.06,155.87\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"209.00\" y1=\"98.26\" x2=\"45.00\" y2=\"98.26\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"219.00,98.26 209.00,93.26 209.00,103.26\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"112.82\" y1=\"44.82\" x2=\"42.84\" y2=\"91.09\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"121.16,39.30 110.06,40.65 115.57,48.99\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"210.11\" y1=\"292.81\" x2=\"44.37\" y2=\"239.35\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"219.63,295.88 211.65,288.05 208.58,297.57\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><circle cx=\"332.00\" cy=\"32.13\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"332.00\" y=\"32.13\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">0</text><circle cx=\"132.00\" cy=\"164.39\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"164.39\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">1</text><circle cx=\"432.00\" cy=\"132.13\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"432.00\" y=\"132.13\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">2</text><circle cx=\"132.00\" cy=\"235.35\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"235.35\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">3</text><circle cx=\"232.00\" cy=\"98.26\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"98.26\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">4</text><circle cx=\"132.00\" cy=\"32.13\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"32.13\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">5</text><circle cx=\"232.00\" cy=\"299.87\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"299.87\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">6</text><circle cx=\"32.00\" cy=\"235.35\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"235.35\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">7</text><circle cx=\"332.00\" cy=\"164.39\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"332.00\" y=\"164.39\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">8</text><circle cx=\"32.00\" cy=\"98.26\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"98.26\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">9</text></svg>"
      ],
      "text/plain": [
       "'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 464 332\" width=\"100%\" font-family=\"Inter, system-ui, sans-serif\"><rect width=\"464\" height=\"332\" fill=\"#fafbfc\"/><line x1=\"312.82\" y1=\"44.82\" x2=\"242.84\" y2=\"91.09\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"321.16,39.30 310.06,40.65 315.57,48.99\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"144.93\" y1=\"163.00\" x2=\"409.13\" y2=\"134.59\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.07,133.52 408.60,129.62 409.67,139.56\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"113.24\" y1=\"177.70\" x2=\"42.60\" y2=\"227.83\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"121.40,171.91 110.35,173.62 116.14,181.78\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"112.82\" y1=\"151.70\" x2=\"42.84\" y2=\"105.43\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"121.16,157.22 115.57,147.53 110.06,155.87\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"409.32\" y1=\"128.29\" x2=\"244.82\" y2=\"100.43\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.18,129.96 410.16,123.36 408.49,133.22\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"410.18\" y1=\"124.86\" x2=\"144.33\" y2=\"36.24\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.67,128.02 411.76,120.11 408.60,129.60\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"410.11\" y1=\"139.19\" x2=\"344.37\" y2=\"160.40\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.63,136.12 408.58,134.43 411.65,143.95\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"139.66\" y1=\"224.85\" x2=\"218.45\" y2=\"116.84\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"224.34,108.76 214.41,113.89 222.49,119.79\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"142.92\" y1=\"242.40\" x2=\"212.67\" y2=\"287.40\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"221.08,292.82 215.38,283.20 209.96,291.60\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"109.00\" y1=\"235.35\" x2=\"45.00\" y2=\"235.35\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"119.00,235.35 109.00,230.35 109.00,240.35\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"212.82\" y1=\"85.57\" x2=\"142.84\" y2=\"39.30\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"221.16,91.09 215.57,81.40 210.06,89.74\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"242.84\" y1=\"105.43\" x2=\"312.82\" y2=\"151.70\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"321.16,157.22 315.57,147.53 310.06,155.87\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"209.00\" y1=\"98.26\" x2=\"45.00\" y2=\"98.26\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"219.00,98.26 209.00,93.26 209.00,103.26\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"112.82\" y1=\"44.82\" x2=\"42.84\" y2=\"91.09\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"121.16,39.30 110.06,40.65 115.57,48.99\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"210.11\" y1=\"292.81\" x2=\"44.37\" y2=\"239.35\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"219.63,295.88 211.65,288.05 208.58,297.57\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><circle cx=\"332.00\" cy=\"32.13\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"332.00\" y=\"32.13\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">0</text><circle cx=\"132.00\" cy=\"164.39\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"164.39\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">1</text><circle cx=\"432.00\" cy=\"132.13\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"432.00\" y=\"132.13\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">2</text><circle cx=\"132.00\" cy=\"235.35\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"235.35\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">3</text><circle cx=\"232.00\" cy=\"98.26\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"98.26\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">4</text><circle cx=\"132.00\" cy=\"32.13\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"32.13\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">5</text><circle cx=\"232.00\" cy=\"299.87\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"299.87\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">6</text><circle cx=\"32.00\" cy=\"235.35\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"235.35\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">7</text><circle cx=\"332.00\" cy=\"164.39\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"332.00\" y=\"164.39\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">8</text><circle cx=\"32.00\" cy=\"98.26\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"98.26\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">9</text></svg>'"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "seed = 7\n",
    "dataset = benchmarks.scm(\"linear_gauss_er\", d=10).sample(n=2000, seed=seed, scale=\"standardize\")\n",
    "X, truth = dataset.data, dataset.observed_graph\n",
    "print(f\"{X.shape[0]} observations, {X.shape[1]} variables, seed {seed}\")\n",
    "display(andrey.viz.draw(truth))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "permutation_based-4",
   "metadata": {},
   "source": [
    "## Fit BOSS and GRaSP\n",
    "\n",
    "BOSS starts from an ordering computed from the data and visits the variables in a random order;\n",
    "GRaSP starts from a random ordering. `seed` fixes the random choices, so a run repeats exactly;\n",
    "without `seed`, the `ANDREY_SEED` environment variable sets it (default 0). `metadata[\"score\"]` is\n",
    "the BIC objective of the final ordering, which the search minimizes. A larger `lambda_value` weighs\n",
    "the BIC penalty more and gives a sparser graph."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "permutation_based-5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "BOSS: cpdag, score -22398.8\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 464 333\" width=\"100%\" font-family=\"Inter, system-ui, sans-serif\"><rect width=\"464\" height=\"333\" fill=\"#fafbfc\"/><line x1=\"45.00\" y1=\"225.37\" x2=\"119.00\" y2=\"225.37\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"340.97\" y1=\"107.36\" x2=\"416.13\" y2=\"186.15\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"423.03,193.38 419.74,182.70 412.51,189.60\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"310.16\" y1=\"90.73\" x2=\"144.34\" y2=\"35.90\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"319.66,93.87 311.73,85.98 308.59,95.48\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"309.00\" y1=\"97.95\" x2=\"245.00\" y2=\"97.95\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"319.00,97.95 309.00,92.95 309.00,102.95\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"409.06\" y1=\"204.52\" x2=\"144.96\" y2=\"224.40\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.04,203.77 408.69,199.53 409.44,209.50\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"409.32\" y1=\"198.95\" x2=\"244.82\" y2=\"171.09\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.18,200.62 410.16,194.02 408.49,203.88\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"415.60\" y1=\"218.92\" x2=\"341.27\" y2=\"292.06\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"422.73,211.91 412.10,215.36 419.11,222.49\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"41.34\" y1=\"137.64\" x2=\"122.66\" y2=\"216.33\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"44.74\" y1=\"131.17\" x2=\"219.26\" y2=\"166.35\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"41.34\" y1=\"119.56\" x2=\"115.47\" y2=\"47.82\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"122.66,40.86 112.00,44.22 118.95,51.41\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"44.85\" y1=\"126.63\" x2=\"219.15\" y2=\"99.92\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"143.32\" y1=\"218.98\" x2=\"220.68\" y2=\"175.31\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"144.16\" y1=\"229.98\" x2=\"319.84\" y2=\"296.57\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"140.03\" y1=\"215.14\" x2=\"223.97\" y2=\"108.18\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"45.00\" y1=\"31.82\" x2=\"109.00\" y2=\"31.82\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"119.00,31.82 109.00,26.82 109.00,36.82\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><circle cx=\"32.00\" cy=\"225.37\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"225.37\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">0</text><circle cx=\"332.00\" cy=\"97.95\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"332.00\" y=\"97.95\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">1</text><circle cx=\"432.00\" cy=\"202.79\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"432.00\" y=\"202.79\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">2</text><circle cx=\"32.00\" cy=\"128.60\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"128.60\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">3</text><circle cx=\"132.00\" cy=\"225.37\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"225.37\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">4</text><circle cx=\"232.00\" cy=\"168.92\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"168.92\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">5</text><circle cx=\"32.00\" cy=\"31.82\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"31.82\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">6</text><circle cx=\"132.00\" cy=\"31.82\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"31.82\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">7</text><circle cx=\"332.00\" cy=\"301.18\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"332.00\" y=\"301.18\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">8</text><circle cx=\"232.00\" cy=\"97.95\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"97.95\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">9</text></svg>"
      ],
      "text/plain": [
       "'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 464 333\" width=\"100%\" font-family=\"Inter, system-ui, sans-serif\"><rect width=\"464\" height=\"333\" fill=\"#fafbfc\"/><line x1=\"45.00\" y1=\"225.37\" x2=\"119.00\" y2=\"225.37\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"340.97\" y1=\"107.36\" x2=\"416.13\" y2=\"186.15\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"423.03,193.38 419.74,182.70 412.51,189.60\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"310.16\" y1=\"90.73\" x2=\"144.34\" y2=\"35.90\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"319.66,93.87 311.73,85.98 308.59,95.48\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"309.00\" y1=\"97.95\" x2=\"245.00\" y2=\"97.95\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"319.00,97.95 309.00,92.95 309.00,102.95\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"409.06\" y1=\"204.52\" x2=\"144.96\" y2=\"224.40\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.04,203.77 408.69,199.53 409.44,209.50\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"409.32\" y1=\"198.95\" x2=\"244.82\" y2=\"171.09\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"419.18,200.62 410.16,194.02 408.49,203.88\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"415.60\" y1=\"218.92\" x2=\"341.27\" y2=\"292.06\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"422.73,211.91 412.10,215.36 419.11,222.49\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"41.34\" y1=\"137.64\" x2=\"122.66\" y2=\"216.33\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"44.74\" y1=\"131.17\" x2=\"219.26\" y2=\"166.35\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"41.34\" y1=\"119.56\" x2=\"115.47\" y2=\"47.82\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"122.66,40.86 112.00,44.22 118.95,51.41\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"44.85\" y1=\"126.63\" x2=\"219.15\" y2=\"99.92\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"143.32\" y1=\"218.98\" x2=\"220.68\" y2=\"175.31\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"144.16\" y1=\"229.98\" x2=\"319.84\" y2=\"296.57\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"140.03\" y1=\"215.14\" x2=\"223.97\" y2=\"108.18\" stroke=\"#e0982b\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><line x1=\"45.00\" y1=\"31.82\" x2=\"109.00\" y2=\"31.82\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"119.00,31.82 109.00,26.82 109.00,36.82\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><circle cx=\"32.00\" cy=\"225.37\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"225.37\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">0</text><circle cx=\"332.00\" cy=\"97.95\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"332.00\" y=\"97.95\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">1</text><circle cx=\"432.00\" cy=\"202.79\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"432.00\" y=\"202.79\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">2</text><circle cx=\"32.00\" cy=\"128.60\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"128.60\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">3</text><circle cx=\"132.00\" cy=\"225.37\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"225.37\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">4</text><circle cx=\"232.00\" cy=\"168.92\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"168.92\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">5</text><circle cx=\"32.00\" cy=\"31.82\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"31.82\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">6</text><circle cx=\"132.00\" cy=\"31.82\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"31.82\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">7</text><circle cx=\"332.00\" cy=\"301.18\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"332.00\" y=\"301.18\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">8</text><circle cx=\"232.00\" cy=\"97.95\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"97.95\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">9</text></svg>'"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "GRaSP: cpdag, score -22406.2\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 364 279\" width=\"100%\" font-family=\"Inter, system-ui, sans-serif\"><rect width=\"364\" height=\"279\" fill=\"#fafbfc\"/><line x1=\"209.35\" y1=\"242.74\" x2=\"144.80\" y2=\"231.29\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"219.20,244.49 210.23,237.82 208.48,247.67\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"240.90\" y1=\"43.33\" x2=\"316.25\" y2=\"123.55\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"323.10,130.83 319.90,120.12 312.61,126.97\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"209.00\" y1=\"33.85\" x2=\"145.00\" y2=\"33.85\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"219.00,33.85 209.00,28.85 209.00,38.85\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"214.31\" y1=\"48.55\" x2=\"42.00\" y2=\"191.68\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"222.00,42.16 211.11,44.70 217.50,52.39\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><path d=\"M 313.70 154.24 Q 242.54 208.43 144.78 226.64\" fill=\"none\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"321.66,148.18 310.67,150.27 316.73,158.22\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"310.32\" y1=\"132.62\" x2=\"244.25\" y2=\"109.17\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"319.75,135.96 312.00,127.90 308.65,137.33\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"310.32\" y1=\"148.00\" x2=\"244.25\" y2=\"171.45\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"319.75,144.66 308.65,143.29 312.00,152.71\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"40.09\" y1=\"113.38\" x2=\"117.69\" y2=\"211.01\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"123.91,218.84 121.60,207.90 113.77,214.12\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"45.00\" y1=\"103.31\" x2=\"209.00\" y2=\"104.63\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"219.00,104.72 209.04,99.63 208.96,109.63\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"42.68\" y1=\"95.80\" x2=\"113.10\" y2=\"46.96\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"121.32,41.26 110.25,42.85 115.95,51.07\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"140.15\" y1=\"218.89\" x2=\"217.58\" y2=\"122.73\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"223.85,114.95 213.68,119.60 221.47,125.87\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"143.48\" y1=\"222.91\" x2=\"211.70\" y2=\"186.60\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"220.52,181.90 209.35,182.19 214.05,191.01\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"109.91\" y1=\"222.61\" x2=\"44.48\" y2=\"203.61\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"119.52,225.39 111.31,217.80 108.52,227.41\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"45.00\" y1=\"32.45\" x2=\"109.00\" y2=\"33.48\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"119.00,33.64 109.08,28.48 108.92,38.48\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><circle cx=\"232.00\" cy=\"246.76\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"246.76\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">0</text><circle cx=\"232.00\" cy=\"33.85\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"33.85\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">1</text><circle cx=\"332.00\" cy=\"140.31\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"332.00\" y=\"140.31\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">2</text><circle cx=\"32.00\" cy=\"103.21\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"103.21\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">3</text><circle cx=\"132.00\" cy=\"229.02\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"229.02\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">4</text><circle cx=\"232.00\" cy=\"104.82\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"104.82\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">5</text><circle cx=\"32.00\" cy=\"32.24\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"32.24\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">6</text><circle cx=\"132.00\" cy=\"33.85\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"33.85\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">7</text><circle cx=\"232.00\" cy=\"175.79\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"175.79\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">8</text><circle cx=\"32.00\" cy=\"199.99\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"199.99\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">9</text></svg>"
      ],
      "text/plain": [
       "'<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 364 279\" width=\"100%\" font-family=\"Inter, system-ui, sans-serif\"><rect width=\"364\" height=\"279\" fill=\"#fafbfc\"/><line x1=\"209.35\" y1=\"242.74\" x2=\"144.80\" y2=\"231.29\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"219.20,244.49 210.23,237.82 208.48,247.67\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"240.90\" y1=\"43.33\" x2=\"316.25\" y2=\"123.55\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"323.10,130.83 319.90,120.12 312.61,126.97\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"209.00\" y1=\"33.85\" x2=\"145.00\" y2=\"33.85\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"219.00,33.85 209.00,28.85 209.00,38.85\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"214.31\" y1=\"48.55\" x2=\"42.00\" y2=\"191.68\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"222.00,42.16 211.11,44.70 217.50,52.39\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><path d=\"M 313.70 154.24 Q 242.54 208.43 144.78 226.64\" fill=\"none\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"321.66,148.18 310.67,150.27 316.73,158.22\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"310.32\" y1=\"132.62\" x2=\"244.25\" y2=\"109.17\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"319.75,135.96 312.00,127.90 308.65,137.33\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"310.32\" y1=\"148.00\" x2=\"244.25\" y2=\"171.45\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"319.75,144.66 308.65,143.29 312.00,152.71\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"40.09\" y1=\"113.38\" x2=\"117.69\" y2=\"211.01\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"123.91,218.84 121.60,207.90 113.77,214.12\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"45.00\" y1=\"103.31\" x2=\"209.00\" y2=\"104.63\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"219.00,104.72 209.04,99.63 208.96,109.63\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"42.68\" y1=\"95.80\" x2=\"113.10\" y2=\"46.96\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"121.32,41.26 110.25,42.85 115.95,51.07\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"140.15\" y1=\"218.89\" x2=\"217.58\" y2=\"122.73\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"223.85,114.95 213.68,119.60 221.47,125.87\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"143.48\" y1=\"222.91\" x2=\"211.70\" y2=\"186.60\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"220.52,181.90 209.35,182.19 214.05,191.01\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"109.91\" y1=\"222.61\" x2=\"44.48\" y2=\"203.61\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"119.52,225.39 111.31,217.80 108.52,227.41\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><line x1=\"45.00\" y1=\"32.45\" x2=\"109.00\" y2=\"33.48\" stroke=\"#3a4658\" stroke-width=\"2.0\" stroke-linecap=\"round\"/><polygon points=\"119.00,33.64 109.08,28.48 108.92,38.48\" fill=\"#3a4658\" stroke-linejoin=\"round\"/><circle cx=\"232.00\" cy=\"246.76\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"246.76\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">0</text><circle cx=\"232.00\" cy=\"33.85\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"33.85\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">1</text><circle cx=\"332.00\" cy=\"140.31\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"332.00\" y=\"140.31\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">2</text><circle cx=\"32.00\" cy=\"103.21\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"103.21\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">3</text><circle cx=\"132.00\" cy=\"229.02\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"229.02\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">4</text><circle cx=\"232.00\" cy=\"104.82\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"104.82\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">5</text><circle cx=\"32.00\" cy=\"32.24\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"32.24\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">6</text><circle cx=\"132.00\" cy=\"33.85\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"132.00\" y=\"33.85\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">7</text><circle cx=\"232.00\" cy=\"175.79\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"232.00\" y=\"175.79\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">8</text><circle cx=\"32.00\" cy=\"199.99\" r=\"13.00\" fill=\"#ffffff\" stroke=\"#182233\" stroke-width=\"1.8\"/><text x=\"32.00\" y=\"199.99\" text-anchor=\"middle\" font-size=\"11\" font-weight=\"600\" fill=\"#182233\" dominant-baseline=\"central\">9</text></svg>'"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "results = {\n",
    "    \"BOSS\": andrey.boss(X, seed=0),\n",
    "    \"GRaSP\": andrey.grasp(X, seed=0),\n",
    "}\n",
    "for name, result in results.items():\n",
    "    print(f\"{name}: {result.structure.kind}, score {result.metadata['score']:.1f}\")\n",
    "    display(andrey.viz.draw(result.structure))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "permutation_based-6",
   "metadata": {},
   "source": [
    "## Compare with GES over ten datasets\n",
    "\n",
    "GES searches over CPDAGs with a BIC score as well. Structural Hamming distance (SHD) counts errors\n",
    "against the truth's CPDAG; lower is better. The empty graph's SHD is the number of true edges, so\n",
    "an estimate at or above it has not improved on returning no edges. One dataset can favor any\n",
    "method, so the table covers ten seeds and their median."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "permutation_based-7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th>seed</th>\n",
       "      <th>0</th>\n",
       "      <th>1</th>\n",
       "      <th>2</th>\n",
       "      <th>3</th>\n",
       "      <th>4</th>\n",
       "      <th>5</th>\n",
       "      <th>6</th>\n",
       "      <th>7</th>\n",
       "      <th>8</th>\n",
       "      <th>9</th>\n",
       "      <th>median</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Empty graph</th>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "      <td>15</td>\n",
       "      <td>15.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>GES</th>\n",
       "      <td>21</td>\n",
       "      <td>10</td>\n",
       "      <td>0</td>\n",
       "      <td>10</td>\n",
       "      <td>17</td>\n",
       "      <td>7</td>\n",
       "      <td>11</td>\n",
       "      <td>17</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>10.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BOSS</th>\n",
       "      <td>6</td>\n",
       "      <td>8</td>\n",
       "      <td>0</td>\n",
       "      <td>10</td>\n",
       "      <td>1</td>\n",
       "      <td>10</td>\n",
       "      <td>13</td>\n",
       "      <td>11</td>\n",
       "      <td>0</td>\n",
       "      <td>14</td>\n",
       "      <td>9.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>GRaSP</th>\n",
       "      <td>6</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>6</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0.5</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "seed          0   1   2   3   4   5   6   7   8   9  median\n",
       "Empty graph  15  15  15  15  15  15  15  15  15  15    15.0\n",
       "GES          21  10   0  10  17   7  11  17   0   0    10.0\n",
       "BOSS          6   8   0  10   1  10  13  11   0  14     9.0\n",
       "GRaSP         6   0   0   1   1   0   1   6   0   0     0.5"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "methods = {\n",
    "    \"GES\": lambda X: andrey.ges(X),\n",
    "    \"BOSS\": lambda X: andrey.boss(X, seed=0),\n",
    "    \"GRaSP\": lambda X: andrey.grasp(X, seed=0),\n",
    "}\n",
    "rows = {}\n",
    "for s in range(10):\n",
    "    draw = benchmarks.scm(\"linear_gauss_er\", d=10).sample(n=2000, seed=s, scale=\"standardize\")\n",
    "    d = draw.observed_graph.n_nodes\n",
    "    empty = andrey.GraphStructure.from_numpy(np.zeros((d, d), dtype=np.uint8), kind=\"cpdag\")\n",
    "    rows[s] = {\"Empty graph\": metrics.score(empty, draw.observed_graph)[\"shd\"]}\n",
    "    for name, fit in methods.items():\n",
    "        rows[s][name] = metrics.score(fit(draw.data), draw.observed_graph)[\"shd\"]\n",
    "shd = pd.DataFrame(rows)\n",
    "shd.columns.name = \"seed\"\n",
    "shd[\"median\"] = shd.median(axis=1)\n",
    "shd"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "permutation_based-8",
   "metadata": {},
   "source": [
    "A seed where GES reaches the empty graph's SHD is one where it has not improved on returning\n",
    "no edges. The [release cards](https://andrey.abel.ai/docs/benchmarks.html) show the same on\n",
    "larger graphs: GES stays close to the empty graph's SHD, while BOSS and GRaSP come close to zero.\n",
    "\n",
    "## Use another dataset\n",
    "\n",
    "Change `seed`, or the `d` and `n` passed to `benchmarks.scm` and `sample`, and rerun. The\n",
    "benchmarks page also compares both methods with `causal-learn`."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
