{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "90a0b0a2",
   "metadata": {},
   "source": [
    "# rf617_simulation_based_inference_multidimensional\n",
    "Use Simulation Based Inference (SBI) in multiple dimensions in RooFit.\n",
    "\n",
    "This tutorial shows how to use SBI in higher dimension in ROOT.\n",
    "This tutorial transfers the simple concepts of the 1D case introduced in\n",
    "rf615_simulation_based_inference.py onto the higher dimensional case.\n",
    "\n",
    "Again as reference distribution we\n",
    "choose a simple uniform distribution. The target distribution is chosen to\n",
    "be Gaussian with different mean values.\n",
    "The classifier is trained to discriminate between the reference and target\n",
    "distribution.\n",
    "We see how the neural networks generalize to unknown mean values.\n",
    "\n",
    "Furthermore, we compare SBI to the approach of moment morphing. In this case,\n",
    "we can conclude, that SBI is way more sample eficcient when it comes to\n",
    "estimating the negative log likelihood ratio.\n",
    "\n",
    "For an introductory background see rf615_simulation_based_inference.py\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "**Author:** Robin Syring  \n",
    "<i><small>This notebook tutorial was automatically generated with <a href= \"https://github.com/root-project/root/blob/master/documentation/doxygen/converttonotebook.py\">ROOTBOOK-izer</a> from the macro found in the ROOT repository  on Tuesday, May 19, 2026 at 08:33 PM.</small></i>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "e0c9315f",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:33:58.163733Z",
     "iopub.status.busy": "2026-05-19T20:33:58.163595Z",
     "iopub.status.idle": "2026-05-19T20:33:59.999884Z",
     "shell.execute_reply": "2026-05-19T20:33:59.999404Z"
    }
   },
   "outputs": [],
   "source": [
    "import ROOT\n",
    "import numpy as np\n",
    "from sklearn.neural_network import MLPClassifier\n",
    "import itertools"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3a76d13",
   "metadata": {},
   "source": [
    "Kills warning messages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "4337843f",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:00.012512Z",
     "iopub.status.busy": "2026-05-19T20:34:00.012270Z",
     "iopub.status.idle": "2026-05-19T20:34:00.171349Z",
     "shell.execute_reply": "2026-05-19T20:34:00.170768Z"
    }
   },
   "outputs": [],
   "source": [
    "ROOT.RooMsgService.instance().setGlobalKillBelow(ROOT.RooFit.WARNING)\n",
    "\n",
    "n_samples_morph = 10000  # Number of samples for morphing\n",
    "n_bins = 4  # Number of 'sampled' Gaussians\n",
    "n_samples_train = n_samples_morph * n_bins  # To have a fair comparison"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35754e99",
   "metadata": {},
   "source": [
    "Morphing as baseline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "23e82c9c",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:00.173718Z",
     "iopub.status.busy": "2026-05-19T20:34:00.173561Z",
     "iopub.status.idle": "2026-05-19T20:34:00.279481Z",
     "shell.execute_reply": "2026-05-19T20:34:00.278902Z"
    }
   },
   "outputs": [],
   "source": [
    "def morphing(setting, n_dimensions):\n",
    "    # Define binning for morphing\n",
    "\n",
    "    binning = [ROOT.RooBinning(n_bins, 0.0, n_bins - 1.0) for dim in range(n_dimensions)]\n",
    "    grid = ROOT.RooMomentMorphFuncND.Grid(*binning)\n",
    "\n",
    "    # Set bins for each x variable\n",
    "    for x_var in x_vars:\n",
    "        x_var.setBins(50)\n",
    "\n",
    "    # Define mu values as input for morphing for each dimension\n",
    "    mu_helps = [ROOT.RooRealVar(f\"mu{i}\", f\"mu{i}\", 0.0) for i in range(n_dimensions)]\n",
    "\n",
    "    # Create a product of Gaussians for all dimensions\n",
    "    gaussians = []\n",
    "    for j in range(n_dimensions):\n",
    "        gaussian = ROOT.RooGaussian(f\"gdim{j}\", f\"gdim{j}\", x_vars[j], mu_helps[j], sigmas[j])\n",
    "        gaussians.append(gaussian)\n",
    "\n",
    "    # Create a product PDF for the multidimensional Gaussian\n",
    "    gauss_product = ROOT.RooProdPdf(\"gauss_product\", \"gauss_product\", ROOT.RooArgList(*gaussians))\n",
    "\n",
    "    templates = dict()\n",
    "\n",
    "    # Iterate through each tuple\n",
    "    for idx, nd_idx in enumerate(itertools.product(range(n_bins), repeat=n_dimensions)):\n",
    "        for i_dim in range(n_dimensions):\n",
    "            mu_helps[i_dim].setVal(nd_idx[i_dim])\n",
    "\n",
    "        # Fill the histograms\n",
    "        hist = gauss_product.generateBinned(ROOT.RooArgSet(*x_vars), n_samples_morph)\n",
    "\n",
    "        # Ensure that every bin is filled and there are no zero probabilities\n",
    "        for i_bin in range(hist.numEntries()):\n",
    "            hist.add(hist.get(i_bin), 1.0)\n",
    "\n",
    "        templates[nd_idx] = ROOT.RooHistPdf(f\"histpdf{idx}\", f\"histpdf{idx}\", ROOT.RooArgSet(*x_vars), hist, 1)\n",
    "        templates[nd_idx]._data_hist = hist  # To keep the underlying RooDataHist alive\n",
    "\n",
    "        # Add the PDF to the grid\n",
    "        grid.addPdf(templates[nd_idx], *nd_idx)\n",
    "\n",
    "    # Create the morphing function and add it to the ws\n",
    "    morph_func = ROOT.RooMomentMorphFuncND(\"morph_func\", \"morph_func\", [*mu_vars], [*x_vars], grid, setting)\n",
    "    morph_func.setPdfMode(True)\n",
    "    morph = ROOT.RooWrapperPdf(\"morph\", \"morph\", morph_func, True)\n",
    "\n",
    "    ws.Import(morph)\n",
    "\n",
    "    # Uncomment to see input plots for the first dimension (you might need to increase the morphed samples)\n",
    "    # f1 = x_vars[0].frame()\n",
    "    # for i in range(n_bins):\n",
    "    #    templates[(i, 0)].plotOn(f1)\n",
    "    # ws[\"morph\"].plotOn(f1, LineColor=\"r\")\n",
    "    # c0 = ROOT.TCanvas()\n",
    "    # f1.Draw()\n",
    "    # input() # Wait for user input to proceed"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "719115bc",
   "metadata": {},
   "source": [
    "Define the observed mean values for the Gaussian distributions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "cd13d9d6",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:00.281667Z",
     "iopub.status.busy": "2026-05-19T20:34:00.281523Z",
     "iopub.status.idle": "2026-05-19T20:34:00.384900Z",
     "shell.execute_reply": "2026-05-19T20:34:00.384193Z"
    }
   },
   "outputs": [],
   "source": [
    "mu_observed = [2.5, 2.0]\n",
    "sigmas = [1.5, 1.5]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9bb0c0e3",
   "metadata": {},
   "source": [
    "Class used in this case to demonstrate the use of SBI in Root"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "1794080f",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:00.386895Z",
     "iopub.status.busy": "2026-05-19T20:34:00.386767Z",
     "iopub.status.idle": "2026-05-19T20:34:00.492941Z",
     "shell.execute_reply": "2026-05-19T20:34:00.492214Z"
    }
   },
   "outputs": [],
   "source": [
    "class SBI:\n",
    "    # Initializing the class SBI\n",
    "    def __init__(self, ws, n_vars):\n",
    "        # Choose the hyperparameters for training the neural network\n",
    "        self.classifier = MLPClassifier(hidden_layer_sizes=(20, 20), max_iter=1000, random_state=42)\n",
    "        self.data_model = None\n",
    "        self.data_ref = None\n",
    "        self.X_train = None\n",
    "        self.y_train = None\n",
    "        self.ws = ws\n",
    "        self.n_vars = n_vars\n",
    "        self._training_mus = None\n",
    "        self._reference_mu = None\n",
    "\n",
    "    # Defining the target / training data for different values of mean value mu\n",
    "    def model_data(self, model, x_vars, mu_vars, n_samples):\n",
    "        ws = self.ws\n",
    "        samples_gaussian = (\n",
    "            ws[model].generate([ws[x] for x in x_vars] + [ws[mu] for mu in mu_vars], n_samples).to_numpy()\n",
    "        )\n",
    "\n",
    "        self._training_mus = np.array([samples_gaussian[mu] for mu in mu_vars]).T\n",
    "        data_test_model = np.array([samples_gaussian[x] for x in x_vars]).T\n",
    "\n",
    "        self.data_model = data_test_model.reshape(-1, self.n_vars)\n",
    "\n",
    "    # Generating samples for the reference distribution\n",
    "    def reference_data(self, model, x_vars, mu_vars, n_samples, help_model):\n",
    "        ws = self.ws\n",
    "        # Ensuring the normalization with generating as many reference data as target data\n",
    "        samples_uniform = ws[model].generate([ws[x] for x in x_vars], n_samples)\n",
    "        data_reference_model = np.array(\n",
    "            [samples_uniform.get(i).getRealValue(x) for x in x_vars for i in range(samples_uniform.numEntries())]\n",
    "        )\n",
    "\n",
    "        self.data_ref = data_reference_model.reshape(-1, self.n_vars)\n",
    "\n",
    "        samples_mu = ws[help_model].generate([ws[mu] for mu in mu_vars], n_samples)\n",
    "        mu_data = np.array(\n",
    "            [samples_mu.get(i).getRealValue(mu) for mu in mu_vars for i in range(samples_mu.numEntries())]\n",
    "        )\n",
    "\n",
    "        self._reference_mu = mu_data.reshape(-1, self.n_vars)\n",
    "\n",
    "    # Bringing the data in the right format for training\n",
    "    def preprocessing(self):\n",
    "        thetas = np.concatenate((self._training_mus, self._reference_mu))\n",
    "        X = np.concatenate([self.data_model, self.data_ref])\n",
    "\n",
    "        self.y_train = np.concatenate([np.ones(len(self.data_model)), np.zeros(len(self.data_ref))])\n",
    "        self.X_train = np.concatenate([X, thetas], axis=1)\n",
    "\n",
    "    # Train the classifier\n",
    "    def train_classifier(self):\n",
    "        self.classifier.fit(self.X_train, self.y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "739ec967",
   "metadata": {},
   "source": [
    "Define the \"observed\" data in a workspace"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e7731e3e",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:00.494677Z",
     "iopub.status.busy": "2026-05-19T20:34:00.494533Z",
     "iopub.status.idle": "2026-05-19T20:34:00.599460Z",
     "shell.execute_reply": "2026-05-19T20:34:00.598854Z"
    }
   },
   "outputs": [],
   "source": [
    "def build_ws(mu_observed):\n",
    "    n_vars = len(mu_observed)\n",
    "    x_vars = [ROOT.RooRealVar(f\"x{i}\", f\"x{i}\", -5, 15) for i in range(n_vars)]\n",
    "    mu_vars = [ROOT.RooRealVar(f\"mu{i}\", f\"mu{i}\", mu_observed[i], 0, 4) for i in range(n_vars)]\n",
    "    gaussians = [ROOT.RooGaussian(f\"gauss{i}\", f\"gauss{i}\", x_vars[i], mu_vars[i], sigmas[i]) for i in range(n_vars)]\n",
    "    uniforms = [ROOT.RooUniform(f\"uniform{i}\", f\"uniform{i}\", x_vars[i]) for i in range(n_vars)]\n",
    "    uniforms_help = [ROOT.RooUniform(f\"uniformh{i}\", f\"uniformh{i}\", mu_vars[i]) for i in range(n_vars)]\n",
    "    # Create multi-dimensional PDFs\n",
    "    gauss = ROOT.RooProdPdf(\"gauss\", \"gauss\", ROOT.RooArgList(*gaussians))\n",
    "    uniform = ROOT.RooProdPdf(\"uniform\", \"uniform\", ROOT.RooArgList(*uniforms))\n",
    "    uniform_help = ROOT.RooProdPdf(\"uniform_help\", \"uniform_help\", ROOT.RooArgList(*uniforms_help))\n",
    "    obs_data = gauss.generate(ROOT.RooArgSet(*x_vars), n_samples_morph)\n",
    "    obs_data.SetName(\"obs_data\")\n",
    "\n",
    "    # Create and return the workspace\n",
    "    ws = ROOT.RooWorkspace()\n",
    "    ws.Import(x_vars)\n",
    "    ws.Import(mu_vars)\n",
    "    ws.Import(gauss)\n",
    "    ws.Import(uniform)\n",
    "    ws.Import(uniform_help)\n",
    "    ws.Import(obs_data)\n",
    "\n",
    "    return ws"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8307d57f",
   "metadata": {},
   "source": [
    "Build the workspace and extract variables"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "113170b0",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:00.601402Z",
     "iopub.status.busy": "2026-05-19T20:34:00.601269Z",
     "iopub.status.idle": "2026-05-19T20:34:00.974435Z",
     "shell.execute_reply": "2026-05-19T20:34:00.974054Z"
    }
   },
   "outputs": [],
   "source": [
    "ws = build_ws(mu_observed)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf0bc3a1",
   "metadata": {},
   "source": [
    "Export the varibles from ws"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "b15ee24d",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:00.981375Z",
     "iopub.status.busy": "2026-05-19T20:34:00.981226Z",
     "iopub.status.idle": "2026-05-19T20:34:01.124594Z",
     "shell.execute_reply": "2026-05-19T20:34:01.123980Z"
    }
   },
   "outputs": [],
   "source": [
    "x_vars = [ws[f\"x{i}\"] for i in range(len(mu_observed))]\n",
    "mu_vars = [ws[f\"mu{i}\"] for i in range(len(mu_observed))]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78c854ce",
   "metadata": {},
   "source": [
    "Do the morphing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "284738f1",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:01.127435Z",
     "iopub.status.busy": "2026-05-19T20:34:01.127310Z",
     "iopub.status.idle": "2026-05-19T20:34:01.383342Z",
     "shell.execute_reply": "2026-05-19T20:34:01.382739Z"
    }
   },
   "outputs": [],
   "source": [
    "morphing(ROOT.RooMomentMorphFuncND.Linear, len(mu_observed))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0349174",
   "metadata": {},
   "source": [
    "Calculate the nll for the moprhed distribution\n",
    "TODO: Fix RooAddPdf::fixCoefNormalization(nset) warnings with new CPU backend"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "405c1f6d",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:01.385538Z",
     "iopub.status.busy": "2026-05-19T20:34:01.385410Z",
     "iopub.status.idle": "2026-05-19T20:34:06.343485Z",
     "shell.execute_reply": "2026-05-19T20:34:06.336098Z"
    }
   },
   "outputs": [],
   "source": [
    "nll_morph = ws[\"morph\"].createNLL(ws[\"obs_data\"], EvalBackend=\"legacy\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3cc41f3d",
   "metadata": {},
   "source": [
    "Initialize the SBI model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "c6805d16",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:06.349681Z",
     "iopub.status.busy": "2026-05-19T20:34:06.349513Z",
     "iopub.status.idle": "2026-05-19T20:34:06.453163Z",
     "shell.execute_reply": "2026-05-19T20:34:06.452413Z"
    }
   },
   "outputs": [],
   "source": [
    "model = SBI(ws, len(mu_observed))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a283157e",
   "metadata": {},
   "source": [
    "Generate and preprocess training data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "eee6d176",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:06.455033Z",
     "iopub.status.busy": "2026-05-19T20:34:06.454894Z",
     "iopub.status.idle": "2026-05-19T20:34:06.898208Z",
     "shell.execute_reply": "2026-05-19T20:34:06.897399Z"
    }
   },
   "outputs": [],
   "source": [
    "model.model_data(\"gauss\", [x.GetName() for x in x_vars], [mu.GetName() for mu in mu_vars], n_samples_train)\n",
    "model.reference_data(\n",
    "    \"uniform\", [x.GetName() for x in x_vars], [mu.GetName() for mu in mu_vars], n_samples_train, \"uniform_help\"\n",
    ")\n",
    "model.preprocessing()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1230d1b",
   "metadata": {},
   "source": [
    "Train the neural network classifier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "bed2112d",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:06.900060Z",
     "iopub.status.busy": "2026-05-19T20:34:06.899933Z",
     "iopub.status.idle": "2026-05-19T20:34:10.934907Z",
     "shell.execute_reply": "2026-05-19T20:34:10.934448Z"
    }
   },
   "outputs": [],
   "source": [
    "model.train_classifier()\n",
    "sbi_model = model"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1e4b539",
   "metadata": {},
   "source": [
    "Function to compute the likelihood ratio using the trained classifier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "88028cb2",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:10.947409Z",
     "iopub.status.busy": "2026-05-19T20:34:10.947262Z",
     "iopub.status.idle": "2026-05-19T20:34:11.051321Z",
     "shell.execute_reply": "2026-05-19T20:34:11.050641Z"
    }
   },
   "outputs": [],
   "source": [
    "def learned_likelihood_ratio(*args):\n",
    "    n = max(*(len(a) for a in args))\n",
    "    X = np.zeros((n, len(args)))\n",
    "    for i in range(len(args)):\n",
    "        X[:, i] = args[i]\n",
    "    prob = sbi_model.classifier.predict_proba(X)[:, 1]\n",
    "    return prob / (1.0 - prob)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "80fa60c3",
   "metadata": {},
   "source": [
    "Create combined variable list for ROOT"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "5914752e",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:11.053461Z",
     "iopub.status.busy": "2026-05-19T20:34:11.053331Z",
     "iopub.status.idle": "2026-05-19T20:34:11.164800Z",
     "shell.execute_reply": "2026-05-19T20:34:11.163937Z"
    }
   },
   "outputs": [],
   "source": [
    "combined_vars = ROOT.RooArgList()\n",
    "for var in x_vars + mu_vars:\n",
    "    combined_vars.add(var)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63b57537",
   "metadata": {},
   "source": [
    "Create a custom likelihood ratio function using the trained classifier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "c79a850f",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:11.166446Z",
     "iopub.status.busy": "2026-05-19T20:34:11.166320Z",
     "iopub.status.idle": "2026-05-19T20:34:11.612046Z",
     "shell.execute_reply": "2026-05-19T20:34:11.611410Z"
    }
   },
   "outputs": [],
   "source": [
    "lhr_learned = ROOT.RooFit.bindFunction(\"MyBinFunc\", learned_likelihood_ratio, combined_vars)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55191389",
   "metadata": {},
   "source": [
    "Calculate the 'analytical' likelihood ratio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "910ed41a",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:11.614185Z",
     "iopub.status.busy": "2026-05-19T20:34:11.614054Z",
     "iopub.status.idle": "2026-05-19T20:34:11.725793Z",
     "shell.execute_reply": "2026-05-19T20:34:11.725070Z"
    }
   },
   "outputs": [],
   "source": [
    "lhr_calc = ROOT.RooFormulaVar(\"lhr_calc\", \"x[0] / x[1]\", [ws[\"gauss\"], ws[\"uniform\"]])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31cfe20b",
   "metadata": {},
   "source": [
    "Define the 'analytical' negative logarithmic likelihood ratio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "f4ee321e",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:11.727674Z",
     "iopub.status.busy": "2026-05-19T20:34:11.727529Z",
     "iopub.status.idle": "2026-05-19T20:34:11.832536Z",
     "shell.execute_reply": "2026-05-19T20:34:11.831743Z"
    }
   },
   "outputs": [],
   "source": [
    "nll_gauss = ws[\"gauss\"].createNLL(ws[\"obs_data\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a68dc448",
   "metadata": {},
   "source": [
    "Create the learned pdf and NLL sum based on the learned likelihood ratio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "dde474bd",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:11.834228Z",
     "iopub.status.busy": "2026-05-19T20:34:11.834097Z",
     "iopub.status.idle": "2026-05-19T20:34:11.949027Z",
     "shell.execute_reply": "2026-05-19T20:34:11.948284Z"
    }
   },
   "outputs": [],
   "source": [
    "pdf_learned = ROOT.RooWrapperPdf(\"learned_pdf\", \"learned_pdf\", lhr_learned, True)\n",
    "\n",
    "nllr_learned = pdf_learned.createNLL(ws[\"obs_data\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74c38087",
   "metadata": {},
   "source": [
    "Plot the learned and analytical summed negativelogarithmic likelihood"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "8f058138",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:11.951123Z",
     "iopub.status.busy": "2026-05-19T20:34:11.950993Z",
     "iopub.status.idle": "2026-05-19T20:34:28.109859Z",
     "shell.execute_reply": "2026-05-19T20:34:28.109325Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf0_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf0_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf0_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf0_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf1_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf1_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf1_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf1_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf2_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf2_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf2_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf2_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf3_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf3_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf3_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf3_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf4_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf4_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf4_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf4_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf5_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf5_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf5_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf5_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf6_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf6_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf6_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf6_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf7_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf7_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf7_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf7_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf8_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf8_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf8_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf8_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf9_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf9_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf9_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf9_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf10_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf10_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf10_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf10_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf11_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf11_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf11_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf11_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf12_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf12_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf12_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf12_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf13_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf13_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf13_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf13_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf14_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf14_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf14_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf14_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf15_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf15_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf15_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf15_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf0_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf0_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf0_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf0_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf1_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf1_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf1_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf1_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf2_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf2_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf2_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf2_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf3_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf3_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf3_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf3_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf4_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf4_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf4_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf4_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf5_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf5_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf5_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf5_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf6_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf6_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf6_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf6_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf7_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf7_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf7_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf7_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf8_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf8_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf8_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf8_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf9_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf9_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf9_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf9_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf10_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf10_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf10_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf10_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf11_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf11_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf11_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf11_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf12_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf12_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf12_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf12_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf13_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf13_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf13_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf13_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf14_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf14_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf14_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf14_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf15_MOMENT_1_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf15_MOMENT_2C_x0_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf15_MOMENT_1_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n",
      "[#0] WARNING:NumericIntegration -- RooAdaptiveIntegratorND::dtor(histpdf15_MOMENT_2C_x1_product) WARNING: Number of suppressed warningings about integral evaluations where target precision was not reached is 1\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<cppyy.gbl.RooPlot object at 0x55af99388d50>"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "frame1 = mu_vars[0].frame(\n",
    "    Title=\"NLL of SBI vs. Morphing;#mu_{1};NLL\",\n",
    "    Range=(mu_observed[0] - 1, mu_observed[0] + 1),\n",
    ")\n",
    "nll_gauss.plotOn(frame1, ShiftToZero=True, LineColor=\"kP6Yellow\", Name=\"gauss\")\n",
    "ROOT.RooAbsReal.setEvalErrorLoggingMode(\"Ignore\")  # Silence some warnings\n",
    "nll_morph.plotOn(frame1, ShiftToZero=True, LineColor=\"kP6Red\", Name=\"morph\")\n",
    "ROOT.RooAbsReal.setEvalErrorLoggingMode(\"PrintErrors\")\n",
    "nllr_learned.plotOn(frame1, LineColor=\"kP6Blue\", ShiftToZero=True, Name=\"learned\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "713a0581",
   "metadata": {},
   "source": [
    "Declare a helper function in ROOT to dereference unique_ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "09409ef3",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:28.114328Z",
     "iopub.status.busy": "2026-05-19T20:34:28.114172Z",
     "iopub.status.idle": "2026-05-19T20:34:28.227445Z",
     "shell.execute_reply": "2026-05-19T20:34:28.226554Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ROOT.gInterpreter.Declare(\n",
    "    \"\"\"\n",
    "RooAbsArg &my_deref(std::unique_ptr<RooAbsArg> const& ptr) { return *ptr; }\n",
    "\"\"\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1a61f9c0",
   "metadata": {},
   "source": [
    "Choose normalization set for lhr_calc to plot over"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "81d6a3cc",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:28.229520Z",
     "iopub.status.busy": "2026-05-19T20:34:28.229353Z",
     "iopub.status.idle": "2026-05-19T20:34:28.385998Z",
     "shell.execute_reply": "2026-05-19T20:34:28.385211Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "norm_set = ROOT.RooArgSet(x_vars)\n",
    "lhr_calc_final_ptr = ROOT.RooFit.Detail.compileForNormSet(lhr_calc, norm_set)\n",
    "lhr_calc_final = ROOT.my_deref(lhr_calc_final_ptr)\n",
    "lhr_calc_final.recursiveRedirectServers(norm_set)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ce22451",
   "metadata": {},
   "source": [
    "Plot the likelihood ratio functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "0b0d4470",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:28.388218Z",
     "iopub.status.busy": "2026-05-19T20:34:28.388053Z",
     "iopub.status.idle": "2026-05-19T20:34:28.517278Z",
     "shell.execute_reply": "2026-05-19T20:34:28.516588Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<cppyy.gbl.RooPlot object at 0x55af99870630>"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "frame2 = x_vars[0].frame(Title=\"Likelihood ratio r(x_{1}|#mu_{1}=2.5);x_{1};p_{gauss}/p_{uniform}\")\n",
    "lhr_learned.plotOn(frame2, LineColor=\"kP6Blue\", Name=\"learned_ratio\")\n",
    "lhr_calc_final.plotOn(frame2, LineColor=\"kP6Yellow\", Name=\"exact\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "737379a5",
   "metadata": {},
   "source": [
    "Write the plots into one canvas to show, or into separate canvases for saving."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "70e0a519",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:28.519544Z",
     "iopub.status.busy": "2026-05-19T20:34:28.519389Z",
     "iopub.status.idle": "2026-05-19T20:34:28.698549Z",
     "shell.execute_reply": "2026-05-19T20:34:28.697797Z"
    }
   },
   "outputs": [],
   "source": [
    "single_canvas = True\n",
    "\n",
    "c = ROOT.TCanvas(\"\", \"\", 1200 if single_canvas else 600, 600)\n",
    "if single_canvas:\n",
    "    c.Divide(2)\n",
    "    c.cd(1)\n",
    "    ROOT.gPad.SetLeftMargin(0.15)\n",
    "    frame1.GetYaxis().SetTitleOffset(1.8)\n",
    "frame1.Draw()\n",
    "\n",
    "legend1 = ROOT.TLegend(0.43, 0.63, 0.8, 0.87)\n",
    "legend1.SetFillColor(\"background\")\n",
    "legend1.SetLineColor(\"background\")\n",
    "legend1.SetTextSize(0.04)\n",
    "legend1.AddEntry(\"learned\", \"learned (SBI)\", \"L\")\n",
    "legend1.AddEntry(\"gauss\", \"true NLL\", \"L\")\n",
    "legend1.AddEntry(\"morphed\", \"moment morphing\", \"L\")\n",
    "legend1.Draw()\n",
    "\n",
    "if single_canvas:\n",
    "    c.cd(2)\n",
    "    ROOT.gPad.SetLeftMargin(0.15)\n",
    "    frame2.GetYaxis().SetTitleOffset(1.8)\n",
    "else:\n",
    "    c.SaveAs(\"rf617_plot_1.png\")\n",
    "    c = ROOT.TCanvas(\"\", \"\", 600, 600)\n",
    "\n",
    "frame2.Draw()\n",
    "\n",
    "legend2 = ROOT.TLegend(0.53, 0.73, 0.87, 0.87)\n",
    "legend2.SetFillColor(\"background\")\n",
    "legend2.SetLineColor(\"background\")\n",
    "legend2.SetTextSize(0.04)\n",
    "legend2.AddEntry(\"learned_ratio\", \"learned (SBI)\", \"L\")\n",
    "legend2.AddEntry(\"exact\", \"true ratio\", \"L\")\n",
    "legend2.Draw()\n",
    "\n",
    "if not single_canvas:\n",
    "    c.SaveAs(\"rf617_plot_2.png\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c21af93e",
   "metadata": {},
   "source": [
    "Use ROOT's minimizer to compute the minimum and display the results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "a78ed60b",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:28.700627Z",
     "iopub.status.busy": "2026-05-19T20:34:28.700483Z",
     "iopub.status.idle": "2026-05-19T20:34:31.106433Z",
     "shell.execute_reply": "2026-05-19T20:34:31.105895Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "  RooFitResult: minimized FCN value: 36418.9, estimated distance to minimum: 1.43276e-06\n",
      "                covariance matrix quality: Full, accurate covariance matrix\n",
      "                Status : MINIMIZE=0 \n",
      "\n",
      "    Floating Parameter    FinalValue +/-  Error   \n",
      "  --------------------  --------------------------\n",
      "                   mu0    2.5116e+00 +/-  1.50e-02\n",
      "                   mu1    2.0000e+00 +/-  1.50e-02\n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "  RooFitResult: minimized FCN value: -23474.8, estimated distance to minimum: 1.23305e-05\n",
      "                covariance matrix quality: Full, accurate covariance matrix\n",
      "                Status : MINIMIZE=0 \n",
      "\n",
      "    Floating Parameter    FinalValue +/-  Error   \n",
      "  --------------------  --------------------------\n",
      "                   mu0    2.3674e+00 +/-  1.43e-02\n",
      "                   mu1    2.0127e+00 +/-  1.41e-02\n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "  RooFitResult: minimized FCN value: 38093.1, estimated distance to minimum: 1.95335e-05\n",
      "                covariance matrix quality: Full, accurate covariance matrix\n",
      "                Status : MINIMIZE=0 \n",
      "\n",
      "    Floating Parameter    FinalValue +/-  Error   \n",
      "  --------------------  --------------------------\n",
      "                   mu0    2.3835e+00 +/-  3.64e-03\n",
      "                   mu1    1.8344e+00 +/-  1.78e-02\n",
      "\n"
     ]
    }
   ],
   "source": [
    "for nll in [nll_gauss, nllr_learned, nll_morph]:\n",
    "    minimizer = ROOT.RooMinimizer(nll)\n",
    "    minimizer.setErrorLevel(0.5)\n",
    "    minimizer.setPrintLevel(-1)\n",
    "    minimizer.minimize(\"Minuit2\")\n",
    "    result = minimizer.save()\n",
    "    result.Print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3bcf776a",
   "metadata": {},
   "source": [
    "Draw all canvases "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "442a2e5a",
   "metadata": {
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2026-05-19T20:34:31.107943Z",
     "iopub.status.busy": "2026-05-19T20:34:31.107817Z",
     "iopub.status.idle": "2026-05-19T20:34:31.302079Z",
     "shell.execute_reply": "2026-05-19T20:34:31.301618Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "\n",
       "<div id=\"root_plot_1779222871292\" style=\"width: 1200px; height: 600px; position: relative\">\n",
       "</div>\n",
       "\n",
       "</div>\n",
       "<script>\n",
       "   function process_root_plot_1779222871292() {\n",
       "      function execCode(Core) {\n",
       "         Core.settings.HandleKeys = false;\n",
       "         \n",
       "Core.unzipJSON(43978,'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').then(json => {\n",
       "   const obj = Core.parse(json);\n",
       "   Core.draw('root_plot_1779222871292', obj, '');\n",
       "});\n",
       "\n",
       "      }\n",
       "      const servers = ['/static/', 'https://root.cern/js/7.11.0/', 'https://jsroot.gsi.de/7.11.0/'],\n",
       "            path = 'build/jsroot';\n",
       "      if (typeof JSROOT !== 'undefined')\n",
       "         execCode(JSROOT);\n",
       "      else if (typeof requirejs !== 'undefined') {\n",
       "         servers.forEach((s,i) => { servers[i] = s + path; });\n",
       "         requirejs.config({ paths: { 'jsroot' : servers } })(['jsroot'],  execCode);\n",
       "      } else {\n",
       "         const config = document.getElementById('jupyter-config-data');\n",
       "         if (config)\n",
       "            servers[0] = (JSON.parse(config.innerHTML || '{}')?.baseUrl || '/') + 'static/';\n",
       "         else\n",
       "            servers.shift();\n",
       "         function loadJsroot() {\n",
       "            return !servers.length ? 0 : import(servers.shift() + path + '.js').catch(loadJsroot).then(() => execCode(JSROOT));\n",
       "         }\n",
       "         loadJsroot();\n",
       "      }\n",
       "   }\n",
       "   process_root_plot_1779222871292();\n",
       "</script>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from ROOT import gROOT \n",
    "gROOT.GetListOfCanvases().Draw()"
   ]
  }
 ],
 "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
}
