<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://ferjorosa.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://ferjorosa.github.io/" rel="alternate" type="text/html" /><updated>2026-01-17T19:11:02+00:00</updated><id>https://ferjorosa.github.io/feed.xml</id><title type="html">Fernando Rodriguez</title><author><name>Fernando Rodriguez</name></author><entry><title type="html">How do language models solve Bayesian network inference?</title><link href="https://ferjorosa.github.io/blog/2026/01/02/llms-probailistic-reasoning.html" rel="alternate" type="text/html" title="How do language models solve Bayesian network inference?" /><published>2026-01-02T00:00:00+00:00</published><updated>2026-01-02T00:00:00+00:00</updated><id>https://ferjorosa.github.io/blog/2026/01/02/llms-probailistic-reasoning</id><content type="html" xml:base="https://ferjorosa.github.io/blog/2026/01/02/llms-probailistic-reasoning.html"><![CDATA[<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">
<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">Table of Contents</summary>

<ul style="margin-top: 0.5em;">
  <li style="margin-bottom: 0.5em;"><a href="#can-large-language-models-think-rationally">Can language models think "probabilistically"?</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#bayesian-networks">Bayesian networks</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#probabilistic-inference-on-bayesian-networks">Probabilistic inference on Bayesian networks</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#variable-elimination-algorithm">Variable Elimination algorithm</a>
    <ul style="margin-top: 0.3em;">
      <li style="margin-bottom: 0.3em;"><a href="#operations-on-factors">Operations on factors</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#the-algorithm">The algorithm</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#example">Example</a>
        <ul style="margin-top: 0.3em;">
          <li style="margin-bottom: 0.3em;"><a href="#step-1-restrict-factors">Step 1: Restrict factors based on evidence</a></li>
          <li style="margin-bottom: 0.3em;"><a href="#step-2-eliminate-v2">Step 2: Eliminate V2</a></li>
          <li style="margin-bottom: 0.3em;"><a href="#step-3-eliminate-v0">Step 3: Eliminate V0</a></li>
          <li style="margin-bottom: 0.3em;"><a href="#step-4-normalize">Step 4: Normalize</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li style="margin-bottom: 0.5em;"><a href="#how-llms-do-it">How LLMs do it</a>
    <ul style="margin-top: 0.3em;">
      <li style="margin-bottom: 0.3em;"><a href="#experimental-setup">Experimental setup</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#raw-reasoning-results">Raw reasoning results</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#code-generation-results">Code generation results</a></li>
    </ul>
  </li>
  <li style="margin-bottom: 0.5em;"><a href="#conclusion">Conclusion</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#references">References</a></li>
</ul>

</details>

<h2 id="can-large-language-models-think-rationally">Can language models think "probabilistically"?</h2>

<p>This question has been on my mind for a while. It motivated me to revisit probabilistic graphical models, write my <a href="https://ferjorosa.github.io/blog/2025/08/07/decision-theory-III.html">blog series on Decision Theory</a>, and explore how large language models (LLMs) solved <a href="https://github.com/ferjorosa/decision-theory-llms/blob/main/notebooks/how_good_are_llms_decision_problems.ipynb">a few hand-crafted decision problems</a>.</p>

<p>Early experiments were promising: models like O3 and Gemini-2.5-Pro reached correct solutions on small decision problems. But I observed they were solving them using decision trees, which <a href="https://ferjorosa.github.io/blog/2025/07/04/decision-theory-II.html">have theoretical limitations</a>. I wondered: were LLMs using decision trees because it was “easier”, or because they didn’t know how to apply influence diagrams?</p>

<p>To answer that, I started running more extensive experiments. But midway through, I realized I was getting ahead of myself. If I wanted to evaluate LLMs on influence diagrams, I should probably start with Bayesian networks, since influence diagrams are essentially Bayesian networks augmented with decisions and utilities. If LLMs struggle with probabilistic inference on Bayesian networks, expecting them to solve full decision problems could be premature.</p>

<p>So that’s what this post explores: <strong>how do current frontier LLMs handle probabilistic inference on a Bayesian network?</strong> I’ll walk through the Variable Elimination algorithm since it is one of the easiest to understand and implement, solve an example by hand with it, and then compare how seven reasoning LLMs approach the same query, analyzing not just whether they get the right answer, but <em>how</em> they reason through the problem.</p>

<h2 id="bayesian-networks">Bayesian networks</h2>

<p>A Bayesian network (BN) is a directed acyclic graph (DAG) in which nodes represent random variables. Arcs encode conditional dependencies between variables in a way that allows us to factorize the joint probability distribution into a product of conditional probability distributions (CPDs),</p>

\[\begin{equation}
P(\mathbf{\textcolor{purple}{V}}) = P(\textcolor{purple}{V_1}, \ldots, \textcolor{purple}{V_n}) = \prod_{i=1}^{n} P(\textcolor{purple}{V_i} | \mathbf{Pa}_{\textcolor{purple}{V_i}})
\end{equation}\]

<p>where \(\mathbf{Pa}_{\textcolor{purple}{V_i}}\) denotes the parents of variable \(\textcolor{purple}{V_i}\) in the DAG. This property is often called the <strong>chain rule for Bayesian networks</strong>.</p>

<p>As an example, consider a Bayesian network with 4 binary variables (\(\textcolor{purple}{V_0}, \textcolor{purple}{V_1}, \textcolor{purple}{V_2}, \textcolor{purple}{V_3}\)). The structure is a simple diamond-like shape where \(\textcolor{purple}{V_0}\) is the root, \(\textcolor{purple}{V_1}\) and \(\textcolor{purple}{V_2}\) depend on \(\textcolor{purple}{V_0}\), and \(\textcolor{purple}{V_3}\) depends on both \(\textcolor{purple}{V_0}\) and \(\textcolor{purple}{V_1}\).</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-12-14-llms-bn-inference/bn_example.png" alt="Bayesian network example" height="300" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 1.</b> Bayesian network example with 4 variables</i>
    </td>
  </tr>
</table>
</center>

<table>
  <tr>
    <th colspan="2" style="text-align: center;">$$P(\textcolor{purple}{V_0})$$</th>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_0}$$</td>
    <td>0.5072</td>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_1}$$</td>
    <td>0.4928</td>
  </tr>
</table>

<table>
  <tr>
    <th rowspan="2" style="text-align: center;">$$P(\textcolor{purple}{V_1} \mid \textcolor{purple}{V_0})$$</th>
    <th colspan="2" style="text-align: center;">$$\textcolor{purple}{V_0}$$</th>
  </tr>
  <tr>
    <th style="text-align: center;">$$\textcolor{purple}{s_0}$$</th>
    <th style="text-align: center;">$$\textcolor{purple}{s_1}$$</th>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_0}$$</td>
    <td>0.3110</td>
    <td>0.0704</td>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_1}$$</td>
    <td>0.6890</td>
    <td>0.9296</td>
  </tr>
</table>

<table>
  <tr>
    <th rowspan="2" style="text-align: center;">$$P(\textcolor{purple}{V_2} \mid \textcolor{purple}{V_0})$$</th>
    <th colspan="2" style="text-align: center;">$$\textcolor{purple}{V_0}$$</th>
  </tr>
  <tr>
    <th style="text-align: center;">$$\textcolor{purple}{s_0}$$</th>
    <th style="text-align: center;">$$\textcolor{purple}{s_1}$$</th>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_0}$$</td>
    <td>0.8950</td>
    <td>0.0562</td>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_1}$$</td>
    <td>0.1050</td>
    <td>0.9438</td>
  </tr>
</table>

<table>
  <tr>
    <th rowspan="2" style="text-align: center;">$$P(\textcolor{purple}{V_3} \mid \textcolor{purple}{V_0},\, \textcolor{purple}{V_1})$$</th>
    <th colspan="2" style="text-align: center;">$$\textcolor{purple}{V_0 = s_0}$$</th>
    <th colspan="2" style="text-align: center;">$$\textcolor{purple}{V_0 = s_1}$$</th>
  </tr>
  <tr>
    <th style="text-align: center;">$$\textcolor{purple}{V_1 = s_0}$$</th>
    <th style="text-align: center;">$$\textcolor{purple}{V_1 = s_1}$$</th>
    <th style="text-align: center;">$$\textcolor{purple}{V_1 = s_0}$$</th>
    <th style="text-align: center;">$$\textcolor{purple}{V_1 = s_1}$$</th>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_0}$$</td>
    <td>0.0607</td>
    <td>0.8173</td>
    <td>0.8890</td>
    <td>0.2251</td>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_1}$$</td>
    <td>0.9393</td>
    <td>0.1827</td>
    <td>0.1110</td>
    <td>0.7749</td>
  </tr>
</table>

<h2 id="probabilistic-inference-on-bayesian-networks">Probabilistic inference on Bayesian networks</h2>

<p>Once we have a BN, we can use it to reason by performing probabilistic inference. This task involves computing the probability of query variables \(\mathbf{\textcolor{purple}{Q}}\) given some observed evidence \(\mathbf{\textcolor{purple}{E}} = \mathbf{\textcolor{purple}{e}}\).</p>

<p>Theoretically, this is straightforward. The Bayesian network defines the full joint distribution, so we could sum over all unobserved “nuisance” variables \(\mathbf{\textcolor{purple}{Z}}\):</p>

\[\begin{equation}
P(\mathbf{\textcolor{purple}{Q}} = \mathbf{\textcolor{purple}{q}} \mid \mathbf{\textcolor{purple}{E}} = \mathbf{\textcolor{purple}{e}}) = \frac{\sum_{\mathbf{\textcolor{purple}{z}}} P(\mathbf{\textcolor{purple}{Q}} = \mathbf{\textcolor{purple}{q}}, \mathbf{\textcolor{purple}{E}} = \mathbf{\textcolor{purple}{e}}, \mathbf{\textcolor{purple}{Z}} = \mathbf{\textcolor{purple}{z}})}{\sum_{\mathbf{\textcolor{purple}{q}}, \mathbf{\textcolor{purple}{z}}} P(\mathbf{\textcolor{purple}{Q}} = \mathbf{\textcolor{purple}{q}}, \mathbf{\textcolor{purple}{E}} = \mathbf{\textcolor{purple}{e}}, \mathbf{\textcolor{purple}{Z}} = \mathbf{\textcolor{purple}{z}})}
\end{equation}\]

<p>However, this naive approach is computationally infeasible. For a network with \(n\) binary variables, storing the full joint distribution would require a table with \(2^n\) entries.</p>

<p>Instead of storing that massive table, we can use the <strong>BN factorization</strong> (Equation 1) to compute only the specific joint probabilities we need on-the-fly. By substituting the factorization into Equation (2), we get:</p>

\[\begin{equation}
P(\mathbf{\textcolor{purple}{Q}} = \mathbf{\textcolor{purple}{q}} \mid \mathbf{\textcolor{purple}{E}} = \mathbf{\textcolor{purple}{e}}) = \frac{\sum_{\mathbf{\textcolor{purple}{z}}} \prod_{i=1}^{n} P(\textcolor{purple}{V_i} \mid \mathbf{Pa}_{\textcolor{purple}{V_i}})}{\sum_{\mathbf{\textcolor{purple}{q}}, \mathbf{\textcolor{purple}{z}}} \prod_{i=1}^{n} P(\textcolor{purple}{V_i} \mid \mathbf{Pa}_{\textcolor{purple}{V_i}})}
\end{equation}\]

<p>While this saves us from storing the full table, we still face the problem of summing over it. We still need to enumerate all combinations of hidden variables \(\mathbf{\textcolor{purple}{z}}\). For 30 binary variables, that’s over a billion terms to sum. This approach, often called <strong>inference by enumeration</strong> or simply applying the <strong>chain rule</strong> naively, is conceptually simple but does not scale.</p>

<p>Efficient inference algorithms avoid this exponential blowup by exploiting the factorized representation more cleverly. Rather than enumerating all combinations, they manipulate the individual CPDs (which are much smaller) and perform marginalization locally, pushing sums inside products where conditional independence allows. Well-known examples include Variable Elimination, Junction Tree algorithm, and Belief Propagation (<a href="http://mcb111.org/w06/KollerFriedman.pdf">Koller &amp; Friedman, 2009</a>). We’ll focus on Variable Elimination since it’s the easiest to explain and commonly used when teaching BN inference.</p>

<h2 id="variable-elimination-algorithm">Variable Elimination algorithm</h2>

<p>As the name suggests, the <strong>Variable Elimination</strong> (VE) algorithm works by eliminating the variables of the network until it yields the answer to a specific query. This algorithm is
typically defined in terms of factors.</p>

<p>A <strong>factor</strong> \(\phi(\mathbf{\textcolor{purple}{X}})\) is a function that maps a set of variables \(\mathbf{\textcolor{purple}{X}}\) to a real positive value. CPDs are an example of factors. In fact, the initial set of factors corresponds exactly to the CPDs of the network.</p>

<p>During inference, new factors are created by multiplying and marginalizing existing ones. These <strong>intermediate factors</strong> are generally <strong>unnormalized</strong>, meaning their values do not sum to one. This is not a problem, since normalization is only required for the final result. Working with unnormalized factors simplifies computation and allows inference algorithms to focus on local operations.</p>

<h3 id="operations-on-factors">Operations on factors</h3>

<p>VE relies on three operations:</p>

<ol>
  <li><strong>Factor Product:</strong> Combine two factors \(\phi_1(\textcolor{purple}{V_1})\) and \(\phi_2(\textcolor{purple}{V_2})\) into a new factor \(\phi_{new}\) over \(\textcolor{purple}{V_1} \cup \textcolor{purple}{V_2}\) by multiplying their values for every consistent assignment:</li>
</ol>

\[\phi_{new}(\textcolor{purple}{V_1}, \textcolor{purple}{V_2}) = \phi_1(\textcolor{purple}{V_1}) \cdot \phi_2(\textcolor{purple}{V_2})\]

<ol>
  <li>
    <p><strong>Marginalization:</strong> Eliminate a variable \(\textcolor{purple}{Z}\) from factor \(\phi(\textcolor{purple}{V}, \textcolor{purple}{Z})\) by summing over all its values to produce a new factor \(\phi_{new}\):</p>

\[\phi_{new}(\textcolor{purple}{V}) = \sum_{\textcolor{purple}{z}} \phi(\textcolor{purple}{V}, \textcolor{purple}{Z} =\textcolor{purple}{z})\]
  </li>
  <li>
    <p><strong>Evidence restriction:</strong> If variable \(\textcolor{purple}{E}\) is observed to be \(\textcolor{purple}{e}\), restrict any factor containing \(\textcolor{purple}{E}\) to that value, essentially selecting the slice of the table consistent with the observation.</p>
  </li>
</ol>

<h3 id="the-algorithm">The algorithm</h3>

<p>Given a Bayesian network, query variables \(\mathbf{\textcolor{purple}{Q}}\), and evidence \(\mathbf{\textcolor{purple}{E}} = \mathbf{\textcolor{purple}{e}}\):</p>

<ol>
  <li>
    <p><strong>Initialize:</strong> Treat each CPD as a factor. Restrict all factors to be consistent with the evidence \(\mathbf{\textcolor{purple}{E}} = \mathbf{\textcolor{purple}{e}}\).</p>
  </li>
  <li>
    <p><strong>Choose elimination order:</strong> Pick an ordering for the hidden variables \(\mathbf{\textcolor{purple}{Z}}\) (neither query nor evidence). The choice of ordering affects efficiency because <strong>bad orders create large intermediate factors</strong>.</p>
  </li>
</ol>

<!-- Here we should later put a comment with a reference or something explaining different heuristics for elimination order -->

<ol>
  <li><strong>Eliminate variables:</strong> For each variable \(\textcolor{purple}{Z_i}\) in order:
    <ul>
      <li><strong>Collect</strong> all factors containing \(\textcolor{purple}{Z_i}\)</li>
      <li><strong>Multiply</strong> them into a single factor \(\phi_{new}'\)</li>
      <li><strong>Sum out</strong> \(\textcolor{purple}{Z_i}\) to get a new factor \(\phi_{new}''\)</li>
      <li><strong>Replace</strong> the collected factors with \(\phi_{new}''\)</li>
    </ul>
  </li>
  <li><strong>Normalize:</strong> Multiply remaining factors (now only over \(\mathbf{\textcolor{purple}{Q}}\)) and normalize to obtain \(P(\mathbf{\textcolor{purple}{Q}} = \mathbf{\textcolor{purple}{q}} \mid \mathbf{\textcolor{purple}{E}} = \mathbf{\textcolor{purple}{e}})\).</li>
</ol>

<h3 id="example">Example</h3>

<p>As an example we are going to use the BN we defined in Figure 1 and compute the probability of \(\textcolor{purple}{V_3}\) being \(\textcolor{purple}{s_1}\) given that \(\textcolor{purple}{V_1}\) is observed to be \(\textcolor{purple}{s_0}\):</p>

\[P(\textcolor{purple}{V_3} = \textcolor{purple}{s_1} \mid \textcolor{purple}{V_1} = \textcolor{purple}{s_0})\]

<p>The evidence is \(\mathbf{\textcolor{purple}{E}} = \{\textcolor{purple}{V_1} = \textcolor{purple}{s_0}\}\). The query variable is \(\mathbf{\textcolor{purple}{Q}} = \{\textcolor{purple}{V_3}\}\). The hidden variables to eliminate are \(\mathbf{\textcolor{purple}{Z}} = \{\textcolor{purple}{V_0}, \textcolor{purple}{V_2}\}\).</p>

<p>We start with the initial factors (the CPDs):</p>

\[\begin{aligned}
\phi_0(\textcolor{purple}{V_0}) &amp;= P(\textcolor{purple}{V_0}) \\
\phi_1(\textcolor{purple}{V_1}, \textcolor{purple}{V_0}) &amp;= P(\textcolor{purple}{V_1} \mid \textcolor{purple}{V_0}) \\
\phi_2(\textcolor{purple}{V_2}, \textcolor{purple}{V_0}) &amp;= P(\textcolor{purple}{V_2} \mid \textcolor{purple}{V_0}) \\
\phi_3(\textcolor{purple}{V_3}, \textcolor{purple}{V_0}, \textcolor{purple}{V_1}) &amp;= P(\textcolor{purple}{V_3} \mid \textcolor{purple}{V_0}, \textcolor{purple}{V_1})
\end{aligned}\]

<p>For the elimination order, we have randomly selected to start with \(\textcolor{purple}{V_2}\) and then \(\textcolor{purple}{V_0}\).</p>

<h4 id="step-1-restrict-factors">Step 1: Restrict factors based on evidence</h4>

<p>Since we observe \(\textcolor{purple}{V_1} = \textcolor{purple}{s_0}\), we restrict any factor containing \(\textcolor{purple}{V_1}\) to this value.</p>

<p>For \(\phi_1(\textcolor{purple}{V_1}, \textcolor{purple}{V_0})\), we fix \(\textcolor{purple}{V_1} = \textcolor{purple}{s_0}\). Since \(\textcolor{purple}{V_1}\) is now a constant, the resulting factor depends only on \(\textcolor{purple}{V_0}\). We call this new factor \(\phi_1'(\textcolor{purple}{V_0})\):</p>

<center>
<table>
  <tr>
    <th colspan="2" style="text-align: center;">$$\phi_1'(\textcolor{purple}{V_0})$$</th>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_0}$$</td>
    <td>0.3110</td>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_1}$$</td>
    <td>0.0704</td>
  </tr>
</table>
</center>

<p>For \(\phi_3(\textcolor{purple}{V_3}, \textcolor{purple}{V_0}, \textcolor{purple}{V_1})\), we similarly select the entries consistent with \(\textcolor{purple}{V_1} = \textcolor{purple}{s_0}\). The new factor depends only on \(\textcolor{purple}{V_3}\) and \(\textcolor{purple}{V_0}\):</p>

<center>
<table>
  <tr>
    <th rowspan="2" style="text-align: center;">$$\phi_3'(\textcolor{purple}{V_3}, \textcolor{purple}{V_0})$$</th>
    <th colspan="2" style="text-align: center;">$$\textcolor{purple}{V_0}$$</th>
  </tr>
  <tr>
    <th style="text-align: center;">$$\textcolor{purple}{s_0}$$</th>
    <th style="text-align: center;">$$\textcolor{purple}{s_1}$$</th>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_0}$$</td>
    <td>0.0607</td>
    <td>0.8890</td>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_1}$$</td>
    <td>0.9393</td>
    <td>0.1110</td>
  </tr>
</table>
</center>

<h4 id="step-2-eliminate-v2">Step 2: Eliminate V2</h4>

<p>The only factor containing \(\textcolor{purple}{V_2}\) is \(\phi_2(\textcolor{purple}{V_2}, \textcolor{purple}{V_0})\). Summing over \(\textcolor{purple}{V_2}\):</p>

\[\phi_4(\textcolor{purple}{V_0}) = \sum_{\textcolor{purple}{V_2}} \phi_2(\textcolor{purple}{V_2}, \textcolor{purple}{V_0}) = \sum_{\textcolor{purple}{V_2}} P(\textcolor{purple}{V_2} \mid \textcolor{purple}{V_0}) = 1\]

<p>Since \(\textcolor{purple}{V_2}\) is a leaf node and not part of the query or evidence, it sums to 1 and effectively disappears (it is a “barren node”).</p>

<h4 id="step-3-eliminate-v0">Step 3: Eliminate V0</h4>

<p>We collect all factors containing \(\textcolor{purple}{V_0}\): \(\phi_0(\textcolor{purple}{V_0})\), \(\phi_1'(\textcolor{purple}{V_0})\), and \(\phi_3'(\textcolor{purple}{V_3}, \textcolor{purple}{V_0})\).
We multiply them to form \(\phi_{prod}(\textcolor{purple}{V_3}, \textcolor{purple}{V_0})\):</p>

<p>For \(\textcolor{purple}{V_0} = \textcolor{purple}{s_{0}}\):</p>

\[\begin{aligned}
\phi_{0}(\textcolor{purple}{V_0} = \textcolor{purple}{s_0}) \cdot \phi_{1}'(\textcolor{purple}{V_0} = \textcolor{purple}{s_0}) &amp;= 0.5072 \cdot 0.3110 = 0.1577 \\[0.5em]
\phi_{prod}(\textcolor{purple}{V_3} = \textcolor{purple}{s_0}, \textcolor{purple}{V_0} = \textcolor{purple}{s_0}) &amp;= 0.1577 \cdot \phi_{3}'(\textcolor{purple}{V_3} = \textcolor{purple}{s_0}, \textcolor{purple}{V_0} = \textcolor{purple}{s_0}) \\[0.5em] &amp;= 0.1577 \cdot 0.0607 = 0.0096 \\
\phi_{prod}(\textcolor{purple}{V_3} = \textcolor{purple}{s_1}, \textcolor{purple}{V_0} = \textcolor{purple}{s_0}) &amp;= 0.1577 \cdot \phi_{3}'(\textcolor{purple}{V_3} = \textcolor{purple}{s_1}, \textcolor{purple}{V_0} = \textcolor{purple}{s_0}) \\[0.5em] &amp;= 0.1577 \cdot 0.9393 = 0.1481
\end{aligned}\]

<p>For \(\textcolor{purple}{V_0} = \textcolor{purple}{s_{1}}\):</p>

\[\begin{aligned}
\phi_{0}(\textcolor{purple}{V_0} = \textcolor{purple}{s_1}) \cdot \phi_{1}'(\textcolor{purple}{V_0} = \textcolor{purple}{s_1}) &amp;= 0.4928 \cdot 0.0704 = 0.0347 \\[0.5em]
\phi_{prod}(\textcolor{purple}{V_3} = \textcolor{purple}{s_0}, \textcolor{purple}{V_0} = \textcolor{purple}{s_1}) &amp;= 0.0347 \cdot \phi_{3}'(\textcolor{purple}{V_3} = \textcolor{purple}{s_0}, \textcolor{purple}{V_0} = \textcolor{purple}{s_1}) \\[0.5em] &amp;= 0.0347 \cdot 0.8890 = 0.0308 \\
\phi_{prod}(\textcolor{purple}{V_3} = \textcolor{purple}{s_1}, \textcolor{purple}{V_0} = \textcolor{purple}{s_1}) &amp;= 0.0347 \cdot \phi_{3}'(\textcolor{purple}{V_3} = \textcolor{purple}{s_1}, \textcolor{purple}{V_0} = \textcolor{purple}{s_1}) \\[0.5em] &amp;= 0.0347 \cdot 0.1110 = 0.0039
\end{aligned}\]

<center>
<table>
  <tr>
    <th rowspan="2" style="text-align: center;">$$\phi_{prod}(\textcolor{purple}{V_3}, \textcolor{purple}{V_0})$$</th>
    <th colspan="2" style="text-align: center;">$$\textcolor{purple}{V_0}$$</th>
  </tr>
  <tr>
    <th style="text-align: center;">$$\textcolor{purple}{s_0}$$</th>
    <th style="text-align: center;">$$\textcolor{purple}{s_1}$$</th>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_0}$$</td>
    <td>0.0096</td>
    <td>0.0308</td>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_1}$$</td>
    <td>0.1481</td>
    <td>0.0039</td>
  </tr>
</table>
</center>

<p>Then we sum out \(\textcolor{purple}{V_0}\) to get \(\phi_5(\textcolor{purple}{V_3})\):</p>

\[\phi_5(\textcolor{purple}{V_3}) = \sum_{\textcolor{purple}{V_0}} \phi_{prod}(\textcolor{purple}{V_3}, \textcolor{purple}{V_0})\]

\[\begin{aligned}
\phi_5(\textcolor{purple}{V_3} = \textcolor{purple}{s_0}) &amp;= \phi_{prod}(\textcolor{purple}{V_3} = \textcolor{purple}{s_0}, \textcolor{purple}{V_0} = \textcolor{purple}{s_0}) + \phi_{prod}(\textcolor{purple}{V_3} = \textcolor{purple}{s_0}, \textcolor{purple}{V_0} = \textcolor{purple}{s_1}) \\
&amp;= 0.0096 + 0.0308 = 0.0404 \\[1em]
\phi_5(\textcolor{purple}{V_3} = \textcolor{purple}{s_1}) &amp;= \phi_{prod}(\textcolor{purple}{V_3} = \textcolor{purple}{s_1}, \textcolor{purple}{V_0} = \textcolor{purple}{s_0}) + \phi_{prod}(\textcolor{purple}{V_3} = \textcolor{purple}{s_1}, \textcolor{purple}{V_0} = \textcolor{purple}{s_1}) \\
&amp;= 0.1481 + 0.0039 = 0.1520
\end{aligned}\]

<center>
<table>
  <tr>
    <th colspan="2" style="text-align: center;">$$\phi_5(\textcolor{purple}{V_3})$$</th>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_0}$$</td>
    <td>0.0404</td>
  </tr>
  <tr>
    <td>$$\textcolor{purple}{s_1}$$</td>
    <td>0.1520</td>
  </tr>
</table>
</center>

<h4 id="step-4-normalize">Step 4: Normalize</h4>

<p>Finally, we normalize \(\phi_5(\textcolor{purple}{V_3})\) to get the probability distribution.</p>

\[Z = 0.0404 + 0.1520 = 0.1924\]

\[\begin{aligned}
P(\textcolor{purple}{V_3} = \textcolor{purple}{s_0} \mid \textcolor{purple}{V_1} = \textcolor{purple}{s_0}) &amp;= \frac{0.0404}{0.1924} = 0.2100 \\
P(\textcolor{purple}{V_3} = \textcolor{purple}{s_1} \mid \textcolor{purple}{V_1} = \textcolor{purple}{s_0}) &amp;= \frac{0.1520}{0.1924} = 0.7900
\end{aligned}\]

<h2 id="how-llms-do-it">How LLMs do it</h2>

<p>Now that we have solved the problem manually, let’s see how LLMs approach the task. To evaluate this comprehensively, I have prepared two complementary experiments:</p>

<ol>
  <li>
    <p><strong>Raw reasoning</strong>: Provide the network definition with CPDs in the prompt and ask for the answer without any tools. This tests whether LLMs can apply inference algorithms (Variable Elimination, Junction Tree, brute force, etc.) and perform arithmetic operations correctly. It’s essentially a test of what I did above but without a calculator (which I used).</p>
  </li>
  <li>
    <p><strong>Code generation</strong>: Provide the network definition with CPDs in the prompt and ask LLMs to write Python code to solve the problem. Given that current reasoning models have demonstrated excellent coding capabilities, this tests their ability to translate the problem into code and solve it. This is a “one-shot” test. I want to see what kind of code they would generate and how many output tokens are required compared to the raw reasoning approach.</p>
  </li>
</ol>

<h3 id="experimental-setup">Experimental setup</h3>

<p>I have selected seven state-of-the-art language models, including both open-source and closed-source reasoning models. The experiments have been conducted using <a href="https://openrouter.ai/">OpenRouter</a>.</p>

<p><strong>Models evaluated:</strong></p>

<table>
<thead>
<tr>
<th>Model</th>
<th>Context Length</th>
<th>Max Output Tokens</th>
<th>Cost Input ($/1M tokens)</th>
<th>Cost Output ($/1M tokens)</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="5" style="background-color: #f0f0f0; font-weight: bold;">Open-source</td>
</tr>
<tr>
<td>DeepSeek-R1-0528</td>
<td>163,840</td>
<td>163,800</td>
<td>0.40</td>
<td>1.75</td>
</tr>
<tr>
<td>Kimi-K2-thinking</td>
<td>262,144</td>
<td>262,000</td>
<td>0.40</td>
<td>1.75</td>
</tr>
<tr>
<td>Qwen3-235B-A22B-thinking-2507</td>
<td>262,144</td>
<td>262,000</td>
<td>0.30</td>
<td>1.20</td>
</tr>
<tr>
<td>GLM-4.7</td>
<td>202,752</td>
<td>131,800</td>
<td>0.40</td>
<td>1.50</td>
</tr>
<tr>
<td colspan="5" style="background-color: #f0f0f0; font-weight: bold;">Closed-source</td>
</tr>
<tr>
<td>Claude Sonnet-4.5</td>
<td>1,000,000</td>
<td>64,000</td>
<td>3.00</td>
<td>15.00</td>
</tr>
<tr>
<td>Gemini-3-Pro</td>
<td>1,048,576</td>
<td>65,500</td>
<td>2.00</td>
<td>12.00</td>
</tr>
<tr>
<td>GPT-5.2-high</td>
<td>400,000</td>
<td>128,000</td>
<td>1.75</td>
<td>14.00</td>
</tr>
</tbody>
</table>

<p>The complete experimental code is available in the <a href="https://github.com/ferjorosa/ferjorosa.github.io/tree/main/code/llms-probabilistic-reasoning"><code class="language-plaintext highlighter-rouge">code/llms-probabilistic-reasoning/</code></a> directory. Running the experiments requires only a few OpenRouter credits, and I’ve shared all results as JSON files for analysis under the <a href="https://github.com/ferjorosa/ferjorosa.github.io/tree/main/code/llms-probabilistic-reasoning/results"><code class="language-plaintext highlighter-rouge">results</code></a> sub-directory.</p>

<p>Each experiment uses a different prompt, both defined in the <a href="https://github.com/ferjorosa/ferjorosa.github.io/tree/main/code/llms-probabilistic-reasoning/prompts.yaml"><code class="language-plaintext highlighter-rouge">prompts.yaml</code></a> file. The raw reasoning template is <code>prompt_base</code> and the code generation template is <code>prompt_base_code</code>.</p>

<h3 id="raw-reasoning-results">Raw reasoning results</h3>

<table>
<thead>
<tr>
<th>Model</th>
<th>Response</th>
<th>Input tokens</th>
<th>Completion tokens</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ground truth</td>
<td>0.7900</td>
<td>1018 <sup>(1)</sup></td>
<td>3275 <sup>(1)</sup></td>
</tr>
<tr>
<td colspan="4" style="background-color: #f0f0f0; font-weight: bold;">Open-source</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/raw_reasoning/deepseek_deepseek-r1-0528_20251226_164351.md">DeepSeek-R1-0528</a></td>
<td>0.789967</td>
<td>1031</td>
<td>14786</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/raw_reasoning/moonshotai_kimi-k2-thinking_20251213_171713.md">Kimi-K2-thinking</a></td>
<td>0.78996796</td>
<td>987</td>
<td>39224</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/raw_reasoning/qwen_qwen3-235b-a22b-thinking-2507_20251226_172229.md">Qwen3-235B-A22B-thinking-2507</a></td>
<td>0.7900</td>
<td>1079</td>
<td>7623</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/raw_reasoning/z-ai_glm-4.7_20251226_170612.md">GLM-4.7</a></td>
<td>0.78997</td>
<td>1044</td>
<td>12432</td>
</tr>
<tr>
<td colspan="4" style="background-color: #f0f0f0; font-weight: bold;">Closed-source</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/raw_reasoning/anthropic_claude-sonnet-4.5_20251226_173811.md">Claude Sonnet-4.5</a></td>
<td>0.7899686793</td>
<td>1188</td>
<td>18721</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/raw_reasoning/google_gemini-3-pro-preview_20251226_175749.md">Gemini-3-Pro</a></td>
<td>0.7900</td>
<td>1155</td>
<td>7576</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/raw_reasoning/openai_gpt-5.2_20251226_180834.md">GPT-5.2-high</a></td>
<td>0.789967957981</td>
<td>1029</td>
<td>10004</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4" style="font-size: 0.9em; font-style: italic; padding-top: 10px;">
<sup>(1)</sup> <a href="https://platform.openai.com/tokenizer">Ground truth token values were approximated using OpenAI's GPT-4o tokenizer.</a>
</td>
</tr>
</tfoot>
</table>

<p>All models successfully computed the correct probability. However, to be honest, that was not especially surprising. Reasoning models have shown great performance <a href="https://livebench.ai/#/?Mathematics=as&amp;sort=Mathematics+Average">on math benchmarks</a> in recent years, and the example query is not especially complicated given the size of the network. What is particularly interesting to me is <strong>how each model approached the task</strong>.</p>

<p>To analyze their approaches, I reviewed the traces and used Gemini-3-Pro to compare them against the VE algorithm I manually applied above. Note that for Gemini-3 and GPT-5.2 we only have access to reasoning “summaries” rather than the full thinking trace, so the analysis of these models is not as accurate.</p>

<p>As a summary, <strong>none of the models used the VE algorithm.</strong> Instead, all models except GPT-5.2 essentially wrote out the formula for the full joint distribution and then summed it up.</p>

<p>DeepSeek-R1, Kimi-K2, Sonnet-4.5, and Gemini-3 wrote the full joint distribution using the chain rule and brute-forced the summation. This forced them to re-calculate the same sub-problems multiple times (e.g., computing the probability of the parents for both the numerator and denominator separately). This redundancy is a major driver of token bloat.</p>

<p>GLM-4.7 and Qwen-3 also summed over the full joint distribution, but they realized that the numerator and denominator shared common terms, like \(P(\textcolor{purple}{V_0})P(\textcolor{purple}{V_1} \mid \textcolor{purple}{V_0})\), so they explicitly calculated these “blocks” once and reused them, naming them for example <code class="language-plaintext highlighter-rouge">term1</code> and <code class="language-plaintext highlighter-rouge">term2</code>. However, while they avoid re-multiplying the same numbers, they are still committed to a formula that grows <strong>exponentially with the network size</strong>.</p>

<p>Finally, GPT-5.2 is the only one that truly changed the structure of the problem. It seems to me that it has applied <a href="https://www.doc.ic.ac.uk/~dfg/ProbabilisticInference/IDAPILecture09.pdf">Cutset conditioning</a>. The idea is to find the minimal set of nodes whose instantiation will make the remainder of the network “singly connected” (i.e., a polytree). Once we have a tree, inference is easy and efficient. In this case, GPT-5.2 correctly identified that \(\textcolor{purple}{V_0}\) acts as a cutset (of size 1). Instantiating \(V_0\) breaks the connection between the “left” path (\(\textcolor{purple}{V_1}\)) and “right” path (\(\textcolor{purple}{V_2}\)). After it solved a small problem (finding \(\textcolor{purple}{V_0}\)’s posterior), it then used that answer to solve the next small problem (finding \(\textcolor{purple}{V_3}\)). To be honest, I was impressed by this. This is what I was hoping to see: <strong>LLMs using their reasoning capabilities to find “heuristics” to simplify the inference problem</strong>. 
<br /></p>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
<b>The "arithmetic anxiety" phenomenon</b>
<br /><br />
It seems the choice of strategy had a direct impact on the model's "arithmetic confidence". Basically, some of the models, usually those that approached the problem from a "brute-force" perspective, suffered from severe verification loops. 
<br /><br />
For instance, DeepSeek-R1 recalculated simple products dozens of times using different formats (decimals, fractions, scientific notation) to "be sure". Sonnet-4.5 constantly interrupted itself to double-check divisions, catching and correcting its own precision errors. Kimi-K2 was the most extreme case, performing manual long division to <b>over 100 decimal places</b> for a problem that only needed 4. Finally, Gemini-3 seems to have done some verification steps, but given the lack of full reasoning trace, we cannot be sure. It is probably not very anxious given the amount of tokens it generated.
<br /><br />
<b>Note:</b> In the prompt I instruct to "Use at least 4 decimal places for precision", so I am sure that also influenced, but it seems more prominent in those that had to do more arithmetic operations.
</div>
<div style="height: 1.1em;"></div>

<h3 id="code-generation-results">Code generation results</h3>

<table>
<thead>
<tr>
<th>Model</th>
<th>Response</th>
<th>Input tokens</th>
<th>Completion tokens</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ground truth</td>
<td>0.7900</td>
<td>1039 <sup>(1)</sup></td>
<td>636 <sup>(1)</sup></td>
</tr>
<tr>
<td colspan="4" style="background-color: #f0f0f0; font-weight: bold;">Open-source</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/code_generation/deepseek_deepseek-r1-0528_20251227_193907.md">DeepSeek-R1-0528</a></td>
<td>0.789968</td>
<td>1048</td>
<td>2793</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/code_generation/moonshotai_kimi-k2-thinking_20251227_194650.md">Kimi-K2-thinking</a></td>
<td>0.789967957981</td>
<td>963</td>
<td>27339</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/code_generation/qwen_qwen3-235b-a22b-thinking-2507_20251227_200602.md">Qwen3-235B-A22B-thinking-2507</a></td>
<td>0.7900</td>
<td>1097</td>
<td>13353</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/code_generation/z-ai_glm-4.7_20251227_195156.md">GLM-4.7</a></td>
<td>0.7899679579812788</td>
<td>1064</td>
<td>5663</td>
</tr>
<tr>
<td colspan="4" style="background-color: #f0f0f0; font-weight: bold;">Closed-source</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/code_generation/anthropic_claude-sonnet-4.5_20251227_193625.md">Claude Sonnet-4.5</a></td>
<td>0.7899679579812788</td>
<td>1205</td>
<td>19864</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/code_generation/google_gemini-3-pro-preview_20251227_163622.md">Gemini-3-Pro</a></td>
<td>0.7899679579812788</td>
<td>1167</td>
<td>5885</td>
</tr>
<tr>
<td><a href="https://github.com/ferjorosa/ferjorosa.github.io/blob/main/code/llms-probabilistic-reasoning/results_md/code_generation/openai_gpt-5.2_20251227_193226.md">GPT-5.2-high</a></td>
<td>0.7899679580</td>
<td>1049</td>
<td>11799</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4" style="font-size: 0.9em; font-style: italic; padding-top: 10px;">
<sup>(1)</sup> <a href="https://platform.openai.com/tokenizer">Ground truth token values were approximated using OpenAI's GPT-4o tokenizer.</a>
</td>
</tr>
</tfoot>
</table>

<p>All models achieved the correct numerical answer. However, despite the prompt explicitly mentioning the possibility to write code for <code class="language-plaintext highlighter-rouge">pgmpy</code> and <code class="language-plaintext highlighter-rouge">pyAgrum</code>, <strong>none of the models used these established BN libraries</strong>. Instead, they all followed the same pattern: they derived the <strong>chain rule</strong> formula and implemented it using vanilla Python.</p>

<p>Looking at the traces, most models actually computed the answer (or at least verified their approach) manually before writing any code. Kimi-K2 and GPT-5.2 were the most extreme examples. They performed the full calculation by hand, including manual long division to many decimal places. Their code then used high-precision arithmetic (<code class="language-plaintext highlighter-rouge">fractions.Fraction</code> for Kimi-K2, <code class="language-plaintext highlighter-rouge">decimal.Decimal</code> with 50-digit precision for GPT-5.2), essentially double-checking their mental work rather than delegating the computation. On the other side of the spectrum, DeepSeek-R1 also computed the numerator and denominator but not the final result, which is why it was far more token efficient.</p>

<p>From my personal tests, I know these models are aware of <code class="language-plaintext highlighter-rouge">pgmpy</code> and <code class="language-plaintext highlighter-rouge">pyAgrum</code> and can write code using them. However, they seem to prefer direct calculations. Perhaps they find them more explainable or maybe they didn’t see it necessary for a small network like this one.</p>

<p>As an example, here is the resulting Python code from Sonnet-4.5 (all of them are quite similar):</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Calculate P(V3=s1 | V1=s0)
</span>
<span class="c1"># P(V0)
</span><span class="n">P_V0_s0</span> <span class="o">=</span> <span class="mf">0.5072</span>
<span class="n">P_V0_s1</span> <span class="o">=</span> <span class="mf">0.4928</span>

<span class="c1"># P(V1 | V0)
</span><span class="n">P_V1_s0_given_V0_s0</span> <span class="o">=</span> <span class="mf">0.3110</span>
<span class="n">P_V1_s0_given_V0_s1</span> <span class="o">=</span> <span class="mf">0.0704</span>

<span class="c1"># P(V3 | V0, V1)
</span><span class="n">P_V3_s1_given_V0_s0_V1_s0</span> <span class="o">=</span> <span class="mf">0.9393</span>
<span class="n">P_V3_s1_given_V0_s1_V1_s0</span> <span class="o">=</span> <span class="mf">0.1110</span>

<span class="c1"># Calculate P(V3=s1, V1=s0) using law of total probability
</span><span class="n">P_V3_s1_V1_s0</span> <span class="o">=</span> <span class="p">(</span><span class="n">P_V3_s1_given_V0_s0_V1_s0</span> <span class="o">*</span> <span class="n">P_V1_s0_given_V0_s0</span> <span class="o">*</span> <span class="n">P_V0_s0</span> <span class="o">+</span> 
                 <span class="n">P_V3_s1_given_V0_s1_V1_s0</span> <span class="o">*</span> <span class="n">P_V1_s0_given_V0_s1</span> <span class="o">*</span> <span class="n">P_V0_s1</span><span class="p">)</span>

<span class="c1"># Calculate P(V1=s0)
</span><span class="n">P_V1_s0</span> <span class="o">=</span> <span class="n">P_V1_s0_given_V0_s0</span> <span class="o">*</span> <span class="n">P_V0_s0</span> <span class="o">+</span> <span class="n">P_V1_s0_given_V0_s1</span> <span class="o">*</span> <span class="n">P_V0_s1</span>

<span class="c1"># Calculate P(V3=s1 | V1=s0)
</span><span class="n">result</span> <span class="o">=</span> <span class="n">P_V3_s1_V1_s0</span> <span class="o">/</span> <span class="n">P_V1_s0</span>

<span class="k">print</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
</code></pre></div></div>

<p>For comparison’s sake, here’s how the problem could be solved using <code class="language-plaintext highlighter-rouge">pgmpy</code>. This is what I have considered ground truth for this experiment:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pgmpy.inference</span> <span class="kn">import</span> <span class="n">VariableElimination</span>
<span class="kn">from</span> <span class="nn">pgmpy.models</span> <span class="kn">import</span> <span class="n">DiscreteBayesianNetwork</span>
<span class="kn">from</span> <span class="nn">pgmpy.factors.discrete</span> <span class="kn">import</span> <span class="n">TabularCPD</span>

<span class="c1"># Create the Bayesian network structure
</span><span class="n">bn</span> <span class="o">=</span> <span class="n">DiscreteBayesianNetwork</span><span class="p">([(</span><span class="s">'V0'</span><span class="p">,</span> <span class="s">'V1'</span><span class="p">),</span> <span class="p">(</span><span class="s">'V0'</span><span class="p">,</span> <span class="s">'V2'</span><span class="p">),</span> <span class="p">(</span><span class="s">'V0'</span><span class="p">,</span> <span class="s">'V3'</span><span class="p">),</span> <span class="p">(</span><span class="s">'V1'</span><span class="p">,</span> <span class="s">'V3'</span><span class="p">)])</span>

<span class="c1"># Define CPDs based on the provided tables
</span>
<span class="c1"># CPD for V0 (root node)
</span><span class="n">cpd_v0</span> <span class="o">=</span> <span class="n">TabularCPD</span><span class="p">(</span>
    <span class="n">variable</span><span class="o">=</span><span class="s">'V0'</span><span class="p">,</span>
    <span class="n">variable_card</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
    <span class="n">values</span><span class="o">=</span><span class="p">[[</span><span class="mf">0.5072</span><span class="p">],</span> <span class="p">[</span><span class="mf">0.4928</span><span class="p">]],</span>
    <span class="n">state_names</span><span class="o">=</span><span class="p">{</span><span class="s">'V0'</span><span class="p">:</span> <span class="p">[</span><span class="s">'s0'</span><span class="p">,</span> <span class="s">'s1'</span><span class="p">]}</span>
<span class="p">)</span>

<span class="c1"># CPD for V1 (depends on V0)
</span><span class="n">cpd_v1</span> <span class="o">=</span> <span class="n">TabularCPD</span><span class="p">(</span>
    <span class="n">variable</span><span class="o">=</span><span class="s">'V1'</span><span class="p">,</span>
    <span class="n">variable_card</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
    <span class="n">values</span><span class="o">=</span><span class="p">[[</span><span class="mf">0.3110</span><span class="p">,</span> <span class="mf">0.0704</span><span class="p">],</span>
            <span class="p">[</span><span class="mf">0.6890</span><span class="p">,</span> <span class="mf">0.9296</span><span class="p">]],</span>
    <span class="n">evidence</span><span class="o">=</span><span class="p">[</span><span class="s">'V0'</span><span class="p">],</span>
    <span class="n">evidence_card</span><span class="o">=</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span>
    <span class="n">state_names</span><span class="o">=</span><span class="p">{</span><span class="s">'V1'</span><span class="p">:</span> <span class="p">[</span><span class="s">'s0'</span><span class="p">,</span> <span class="s">'s1'</span><span class="p">],</span> <span class="s">'V0'</span><span class="p">:</span> <span class="p">[</span><span class="s">'s0'</span><span class="p">,</span> <span class="s">'s1'</span><span class="p">]}</span>
<span class="p">)</span>

<span class="c1"># CPD for V2 (depends on V0)
</span><span class="n">cpd_v2</span> <span class="o">=</span> <span class="n">TabularCPD</span><span class="p">(</span>
    <span class="n">variable</span><span class="o">=</span><span class="s">'V2'</span><span class="p">,</span>
    <span class="n">variable_card</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
    <span class="n">values</span><span class="o">=</span><span class="p">[[</span><span class="mf">0.8950</span><span class="p">,</span> <span class="mf">0.0562</span><span class="p">],</span>
            <span class="p">[</span><span class="mf">0.1050</span><span class="p">,</span> <span class="mf">0.9438</span><span class="p">]],</span>
    <span class="n">evidence</span><span class="o">=</span><span class="p">[</span><span class="s">'V0'</span><span class="p">],</span>
    <span class="n">evidence_card</span><span class="o">=</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span>
    <span class="n">state_names</span><span class="o">=</span><span class="p">{</span><span class="s">'V2'</span><span class="p">:</span> <span class="p">[</span><span class="s">'s0'</span><span class="p">,</span> <span class="s">'s1'</span><span class="p">],</span> <span class="s">'V0'</span><span class="p">:</span> <span class="p">[</span><span class="s">'s0'</span><span class="p">,</span> <span class="s">'s1'</span><span class="p">]}</span>
<span class="p">)</span>

<span class="c1"># CPD for V3 (depends on V0 and V1)
</span><span class="n">cpd_v3</span> <span class="o">=</span> <span class="n">TabularCPD</span><span class="p">(</span>
    <span class="n">variable</span><span class="o">=</span><span class="s">'V3'</span><span class="p">,</span>
    <span class="n">variable_card</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
    <span class="n">values</span><span class="o">=</span><span class="p">[[</span><span class="mf">0.0607</span><span class="p">,</span> <span class="mf">0.8173</span><span class="p">,</span> <span class="mf">0.8890</span><span class="p">,</span> <span class="mf">0.2251</span><span class="p">],</span>
            <span class="p">[</span><span class="mf">0.9393</span><span class="p">,</span> <span class="mf">0.1827</span><span class="p">,</span> <span class="mf">0.1110</span><span class="p">,</span> <span class="mf">0.7749</span><span class="p">]],</span>
    <span class="n">evidence</span><span class="o">=</span><span class="p">[</span><span class="s">'V0'</span><span class="p">,</span> <span class="s">'V1'</span><span class="p">],</span>
    <span class="n">evidence_card</span><span class="o">=</span><span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span>
    <span class="n">state_names</span><span class="o">=</span><span class="p">{</span><span class="s">'V3'</span><span class="p">:</span> <span class="p">[</span><span class="s">'s0'</span><span class="p">,</span> <span class="s">'s1'</span><span class="p">],</span> <span class="s">'V0'</span><span class="p">:</span> <span class="p">[</span><span class="s">'s0'</span><span class="p">,</span> <span class="s">'s1'</span><span class="p">],</span> <span class="s">'V1'</span><span class="p">:</span> <span class="p">[</span><span class="s">'s0'</span><span class="p">,</span> <span class="s">'s1'</span><span class="p">]}</span>
<span class="p">)</span>

<span class="c1"># Add CPDs to the bn
</span><span class="n">bn</span><span class="p">.</span><span class="n">add_cpds</span><span class="p">(</span><span class="n">cpd_v0</span><span class="p">,</span> <span class="n">cpd_v1</span><span class="p">,</span> <span class="n">cpd_v2</span><span class="p">,</span> <span class="n">cpd_v3</span><span class="p">)</span>

<span class="c1"># Validate the bn
</span><span class="k">assert</span> <span class="n">bn</span><span class="p">.</span><span class="n">check_model</span><span class="p">()</span>

<span class="c1"># Create inference object
</span><span class="n">inference</span> <span class="o">=</span> <span class="n">VariableElimination</span><span class="p">(</span><span class="n">bn</span><span class="p">)</span>

<span class="c1"># Compute P(V3=s1 | V1=s0)
</span><span class="n">query_result</span> <span class="o">=</span> <span class="n">inference</span><span class="p">.</span><span class="n">query</span><span class="p">(</span><span class="n">variables</span><span class="o">=</span><span class="p">[</span><span class="s">'V3'</span><span class="p">],</span> <span class="n">evidence</span><span class="o">=</span><span class="p">{</span><span class="s">'V1'</span><span class="p">:</span> <span class="s">'s0'</span><span class="p">})</span>
<span class="n">prob_v3_s1_given_v1_s0</span> <span class="o">=</span> <span class="n">query_result</span><span class="p">.</span><span class="n">values</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>  <span class="c1"># Index 1 corresponds to V3=s1
</span>
<span class="k">print</span><span class="p">(</span><span class="n">prob_v3_s1_given_v1_s0</span><span class="p">)</span>
</code></pre></div></div>

<p>Writing code using the chain rule for a small network is not “bad” per se, but it may suggest that these models are not accustomed to using BN libraries. This could be an issue for more complex queries, where translating the problem manually becomes error-prone or even infeasible.</p>

<p>A more significant observation is that every model chose to solve the inference problem manually before writing a single line of code. This “double-work”, combined with the verbose chain-rule derivation, leads to token bloat. Since reasoning LLMs have limited context windows and generation speeds (often 50-100 tokens/s), reducing this manual verification would make the process far more efficient. For instance, some responses took over 10-15 minutes to complete purely due to this verbosity.</p>

<p>Now, I don’t want to be all “doom and gloom”. First, this is based on a single example, and <strong>more experiments are needed</strong>. Second, I think these results are very interesting and hint at notable opportunities for optimization (e.g., <strong>training LLMs to use these BN libraries more often</strong>), especially as we move from pure LLMs to agents with iterative reasoning processes and tools.</p>

<h2 id="conclusion">Conclusion</h2>

<p>The key takeaway from this exploration is that <strong>LLMs can solve probabilistic inference problems, but they currently do so inefficiently</strong>. Rather than applying BN algorithms like VE, they seem to prefer to write the chain rule formula and brute-force the arithmetic. This works for small networks but does not scale.</p>

<p><strong>Limitations.</strong> This was a small-scale exploration with a single query on a 4-node network. A systematic evaluation would require varying network sizes, query complexities, and prompting strategies. I also did not test function calling, which would enable a more agentic approach.</p>

<p><strong>Related work.</strong> While I have not found many papers on the topic, two recent papers are relevant: <a href="https://arxiv.org/abs/2406.12830">Paruchuri et al. (2024)</a> evaluated LLMs on probabilistic reasoning over univariate distributions. <a href="https://arxiv.org/abs/2402.09614">Nafar et al. (2025)</a> is closer to my experiments, testing how LLMs translate text-based probabilistic queries into symbolic representations.</p>

<p><strong>Looking ahead.</strong> More experiments are needed: testing different network structures, varying sizes, and exploring alternative prompting strategies. I would also like to evaluate tool-augmented approaches via function calling, which could reveal whether LLMs perform better when they can delegate computation rather than doing it “in their heads.”</p>

<p>More broadly, understanding how LLMs reason “under the hood” about structured mathematical problems like probabilistic inference is valuable in itself. It helps us identify where current architectures struggle and what kinds of reasoning they handle well. This connects to a fascinating discussion on the <a href="https://www.youtube.com/@MachineLearningStreetTalk">Machine Learning Street Talk</a> channel that I watched the other day, where researchers explore why LLMs still fail at arithmetic that a second-grader could do, and whether mathematical frameworks like Category Theory could help us understand these limitations more rigorously. It is a bit dense, but I recommend watching it if you are interested in the topic.</p>

<center>
<iframe width="560" height="315" src="https://www.youtube.com/embed/AWqvBdqCAAE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe>
</center>

<h2 id="references">References</h2>

<ol>
  <li>Rodriguez, F. (2025, July 4). <a href="https://ferjorosa.github.io/blog/2025/07/04/decision-theory-II.html"><u>Introduction to decision theory: Part II</u></a>.
<br /><br /></li>
  <li>Rodriguez, F. (2025, August 7). <a href="https://ferjorosa.github.io/blog/2025/08/07/decision-theory-III.html"><u>Introduction to decision theory: Part III</u></a>.
<br /><br /></li>
  <li>Koller, D., &amp; Friedman, N. (2009). <a href="http://mcb111.org/w06/KollerFriedman.pdf"><u>Probabilistic Graphical Models: Principles and Techniques</u></a>. MIT Press.
<br /><br /></li>
  <li>Cutset conditioning lecture notes from Imperial College London. <a href="https://www.doc.ic.ac.uk/~dfg/ProbabilisticInference/IDAPILecture09.pdf"><u>PDF link</u></a>.
<br /><br /></li>
  <li>Nafar, A., Venable, K. B., &amp; Kordjamshidi, P. (2025). <a href="https://arxiv.org/abs/2402.09614"><u>Reasoning over uncertain text by generative large language models</u></a>. In Proceedings of the AAAI Conference on Artificial Intelligence (Vol. 39, No. 23, pp. 24911-24920).
<br /><br /></li>
  <li>Paruchuri, A., Garrison, J., Liao, S., et al. (2024). <a href="https://arxiv.org/abs/2406.12830"><u>What are the odds? Language models are capable of probabilistic reasoning</u></a>. In Proceedings of the 2024 Conference on Empirical Methods in Natural Language Processing (pp. 11712-11733).
<br /><br /></li>
  <li>pgmpy documentation: <a href="https://pgmpy.org/"><u>https://pgmpy.org/</u></a>.</li>
</ol>]]></content><author><name>Fernando Rodriguez</name></author><category term="blog" /><category term="Probabilistic Reasoning" /><summary type="html"><![CDATA[Exploring how frontier LLMs approach probabilistic inference on Bayesian networks, comparing their reasoning strategies against the traditional Variable Elimination algorithm.]]></summary></entry><entry><title type="html">Some reflections on AI and Creativity</title><link href="https://ferjorosa.github.io/blog/2025/12/11/reflections-ai-creativity.html" rel="alternate" type="text/html" title="Some reflections on AI and Creativity" /><published>2025-12-11T00:00:00+00:00</published><updated>2025-12-11T00:00:00+00:00</updated><id>https://ferjorosa.github.io/blog/2025/12/11/reflections-ai-creativity</id><content type="html" xml:base="https://ferjorosa.github.io/blog/2025/12/11/reflections-ai-creativity.html"><![CDATA[<p>I have the weird habit of sometimes opening Linkedin and looking at my own profile. I think it’s probably some subconscious thing, similar to what motivates us to look at ourselves in the mirror, searching for imperfections, or just trying to keep an updated view of ourselves. Maybe it’s because I look at my phone too much. I don’t know.</p>

<p>Anyway, in one of those sporadic moments (this Sunday morning, to be precise), I glanced at my own profile text and remembered a conversation I had with my girlfriend this week about what a CV profile should say. Out of curiosity (and habit), I couldn’t help thinking to myself: What would Karpathy do? What does Karpathy have in his Linkedin profile? So I typed “karpathy” in the search bar, but when I was about to click on his profile, I misclicked and searched the term instead, allowing Linkedin to show me the “closest” thing to “karpathy” on the platform.</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-12-11-reflections-ai-creativity/karpathy_photo.jpg" alt="Andrej Karpathy" width="220" />
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 1.</b> What would Andrej Karpathy do?</i>
    </td>
  </tr>
</table>
</center>

<p>To my honest surprise, the top result was not Andrej Karpathy’s profile (could it be because he doesn’t post on Linkedin?). Instead, it was a post from an AI influencer.</p>

<p>Following my curiosity, I opened his profile to see what made his post the closest thing to “karpathy” (I am always on an almost “obsessive” mission to find interesting people and papers in the AI space, so I had to check). Inside, I saw he had 1.5M followers which could explain the recommendation. That shifted my curiosity: I decided to investigate how a “top voice” in the AI space actually writes, especially now that I’m dedicating some time to writing myself.</p>

<p><a href="https://www.linkedin.com/posts/pascalbornet_awsambassador-awsreinvent2025-sportsanalytics-activity-7405245122554077184-BuJJ?utm_source=share&amp;utm_medium=member_desktop&amp;rcm=ACoAABa5Rg4B28_o_EZLw2KuMtrdpQKRKhPx0M4">Reading one of the posts</a>, I couldn’t help but notice common patterns of AI writing:</p>

<ul>
  <li>Using a question in the middle of the post to catch the reader’s attention</li>
  <li>Phrases like “The more powerful the blablabla, the more human the blublublu…”</li>
  <li>Emojis or uncommon UTF-8 characters</li>
</ul>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-12-11-reflections-ai-creativity/karpathy_linkedin.jpeg" alt="Closest post to Karpathy according to Linkedin search" width="300" />
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 2.</b> Closest post to "karpathy" according to Linkedin search</i>
    </td>
  </tr>
</table>
</center>

<p>Now, while my first intuition was that AI had played a role here, I am not a native English speaker, nor am I an expert on the topic. In fact, there is an interesting conversation to be had about <a href="https://youtube.com/shorts/96ppb7x4XdI?si=SFVLPqrj4AwaaumM">how LLMs are influencing the way we speak</a>. For instance, I have noticed myself using terms like “delve” and “showcase” more frequently, terms usually associated with AI writing, even when I am not using an 
LLM (<a href="https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing">Wikipedia has an interesting article about signs of AI writing</a>, if you’re curious).</p>

<p>That said, I don’t believe that using LLMs means everything written or created will be slop. Nor do I think LLMs are “incapable” of creating creative or high-quality content, though there is certainly a discussion to be had about it (<a href="https://statmodeling.stat.columbia.edu/2025/02/25/what-is-interesting-writing-and-can-llms-create-it/">Jessica Hullman has an interesting blog post on the matter</a>).</p>

<p>But I am slightly digressing. Coming back to that Linkedin post, I think it reignited an internal questioning I have been wrestling with all year about creativity and “craft”, especially with current AI advancements. Why do I build software? Why do I paint miniatures? Why spend a Sunday writing this post when an LLM could generate a “passable” version in seconds? To me, it boils down to two things: understanding why I create in the first place, and figuring out how to preserve myself in the resulting creation.</p>

<p>Thinking about all of this made me remember something I built long before LLMs existed: my first webpage, made back in 2006 for the game <a href="https://en.wikipedia.org/wiki/Metroid_Prime_Hunters">Metroid Prime Hunters</a>. A page built using <a href="https://es.wikipedia.org/wiki/Microsoft_FrontPage">Microsoft FrontPage</a> that, if I recall correctly, was hosted by Telecable, my home’s internet provider when I was a kid. I still remember the feeling of joy when I got it to work and shared the webpage with my friends.</p>

<p>Back then, there were no LLMs, not even StackOverflow, so I remember reading through the book and dedicating part of my weekends to learning and building through trial and error. I remember searching for the “coolest” images and GIFs on the internet, <a href="https://www.trymstene.com/dancing-banana-gif-meme">like the legendary “Dancing Banana GIF”</a>: <img src="/assets/2025-12-11-reflections-ai-creativity/banana-dance.gif" alt="Dancing banana GIF" width="25" style="vertical-align: middle;" />.</p>

<p>Unfortunately, I didn’t save a copy of that webpage, but it was something similar to the following:</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-12-11-reflections-ai-creativity/old_homepage_example.png" alt="Old webpage example" width="400" />
    </td>
    <td align="center">
      <img src="/assets/2025-12-11-reflections-ai-creativity/frontpage_portada.png" alt="A copy of Microsoft Frontpage (2002)" width="400" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 3.</b> A similar kind of webpage to the one I created when I was young (left) and my father's copy of Microsoft FrontPage (2002), which I used to build it (right)</i>
    </td>
  </tr>
</table>
</center>

<p>When I think about that webpage, the miniatures I paint, these blog posts, and even the software I write every day in my job, I realize that what motivates me is creating something that is not only cool, but that also endures (even if just a little) and keeps a part of me in it.</p>

<p>This desire for endurance might be why “AI-accelerated” content often bothers me. It gives off a “fast-food” feeling, where things are created with no intention of lasting. It might be code without proper architecture or content designed solely to optimize for engagement algorithms and rise higher in the feed. On this topic, I remembered a conversation between Jeremy Howard and Chris Lattner about <a href="https://www.fast.ai/posts/2025-10-30-build-to-last.html">building software that lasts in an age when “everyone is vibe-coding their way through problems”.</a></p>

<p>So yeah, I think my main reflection here is about how we can use AI as a tool without losing ourselves in the process. I have been using LLMs to review my text and code since Chat-GPT was released in 2022. It is a learning process, but if used correctly, I don’t think using AI makes the result less “mine”.</p>

<p>As an example, here’s a cover letter I sent to Perplexity back in 2023 (I don’t think they’ll mind sharing it, they never replied). At the time, using an LLM for this felt almost novel to me, an experiment at integrating this new technology into my daily life. Reading the letter now, I still recognize my voice in it, even if I used an LLM to co-write it.</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-12-11-reflections-ai-creativity/cover_letter_2023_perplexity.png" alt="Cover letter for Perplexity (2023)" width="700" />
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 4.</b> Cover letter I wrote back in 2023 for an application to Perplexity AI</i>
    </td>
  </tr>
</table>
</center>

<p>One last analogy (I promise). I think current LLMs present a problem similar to the Ring of Gyges (<a href="https://www.youtube.com/watch?v=TfVmW6sNux8">here is a nice video from TED Ed that I found the other day, which motivated the example</a>). In Plato’s story, the ring grants its wearer invisibility, and with it, the temptation to act without consequences. I think something similar happens with LLMs: we get a nice powerup and assume no one will notice. But even if that were true (and it’s doubtful, since remaining unnoticed is hard when everyone knows you have “the ring”), the real danger isn’t getting caught. It’s the risk of corruption, of slowly losing part of ourselves in the process.</p>

<p>For all these reasons, I like to remind myself why I do what I do. And I keep coming back to the same answer: <strong>I want to create something interesting that lasts</strong>. I write posts not just to share, but to organize and reflect on my ideas. I paint miniatures because the result is cool, tangible, and lasting. As for studying and working in AI, it helps me understand myself better as a human being and, honestly, I still dream of creating intelligent beings. With that clarity, LLMs, and AI in general, become useful tools that help me develop my “craft”, serving my goals rather than eroding my sense of self.</p>

<p>So, what about the original question? What does Karpathy have in his Linkedin profile? Well, <a href="https://www.linkedin.com/in/andrej-karpathy-9a650716/">his profile simply has the URL of his personal webpage</a>, which probably makes sense for someone of his caliber. I am not sure if I should do the same, to be honest. Nevertheless, that small missclick finally pushed me to organize these thoughts. It also reminded me of what I wrote in that old cover letter. Now, hopefully, I can make a cool and lasting contribution, if not to AI itself, then at least with it.</p>

<div style="background-color: #f5f5f5; border-left: 4px solid #ccc; padding: 12px 16px; margin-top: 2em; font-size: 0.9em; color: #555;">
<strong>Note:</strong> I used Gemini 3.0 and Opus 4.5 to assist me in writing this post. They are undoubtedly better than me at writing. Nevertheless, all the ideas and content are entirely my own, and this post has undergone multiple rounds of revision between them and me.
</div>]]></content><author><name>Fernando Rodriguez</name></author><category term="blog" /><category term="Reflections" /><summary type="html"><![CDATA[Can we use AI as a tool without losing ourselves? I think so, as long as we stay connected to why we create things in the first place.]]></summary></entry><entry><title type="html">Introduction to Decision Theory: Part III</title><link href="https://ferjorosa.github.io/blog/2025/08/07/decision-theory-III.html" rel="alternate" type="text/html" title="Introduction to Decision Theory: Part III" /><published>2025-08-07T00:00:00+00:00</published><updated>2025-08-07T00:00:00+00:00</updated><id>https://ferjorosa.github.io/blog/2025/08/07/decision-theory-III</id><content type="html" xml:base="https://ferjorosa.github.io/blog/2025/08/07/decision-theory-III.html"><![CDATA[<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">
<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">Table of Contents</summary>

<ul style="margin-top: 0.5em;">
  <li style="margin-bottom: 0.5em;"><a href="#closing-the-loop">Closing the Loop</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#building-the-oil-field-limid-in-pyagrum">Building the Oil-Field LIMID in PyAgrum</a>
    <ul style="margin-top: 0.3em;">
      <li style="margin-bottom: 0.3em;"><a href="#setting-up-the-network-structure">Setting Up the Network Structure</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#filling-in-the-numbers">Filling in the Numbers</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#solving-the-network">Solving the Network</a></li>
    </ul>
  </li>
  <li style="margin-bottom: 0.5em;"><a href="#testing-robustness-with-sensitivity-analysis">Testing Robustness with Sensitivity Analysis</a>
    <ul style="margin-top: 0.3em;">
      <li style="margin-bottom: 0.3em;"><a href="#single-parameter-sensitivity-analysis">Single Parameter Sensitivity Analysis</a>
        <ul style="margin-top: 0.2em;">
          <li style="margin-bottom: 0.2em;"><a href="#example-1-prior-probability-of-high-quality-fields">Example 1: Prior Probability of High-Quality Fields</a></li>
          <li style="margin-bottom: 0.2em;"><a href="#example-2-test-precision-for-medium-quality-fields">Example 2: Test Precision for Medium-Quality Fields</a></li>
        </ul>
      </li>
      <li style="margin-bottom: 0.3em;"><a href="#tornado-diagrams-visualizing-parameter-impact">Tornado Diagrams: Visualizing Parameter Impact</a>
        <ul style="margin-top: 0.2em;">
          <li style="margin-bottom: 0.2em;"><a href="#example-1-direct-utility-value-sensitivity">Example 1: Direct Utility Value Sensitivity</a></li>
          <li style="margin-bottom: 0.2em;"><a href="#example-2-test-cost-sensitivity">Example 2: Test Cost Sensitivity</a></li>
        </ul>
      </li>
      <li style="margin-bottom: 0.3em;"><a href="#interactive-gradio-interface-real-time-multi-parameter-exploration">Interactive Gradio Interface</a>
        <ul style="margin-top: 0.2em;">
          <li style="margin-bottom: 0.2em;"><a href="#implementation-overview">Implementation Overview</a></li>
          <li style="margin-bottom: 0.2em;"><a href="#live-interactive-interface">Demo</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li style="margin-bottom: 0.5em;"><a href="#conclusion-building-robust-decision-strategies">Conclusion</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#references">References</a></li>
</ul>

</details>

<h2 id="closing-the-loop">Closing the Loop</h2>

<p>In <a href="https://ferjorosa.github.io/blog/2025/06/08/decision-theory-I.html">Part I</a>, we explored the oil company’s dilemma: should we buy the field or walk away? We used a decision tree to analyze the problem step by step, weighing probabilities and payoffs to determine the optimal choice. In <a href="https://ferjorosa.github.io/blog/2025/07/04/decision-theory-II.html">Part II</a>, we examined the limitations of decision trees and introduced influence diagrams as a more scalable alternative. We solved the same problem manually using influence diagrams, confirming that they yield the same result as decision trees.</p>

<p>But let’s be honest, constantly redrawing diagrams and recalculating expected utilities every time geological estimates change or market conditions shift is not realistic. Real-world decision problems need tools that adapt quickly. That’s what we’ll build in this final part, focusing on two crucial questions:</p>

<ol>
  <li>
    <p><strong>How do we actually implement these models in code?</strong> We’ll see how to recreate our oil field analysis using <a href="https://pyagrum.readthedocs.io"><code>PyAgrum</code></a>, transforming those tedious manual calculations into just a few lines of Python.</p>
  </li>
  <li>
    <p><strong>How much should we trust the model’s recommendation?</strong> Using sensitivity analysis, we’ll discover whether our “buy the field” decision is robust to parameter changes. We’ll build different types of visualizations and create an interactive <a href="https://www.gradio.app/"><code>Gradio</code></a> interface where we can adjust any parameter and immediately see the impact.</p>
  </li>
</ol>

<h2 id="building-the-oil-field-limid-in-pyagrum">Building the Oil-Field LIMID in PyAgrum</h2>

<p><a href="https://pyagrum.readthedocs.io"><code>PyAgrum</code></a> is a Python wrapper around the C++ <a href="https://agrum.gitlab.io/pages/agrum.html"><code>aGrUM</code></a> library for building and solving probabilistic graphical models such as Bayesian networks, LIMIDs, causal networks, and more. With a few lines of Python code we can define the influence diagram’s structure, add the probabilities and utilities, execute, and get the optimal policy.</p>

<p>Let’s now code the decision problem.</p>

<h3 id="setting-up-the-network-structure">Setting Up the LIMID Structure</h3>

<p>We start by importing <code>pyagrum</code> and creating an empty influence diagram. Then we add our four variables: oil field quality (\(\textcolor{purple}{Q}\)), test results (\(\textcolor{purple}{R}\)), the test decision (\(\textcolor{red}{T}\)), the buy decision (\(\textcolor{red}{B}\)), and a utility node (\(\textcolor{blue}{U}\)).</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pyagrum</span> <span class="k">as</span> <span class="n">grum</span>
<span class="kn">from</span> <span class="nn">pyagrum</span> <span class="kn">import</span> <span class="n">InfluenceDiagram</span>

<span class="c1"># Create the influence diagram
</span><span class="n">influence_diagram</span> <span class="o">=</span> <span class="n">InfluenceDiagram</span><span class="p">()</span>

<span class="c1"># Initialize with 0 states, then manually add the labels we need
</span><span class="n">Q</span> <span class="o">=</span> <span class="n">influence_diagram</span><span class="p">.</span><span class="n">addChanceNode</span><span class="p">(</span>
    <span class="n">grum</span><span class="p">.</span><span class="n">LabelizedVariable</span><span class="p">(</span><span class="s">"Q"</span><span class="p">,</span> <span class="s">"Q"</span><span class="p">,</span> <span class="mi">0</span><span class="p">).</span><span class="n">addLabel</span><span class="p">(</span><span class="s">'high'</span><span class="p">).</span><span class="n">addLabel</span><span class="p">(</span><span class="s">'medium'</span><span class="p">).</span><span class="n">addLabel</span><span class="p">(</span><span class="s">'low'</span><span class="p">))</span>
<span class="n">R</span> <span class="o">=</span> <span class="n">influence_diagram</span><span class="p">.</span><span class="n">addChanceNode</span><span class="p">(</span>
    <span class="n">grum</span><span class="p">.</span><span class="n">LabelizedVariable</span><span class="p">(</span><span class="s">"R"</span><span class="p">,</span> <span class="s">"R"</span><span class="p">,</span> <span class="mi">0</span><span class="p">).</span><span class="n">addLabel</span><span class="p">(</span><span class="s">'pass'</span><span class="p">).</span><span class="n">addLabel</span><span class="p">(</span><span class="s">'fail'</span><span class="p">).</span><span class="n">addLabel</span><span class="p">(</span><span class="s">'no_results'</span><span class="p">))</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">influence_diagram</span><span class="p">.</span><span class="n">addDecisionNode</span><span class="p">(</span>
    <span class="n">grum</span><span class="p">.</span><span class="n">LabelizedVariable</span><span class="p">(</span><span class="s">"T"</span><span class="p">,</span> <span class="s">"T"</span><span class="p">,</span> <span class="mi">0</span><span class="p">).</span><span class="n">addLabel</span><span class="p">(</span><span class="s">'do'</span><span class="p">).</span><span class="n">addLabel</span><span class="p">(</span><span class="s">'not_do'</span><span class="p">))</span>
<span class="n">B</span> <span class="o">=</span> <span class="n">influence_diagram</span><span class="p">.</span><span class="n">addDecisionNode</span><span class="p">(</span>
    <span class="n">grum</span><span class="p">.</span><span class="n">LabelizedVariable</span><span class="p">(</span><span class="s">"B"</span><span class="p">,</span> <span class="s">"B"</span><span class="p">,</span> <span class="mi">0</span><span class="p">).</span><span class="n">addLabel</span><span class="p">(</span><span class="s">'buy'</span><span class="p">).</span><span class="n">addLabel</span><span class="p">(</span><span class="s">'not_buy'</span><span class="p">))</span>
<span class="n">U</span> <span class="o">=</span> <span class="n">influence_diagram</span><span class="p">.</span><span class="n">addUtilityNode</span><span class="p">(</span><span class="s">"U"</span><span class="p">)</span>  <span class="c1"># Utility node takes just a name
</span></code></pre></div></div>

<p>Next, we connect the nodes with arcs to capture the dependencies from our diagram. Notice the memory arc from \(\textcolor{red}{T}\) to \(\textcolor{red}{B}\) that transforms the diagram into a LIMID.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Add arcs to define dependencies
</span><span class="n">influence_diagram</span><span class="p">.</span><span class="n">addArc</span><span class="p">(</span><span class="s">"T"</span><span class="p">,</span> <span class="s">"R"</span><span class="p">)</span>   
<span class="n">influence_diagram</span><span class="p">.</span><span class="n">addArc</span><span class="p">(</span><span class="s">"T"</span><span class="p">,</span> <span class="s">"B"</span><span class="p">)</span>    <span class="c1"># Memory arc: buy decision remembers test choice
</span><span class="n">influence_diagram</span><span class="p">.</span><span class="n">addArc</span><span class="p">(</span><span class="s">"T"</span><span class="p">,</span> <span class="s">"U"</span><span class="p">)</span>    
<span class="n">influence_diagram</span><span class="p">.</span><span class="n">addArc</span><span class="p">(</span><span class="s">"R"</span><span class="p">,</span> <span class="s">"B"</span><span class="p">)</span>
<span class="n">influence_diagram</span><span class="p">.</span><span class="n">addArc</span><span class="p">(</span><span class="s">"B"</span><span class="p">,</span> <span class="s">"U"</span><span class="p">)</span>
<span class="n">influence_diagram</span><span class="p">.</span><span class="n">addArc</span><span class="p">(</span><span class="s">"Q"</span><span class="p">,</span> <span class="s">"R"</span><span class="p">)</span>
<span class="n">influence_diagram</span><span class="p">.</span><span class="n">addArc</span><span class="p">(</span><span class="s">"Q"</span><span class="p">,</span> <span class="s">"U"</span><span class="p">)</span>
</code></pre></div></div>

<p><a href="https://pyagrum.readthedocs.io"><code>PyAgrum</code></a> makes it easy to visualize what we’ve built. We can generate a diagram directly from our code:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pyagrum.lib.notebook</span> <span class="k">as</span> <span class="n">gnb</span>
<span class="kn">from</span> <span class="nn">pyagrum.lib</span> <span class="kn">import</span> <span class="n">image</span>

<span class="c1"># Display if run in Jupyter notebook
</span><span class="n">gnb</span><span class="p">.</span><span class="n">sideBySide</span><span class="p">(</span><span class="n">influence_diagram</span><span class="p">,</span> <span class="n">captions</span><span class="o">=</span><span class="p">[</span><span class="s">"Oil field influence diagram"</span><span class="p">])</span>

<span class="c1"># Or export to PNG for use elsewhere
</span><span class="n">image</span><span class="p">.</span><span class="n">export</span><span class="p">(</span><span class="n">influence_diagram</span><span class="p">,</span> <span class="s">"influence_diagram.png"</span><span class="p">)</span>
</code></pre></div></div>

<p>Here’s the resulting <code>influence_diagram.png</code>, the same LIMID from <a href="https://ferjorosa.github.io/blog/2025/07/04/decision-theory-II.html">Part II</a>.</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-08-07-decision-theory-III/1_limid_oil_pyagrum.png" alt="Visual representation of the oil field LIMID generated by PyAgrum" width="200" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 1.</b> Visual representation of the oil field LIMID generated by PyAgrum</i>
    </td>
  </tr>
</table>
</center>

<h3 id="filling-in-the-numbers">Filling in the Numbers</h3>

<p>The network structure is just the skeleton. Now we need to populate it with the probabilities and utilities from our original problem.</p>

<p>First, we set the prior probabilities for oil field quality:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">influence_diagram</span><span class="p">.</span><span class="n">cpt</span><span class="p">(</span><span class="n">Q</span><span class="p">)[:]</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.35</span><span class="p">,</span> <span class="mf">0.45</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">]</span>  <span class="c1"># high, medium, low
</span></code></pre></div></div>

<p>Next, we define how test results depend on both the true field quality and whether we actually perform the test:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># When test is performed ('do')
</span><span class="n">influence_diagram</span><span class="p">.</span><span class="n">cpt</span><span class="p">(</span><span class="n">R</span><span class="p">)[{</span><span class="s">"Q"</span><span class="p">:</span> <span class="s">"high"</span><span class="p">,</span> <span class="s">"T"</span><span class="p">:</span> <span class="s">"do"</span><span class="p">}]</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.95</span><span class="p">,</span> <span class="mf">0.05</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">]</span>    <span class="c1"># pass, fail, no_results
</span><span class="n">influence_diagram</span><span class="p">.</span><span class="n">cpt</span><span class="p">(</span><span class="n">R</span><span class="p">)[{</span><span class="s">"Q"</span><span class="p">:</span> <span class="s">"medium"</span><span class="p">,</span> <span class="s">"T"</span><span class="p">:</span> <span class="s">"do"</span><span class="p">}]</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.7</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">]</span>
<span class="n">influence_diagram</span><span class="p">.</span><span class="n">cpt</span><span class="p">(</span><span class="n">R</span><span class="p">)[{</span><span class="s">"Q"</span><span class="p">:</span> <span class="s">"low"</span><span class="p">,</span> <span class="s">"T"</span><span class="p">:</span> <span class="s">"do"</span><span class="p">}]</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.15</span><span class="p">,</span> <span class="mf">0.85</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">]</span>

<span class="c1"># When test is not performed ('not_do') - always get 'no_results'
</span><span class="n">influence_diagram</span><span class="p">.</span><span class="n">cpt</span><span class="p">(</span><span class="n">R</span><span class="p">)[{</span><span class="s">"Q"</span><span class="p">:</span> <span class="s">"high"</span><span class="p">,</span> <span class="s">"T"</span><span class="p">:</span> <span class="s">"not_do"</span><span class="p">}]</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">]</span>
<span class="n">influence_diagram</span><span class="p">.</span><span class="n">cpt</span><span class="p">(</span><span class="n">R</span><span class="p">)[{</span><span class="s">"Q"</span><span class="p">:</span> <span class="s">"medium"</span><span class="p">,</span> <span class="s">"T"</span><span class="p">:</span> <span class="s">"not_do"</span><span class="p">}]</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">]</span>
<span class="n">influence_diagram</span><span class="p">.</span><span class="n">cpt</span><span class="p">(</span><span class="n">R</span><span class="p">)[{</span><span class="s">"Q"</span><span class="p">:</span> <span class="s">"low"</span><span class="p">,</span> <span class="s">"T"</span><span class="p">:</span> <span class="s">"not_do"</span><span class="p">}]</span> <span class="o">=</span> <span class="p">[</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">0.0</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">]</span>
</code></pre></div></div>

<p>Finally, we specify the utility values for each combination of decisions and outcomes. Note the $30M test cost when we choose to perform the test:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>

<span class="c1"># Test performed: subtract $30M test cost from original values
</span><span class="n">influence_diagram</span><span class="p">.</span><span class="n">utility</span><span class="p">(</span><span class="n">U</span><span class="p">)[{</span><span class="s">"T"</span><span class="p">:</span> <span class="s">"do"</span><span class="p">,</span> <span class="s">"B"</span><span class="p">:</span> <span class="s">"buy"</span><span class="p">}]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="mi">1220</span><span class="p">,</span> <span class="mi">600</span><span class="p">,</span> <span class="o">-</span><span class="mi">30</span><span class="p">])[:,</span> <span class="n">np</span><span class="p">.</span><span class="n">newaxis</span><span class="p">]</span>    <span class="c1"># Q: high, medium, low
</span><span class="n">influence_diagram</span><span class="p">.</span><span class="n">utility</span><span class="p">(</span><span class="n">U</span><span class="p">)[{</span><span class="s">"T"</span><span class="p">:</span> <span class="s">"do"</span><span class="p">,</span> <span class="s">"B"</span><span class="p">:</span> <span class="s">"not_buy"</span><span class="p">}]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="mi">320</span><span class="p">,</span> <span class="mi">320</span><span class="p">,</span> <span class="mi">320</span><span class="p">])[:,</span> <span class="n">np</span><span class="p">.</span><span class="n">newaxis</span><span class="p">]</span>

<span class="c1"># No test performed: original values
</span><span class="n">influence_diagram</span><span class="p">.</span><span class="n">utility</span><span class="p">(</span><span class="n">U</span><span class="p">)[{</span><span class="s">"T"</span><span class="p">:</span> <span class="s">"not_do"</span><span class="p">,</span> <span class="s">"B"</span><span class="p">:</span> <span class="s">"buy"</span><span class="p">}]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="mi">1250</span><span class="p">,</span> <span class="mi">630</span><span class="p">,</span> <span class="mi">0</span><span class="p">])[:,</span> <span class="n">np</span><span class="p">.</span><span class="n">newaxis</span><span class="p">]</span>
<span class="n">influence_diagram</span><span class="p">.</span><span class="n">utility</span><span class="p">(</span><span class="n">U</span><span class="p">)[{</span><span class="s">"T"</span><span class="p">:</span> <span class="s">"not_do"</span><span class="p">,</span> <span class="s">"B"</span><span class="p">:</span> <span class="s">"not_buy"</span><span class="p">}]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="mi">350</span><span class="p">,</span> <span class="mi">350</span><span class="p">,</span> <span class="mi">350</span><span class="p">])[:,</span> <span class="n">np</span><span class="p">.</span><span class="n">newaxis</span><span class="p">]</span>
</code></pre></div></div>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
The <code>[:, np.newaxis]</code> reshaping is used to align the data with the expected order of parent nodes. While not confirmed to be a universal PyAgrum requirement, this approach proved effective in this specific implementation.
</div>
<div style="height: 1.1em;"></div>

<h3 id="solving-the-network">Solving the Network</h3>

<p>With structure and parameters in place, we can create an inference engine and solve the decision problem. In this case, we use the Shafer-Shenoy algorithm for LIMIDs (<a href="https://kuscholarworks.ku.edu/server/api/core/bitstreams/c353aa52-11ad-46c0-b867-f5d05f7f1962/content"><u>Shafer &amp; Shenoy, 1990</u></a>):</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Create inference engine and solve
</span><span class="n">inference_engine</span> <span class="o">=</span> <span class="n">grum</span><span class="p">.</span><span class="n">ShaferShenoyLIMIDInference</span><span class="p">(</span><span class="n">influence_diagram</span><span class="p">)</span>
<span class="n">inference_engine</span><span class="p">.</span><span class="n">makeInference</span><span class="p">()</span>

<span class="k">print</span><span class="p">(</span><span class="sa">f</span><span class="s">"Is the diagram solvable?: </span><span class="si">{</span><span class="n">inference_engine</span><span class="p">.</span><span class="n">isSolvable</span><span class="p">()</span><span class="si">}</span><span class="s">"</span><span class="p">)</span>
</code></pre></div></div>

<p>We can examine the optimal decision for each decision node. For example, the test decision (\(\textcolor{red}{T}\)):</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">IPython.display</span> <span class="kn">import</span> <span class="n">display</span>

<span class="n">optimal_decision_T</span> <span class="o">=</span> <span class="n">inference_engine</span><span class="p">.</span><span class="n">optimalDecision</span><span class="p">(</span><span class="n">T</span><span class="p">)</span>

<span class="k">print</span><span class="p">(</span><span class="n">optimal_decision_T</span><span class="p">)</span>
<span class="n">display</span><span class="p">(</span><span class="n">optimal_decision_T</span><span class="p">)</span>
</code></pre></div></div>

<p>This outputs both a text representation and a formatted table in Jupyter notebooks:</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-08-07-decision-theory-III/2_optimal_decision_t.png" alt="Optimal decision T displayed as text and table in PyAgrum" width="250" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 2.</b> Optimal decision for test variable T shown in both text and table format</i>
    </td>
  </tr>
</table>
</center>

<p>We can also generate a visual representation of the solved network, showing the optimal decisions and expected utilities:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Note: On macOS, you may need this line to avoid cairo issues
</span><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">pyagrum.lib.notebook</span> <span class="k">as</span> <span class="n">gnb</span>

<span class="n">os</span><span class="p">.</span><span class="n">environ</span><span class="p">[</span><span class="s">"DYLD_FALLBACK_LIBRARY_PATH"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"/opt/homebrew/opt/cairo/lib"</span>

<span class="c1"># Visualize the solved network
</span><span class="n">gnb</span><span class="p">.</span><span class="n">showInference</span><span class="p">(</span><span class="n">influence_diagram</span><span class="p">,</span> <span class="n">engine</span><span class="o">=</span><span class="n">inference_engine</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="s">"6!"</span><span class="p">)</span>

<span class="c1"># Or export the inference result as an image
</span><span class="n">image</span><span class="p">.</span><span class="n">exportInference</span><span class="p">(</span><span class="n">influence_diagram</span><span class="p">,</span> <span class="s">"inference_result.png"</span><span class="p">,</span> <span class="n">engine</span><span class="o">=</span><span class="n">inference_engine</span><span class="p">)</span>
</code></pre></div></div>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-08-07-decision-theory-III/3_inference_result.png" alt="Evaluated oil field LIMID generated by PyAgrum" width="500" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 3.</b> Solved oil field LIMID showing optimal decisions and expected utilities</i>
    </td>
  </tr>
</table>
</center>

<p>The results confirm our hand-written calculations: the optimal strategy is to skip the test and buy the field directly, with a maximum expected utility of 721 million dollars. What took us pages of manual calculations, <a href="https://pyagrum.readthedocs.io"><code>PyAgrum</code></a> solved in just 0.24 milliseconds.</p>

<h2 id="testing-robustness-with-sensitivity-analysis">Testing Robustness with Sensitivity Analysis</h2>

<p>Now that we’ve found the best strategy for buying the oil field, we may wonder: What happens if we got some of our numbers wrong? Maybe the geological survey isn’t as accurate as we thought, or test costs could jump higher than expected. At what point do these changes actually matter for our decision?</p>

<p>This is exactly what sensitivity analysis helps us figure out. Once we have our optimal strategy, we need to test how much our answer depends on the specific numbers we plugged in. Some parameters might barely affect our decision, while others could completely flip our recommendation with just small changes.</p>

<p>We’ll tackle this challenge with three complementary approaches:</p>

<ol>
  <li>
    <p><strong>Single-parameter sweeps</strong>: Vary one parameter at a time to see how the expected utility changes, helping us understand individual parameter sensitivity.</p>
  </li>
  <li>
    <p><strong>Tornado diagrams</strong>: Create visual summaries that show which variables have the most impact on our decision, sorted by magnitude of influence.</p>
  </li>
  <li>
    <p><strong>Interactive Gradio interface</strong>: Build a web app where we can change multiple parameters simultaneously, and instantly see how the optimal decision and expected utility respond.</p>
  </li>
</ol>

<h3 id="single-parameter-sensitivity-analysis">Single Parameter Sensitivity Analysis</h3>

<p>Single parameter sensitivity analysis examines how changes in one specific parameter affect 
the optimal decision and expected utility while keeping all other parameters constant. This 
approach is particularly valuable because it:</p>

<ul>
  <li><strong>Identifies critical thresholds</strong>: We can discover specific values where the optimal decision changes.</li>
  <li><strong>Guides data collection</strong>: Parameters with high sensitivity may warrant additional 
research or more precise estimation.</li>
</ul>

<p>Let’s apply this to two key parameters in our oil field problem.</p>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
<a href="https://github.com/ferjorosa/decision-theory-llms/tree/main/decision_problems/oil_field_purchase/sensitivity_analysis">You can find  the complete source code for this implementation on GitHub</a>
</div>
<div style="height: 1.1em;"></div>

<h4 id="example-1-prior-probability-of-high-quality-fields">Example 1: Prior Probability of High-quality Fields</h4>

<p>Our first analysis explores how varying the prior probability that a field is high quality influences our decision strategy. Beginning with the baseline value \(P(\textcolor{purple}{Q}=\textcolor{purple}{\text{high}}) = 0.35\), we adjust this probability by \(\pm0.15\) in increments of \(0.05\), producing seven scenarios. The probabilities of the remaining quality categories are rescaled proportionally so that the distribution still sums to one.</p>

<center>
<table>
  <tr>
    <td align="center">
      <div id="q-cpt-sensitivity-plot" class="plotly-graph-div" style="height:500px; width:100%; max-width:700px;"></div>
      <script type="text/javascript">
      // Ensure syntax highlighting is preserved before creating Plotly chart
      document.addEventListener('DOMContentLoaded', function() {
        // Wait a bit to ensure syntax highlighting is stable
        setTimeout(function() {
          if (typeof Plotly !== 'undefined') {
            window.PLOTLYENV = window.PLOTLYENV || {};
            Plotly.newPlot(
              "q-cpt-sensitivity-plot",
              [{"hovertemplate":"%{hovertext}<extra></extra>","hovertext":["Parameter: 0.200<br>MEU: 598.9<br>T: not_do<br>B: [R=pass→buy, R=fail→buy, R=no_results→buy]","Parameter: 0.250<br>MEU: 639.6<br>T: not_do<br>B: [R=pass→buy, R=fail→buy, R=no_results→buy]","Parameter: 0.300<br>MEU: 680.3<br>T: not_do<br>B: [R=pass→buy, R=fail→buy, R=no_results→buy]","Parameter: 0.350<br>MEU: 721.0<br>T: not_do<br>B: [R=pass→buy, R=fail→buy, R=no_results→buy]","Parameter: 0.400<br>MEU: 761.7<br>T: not_do<br>B: [R=pass→buy, R=fail→buy, R=no_results→buy]","Parameter: 0.450<br>MEU: 802.4<br>T: not_do<br>B: [R=pass→buy, R=fail→buy, R=no_results→buy]","Parameter: 0.500<br>MEU: 843.1<br>T: not_do<br>B: [R=pass→buy, R=fail→buy, R=no_results→buy]"],"line":{"color":"steelblue","width":3},"marker":{"color":"steelblue","line":{"color":"navy","width":2},"size":12},"mode":"markers+lines","name":"Sensitivity Analysis","x":[598.9230769230769,639.6153846153846,680.3076923076924,721.0,761.6923076923076,802.3846153846154,843.0769230769231],"y":[0.19999999999999998,0.24999999999999997,0.3,0.35,0.39999999999999997,0.44999999999999996,0.5],"type":"scatter"}],
              {"template":{"data":{"barpolar":[{"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"type":"carpet"}],"choropleth":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"choropleth"}],"contourcarpet":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"contourcarpet"}],"contour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"contour"}],"heatmap":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"heatmap"}],"histogram2dcontour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2dcontour"}],"histogram2d":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2d"}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"mesh3d":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"mesh3d"}],"parcoords":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"parcoords"}],"pie":[{"automargin":true,"type":"pie"}],"scatter3d":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatter3d"}],"scattercarpet":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattercarpet"}],"scattergeo":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergeo"}],"scattergl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergl"}],"scattermapbox":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermapbox"}],"scattermap":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermap"}],"scatterpolargl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolargl"}],"scatterpolar":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolar"}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"scatterternary":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterternary"}],"surface":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"surface"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}]},"layout":{"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"autotypenumbers":"strict","coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]],"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]},"colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"geo":{"bgcolor":"white","lakecolor":"white","landcolor":"white","showlakes":true,"showland":true,"subunitcolor":"#C8D4E3"},"hoverlabel":{"align":"left"},"hovermode":"closest","mapbox":{"style":"light"},"paper_bgcolor":"white","plot_bgcolor":"white","polar":{"angularaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""},"bgcolor":"white","radialaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""}},"scene":{"xaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"yaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"zaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"ternary":{"aaxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"baxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"bgcolor":"white","caxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""}},"title":{"x":0.05},"xaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2},"yaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2}}},"annotations":[{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"598.9","x":598.9230769230769,"xshift":15,"y":0.19999999999999998,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"639.6","x":639.6153846153846,"xshift":15,"y":0.24999999999999997,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"680.3","x":680.3076923076924,"xshift":15,"y":0.3,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"721.0","x":721.0,"xshift":15,"y":0.35,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"761.7","x":761.6923076923076,"xshift":15,"y":0.39999999999999997,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"802.4","x":802.3846153846154,"xshift":15,"y":0.44999999999999996,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"843.1","x":843.0769230769231,"xshift":15,"y":0.5,"yshift":5},{"showarrow":false,"text":"Baseline MEU: 721.0","x":721.0,"xanchor":"center","xref":"x","y":1,"yanchor":"bottom","yref":"y domain"}],"shapes":[{"line":{"color":"red","dash":"dash"},"type":"line","x0":721.0,"x1":721.0,"xref":"x","y0":0,"y1":1,"yref":"y domain"}],"title":{"text":"Sensitivity Analysis: P(Q=high) vs MEU"},"xaxis":{"title":{"text":"Maximum Expected Utility (MEU)"}},"yaxis":{"title":{"text":"P(Q=high)"}},"width":700,"height":500,"showlegend":false},
              {"responsive": true}
            );
          }
        }, 200); // Small delay to let syntax highlighting settle
      });
      </script>
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 4.</b> Sensitivity analysis of prior probability P(Q=high) showing the relationship between field quality expectations and maximum expected utility</i>
    </td>
  </tr>
</table>
</center>

<p>These changes definitely affect how much money we expect to make, but they don’t change the optimal policy: skip the test and buy the field directly. This makes sense when you think about it: knowing that fields in this region are more likely to be high quality affects our expected profits, but it doesn’t change how useful the test would be.</p>

<h4 id="example-2-test-precision-for-medium-quality-fields">Example 2: Test Precision for Medium-quality Fields</h4>

<p>For our second analysis, let’s look at the geological test’s accuracy, specifically focusing on its ability to correctly identify medium-quality fields. Medium-quality fields are particularly interesting because they are profitable but seem easy to mistake for 
low-grade ones.</p>

<p>What if we could improve the test to better identify these medium-quality fields? We’ll vary the test’s pass rate for true medium fields \(P(\textcolor{purple}{R}=\textcolor{purple}{\text{pass}} \mid \textcolor{purple}{Q}=\textcolor{purple}{\text{medium}})\) from \(0.70\) to \(0.95\) to see when the improved accuracy makes testing worthwhile.</p>

<center>
<table>
  <tr>
    <td align="center">
      <div id="r-cpt-sensitivity-plot" class="plotly-graph-div" style="height:500px; width:100%; max-width:700px;"></div>
      <script type="text/javascript">
      // Ensure syntax highlighting is preserved before creating second Plotly chart
      document.addEventListener('DOMContentLoaded', function() {
        // Wait a bit longer to ensure first plot and syntax highlighting are stable
        setTimeout(function() {
          if (typeof Plotly !== 'undefined') {
            window.PLOTLYENV = window.PLOTLYENV || {};
            Plotly.newPlot(
              "r-cpt-sensitivity-plot",
              [{"hovertemplate":"%{hovertext}<extra></extra>","hovertext":["Parameter: 0.700<br>MEU: 721.0<br>T: not_do<br>B: [R=pass→buy, R=fail→buy, R=no_results→buy]","Parameter: 0.750<br>MEU: 721.0<br>T: not_do<br>B: [R=pass→buy, R=fail→buy, R=no_results→buy]","Parameter: 0.800<br>MEU: 721.0<br>T: not_do<br>B: [R=pass→buy, R=fail→buy, R=no_results→buy]","Parameter: 0.850<br>MEU: 721.0<br>T: not_do<br>B: [R=pass→buy, R=fail→buy, R=no_results→buy]","Parameter: 0.900<br>MEU: 722.1<br>T: do<br>B: [R=pass→buy, R=fail→not_buy, R=no_results→buy]","Parameter: 0.950<br>MEU: 728.5<br>T: do<br>B: [R=pass→buy, R=fail→not_buy, R=no_results→buy]"],"line":{"color":"steelblue","width":3},"marker":{"color":"steelblue","line":{"color":"navy","width":2},"size":12},"mode":"markers+lines","name":"Sensitivity Analysis","x":[721.0,721.0,721.0,721.0,722.15,728.45],"y":[0.7,0.75,0.7999999999999999,0.85,0.8999999999999999,0.95],"type":"scatter"}],
              {"template":{"data":{"barpolar":[{"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"white","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"#C8D4E3","linecolor":"#C8D4E3","minorgridcolor":"#C8D4E3","startlinecolor":"#2a3f5f"},"type":"carpet"}],"choropleth":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"choropleth"}],"contourcarpet":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"contourcarpet"}],"contour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"contour"}],"heatmap":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"heatmap"}],"histogram2dcontour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2dcontour"}],"histogram2d":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2d"}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"mesh3d":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"mesh3d"}],"parcoords":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"parcoords"}],"pie":[{"automargin":true,"type":"pie"}],"scatter3d":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatter3d"}],"scattercarpet":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattercarpet"}],"scattergeo":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergeo"}],"scattergl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergl"}],"scattermapbox":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermapbox"}],"scattermap":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermap"}],"scatterpolargl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolargl"}],"scatterpolar":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolar"}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"scatterternary":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterternary"}],"surface":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"surface"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}]},"layout":{"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"autotypenumbers":"strict","coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]],"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]},"colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"geo":{"bgcolor":"white","lakecolor":"white","landcolor":"white","showlakes":true,"showland":true,"subunitcolor":"#C8D4E3"},"hoverlabel":{"align":"left"},"hovermode":"closest","mapbox":{"style":"light"},"paper_bgcolor":"white","plot_bgcolor":"white","polar":{"angularaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""},"bgcolor":"white","radialaxis":{"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":""}},"scene":{"xaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"yaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"},"zaxis":{"backgroundcolor":"white","gridcolor":"#DFE8F3","gridwidth":2,"linecolor":"#EBF0F8","showbackground":true,"ticks":"","zerolinecolor":"#EBF0F8"}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"ternary":{"aaxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"baxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""},"bgcolor":"white","caxis":{"gridcolor":"#DFE8F3","linecolor":"#A2B1C6","ticks":""}},"title":{"x":0.05},"xaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2},"yaxis":{"automargin":true,"gridcolor":"#EBF0F8","linecolor":"#EBF0F8","ticks":"","title":{"standoff":15},"zerolinecolor":"#EBF0F8","zerolinewidth":2}}},"annotations":[{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"721.0","x":721.0,"xshift":15,"y":0.7,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"721.0","x":721.0,"xshift":15,"y":0.75,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"721.0","x":721.0,"xshift":15,"y":0.7999999999999999,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"721.0","x":721.0,"xshift":15,"y":0.85,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"722.1","x":722.15,"xshift":15,"y":0.8999999999999999,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"728.5","x":728.45,"xshift":15,"y":0.95,"yshift":5},{"bgcolor":"rgba(255,255,255,0.8)","bordercolor":"black","borderwidth":1,"font":{"color":"black","size":10},"showarrow":false,"text":"Baseline MEU: 721.0","x":721.0,"xanchor":"center","xref":"x","y":1,"yanchor":"bottom","yref":"y domain"}],"shapes":[{"line":{"color":"red","dash":"dash"},"type":"line","x0":721.0,"x1":721.0,"xref":"x","y0":0,"y1":1,"yref":"y domain"}],"title":{"text":"Sensitivity Analysis: P(R=pass | Q=medium) vs MEU"},"xaxis":{"title":{"text":"Maximum Expected Utility (MEU)"}},"yaxis":{"title":{"text":"P(R=pass | Q=medium)"}},"width":700,"height":500,"showlegend":false},
              {"responsive": true}
            );
          }
        }, 400); // Longer delay for second plot to let first one settle
      });
      </script>
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 5.</b> Sensitivity analysis of test precision P(R=pass | Q=medium) showing when improved test accuracy makes testing worthwhile</i>
    </td>
  </tr>
</table>
</center>

<p>Interestingly, once the test becomes good enough at spotting medium-quality fields (achieving \(0.9\) accuracy or better), testing suddenly becomes worth the cost. The takeaway is clear: if we can upgrade our testing technology to correctly identify medium-quality fields at least 90% of the time, we should start using the test before making purchase decisions.</p>

<h3 id="tornado-diagrams-visualizing-parameter-impact">Tornado Diagrams: Visualizing Parameter Impact</h3>

<p>While single parameter analysis tells us how each variable affects our decision, <a href="https://en.wikipedia.org/wiki/Tornado_diagram"><u>tornado diagrams</u></a> give us the big picture by ranking all parameters by their <strong>individual</strong> impact. These charts get their name from their shape: wide at the top for the most important variables and narrow at the bottom for the least important.</p>

<p>These diagrams are particularly valuable when we have formulas that define the utilities. For instance, if our utility numbers depended on a formula based on factors like drilling costs, oil prices, or project timelines, a tornado diagram would easily show us whether a 10% change in oil prices matters more than a 20% change in drilling costs.</p>

<p>For our oil field problem, we’ll look at two examples to see how this works.</p>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
<a href="https://github.com/ferjorosa/decision-theory-llms/tree/main/decision_problems/oil_field_purchase/sensitivity_analysis">You can find  the complete source code for this implementation on GitHub</a>
</div>
<div style="height: 1.1em;"></div>

<h4 id="example-1-direct-utility-value-sensitivity">Example 1: Direct Utility Value Sensitivity</h4>

<p>Our first tornado analysis examines how changes in the direct utility values affect the maximum expected utility. We test each utility parameter by applying a \(\pm100\) million dollar variation while keeping all other parameters constant.</p>

<center>
<table>
  <tr>
    <td align="center">
      <div id="tornado-plot-utility" class="plotly-graph-div" style="height:500px; width:100%; max-width:700px;"></div>
      <script type="text/javascript">
      // Ensure syntax highlighting is preserved before creating tornado plot
      document.addEventListener('DOMContentLoaded', function() {
        // Wait a bit longer to ensure previous plots and syntax highlighting are stable
        setTimeout(function() {
          if (typeof Plotly !== 'undefined') {
            window.PLOTLYENV = window.PLOTLYENV || {};
            Plotly.newPlot(
              "tornado-plot-utility",
              [{"hoverinfo":"skip","marker":{"color":"lightcoral","line":{"color":"black","width":0.5}},"name":"Lower Impact","offsetgroup":"1","orientation":"h","showlegend":true,"width":0.6,"x":[-24.049999999999955],"y":["U(not_do, buy, medium)"],"type":"bar"},{"hoverinfo":"skip","marker":{"color":"lightblue","line":{"color":"black","width":0.5}},"name":"Higher Impact","offsetgroup":"1","orientation":"h","showlegend":true,"width":0.6,"x":[45.0],"y":["U(not_do, buy, medium)"],"type":"bar"},{"hoverlabel":{"bgcolor":"lightcoral","bordercolor":"darkred","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(not_do, buy, medium)\u003cbr\u003e\n        Low Scenario\u003cbr\u003e\n        MEU: 696.95\u003cbr\u003e\n        Impact: -24.05\u003cbr\u003e\n        Optimal Decisions: T: do, B: [pass: buy, fail: not_buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[-12.024999999999977],"y":["U(not_do, buy, medium)"],"type":"scatter"},{"hoverlabel":{"bgcolor":"lightblue","bordercolor":"darkblue","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(not_do, buy, medium)\u003cbr\u003e\n        High Scenario\u003cbr\u003e\n        MEU: 766.00\u003cbr\u003e\n        Impact: +45.00\u003cbr\u003e\n        Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[22.5],"y":["U(not_do, buy, medium)"],"type":"scatter"},{"hoverinfo":"skip","marker":{"color":"lightcoral","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[-24.049999999999955],"y":["U(not_do, buy, high)"],"type":"bar"},{"hoverinfo":"skip","marker":{"color":"lightblue","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[35.0],"y":["U(not_do, buy, high)"],"type":"bar"},{"hoverlabel":{"bgcolor":"lightcoral","bordercolor":"darkred","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(not_do, buy, high)\u003cbr\u003e\n        Low Scenario\u003cbr\u003e\n        MEU: 696.95\u003cbr\u003e\n        Impact: -24.05\u003cbr\u003e\n        Optimal Decisions: T: do, B: [pass: buy, fail: not_buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[-12.024999999999977],"y":["U(not_do, buy, high)"],"type":"scatter"},{"hoverlabel":{"bgcolor":"lightblue","bordercolor":"darkblue","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(not_do, buy, high)\u003cbr\u003e\n        High Scenario\u003cbr\u003e\n        MEU: 756.00\u003cbr\u003e\n        Impact: +35.00\u003cbr\u003e\n        Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[17.5],"y":["U(not_do, buy, high)"],"type":"scatter"},{"hoverinfo":"skip","marker":{"color":"lightcoral","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[-20.0],"y":["U(not_do, buy, low)"],"type":"bar"},{"hoverinfo":"skip","marker":{"color":"lightblue","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[20.0],"y":["U(not_do, buy, low)"],"type":"bar"},{"hoverlabel":{"bgcolor":"lightcoral","bordercolor":"darkred","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(not_do, buy, low)\u003cbr\u003e\n        Low Scenario\u003cbr\u003e\n        MEU: 701.00\u003cbr\u003e\n        Impact: -20.00\u003cbr\u003e\n        Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[-10.0],"y":["U(not_do, buy, low)"],"type":"scatter"},{"hoverlabel":{"bgcolor":"lightblue","bordercolor":"darkblue","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(not_do, buy, low)\u003cbr\u003e\n        High Scenario\u003cbr\u003e\n        MEU: 741.00\u003cbr\u003e\n        Impact: +20.00\u003cbr\u003e\n        Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[10.0],"y":["U(not_do, buy, low)"],"type":"scatter"},{"hoverinfo":"skip","marker":{"color":"lightcoral","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[0.0],"y":["U(do, buy, medium)"],"type":"bar"},{"hoverinfo":"skip","marker":{"color":"lightblue","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[15.0],"y":["U(do, buy, medium)"],"type":"bar"},{"hoverlabel":{"bgcolor":"lightcoral","bordercolor":"darkred","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(do, buy, medium)\u003cbr\u003e\n        Low Scenario\u003cbr\u003e\n        MEU: 721.00\u003cbr\u003e\n        Impact: +0.00\u003cbr\u003e\n        Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[0.0],"y":["U(do, buy, medium)"],"type":"scatter"},{"hoverlabel":{"bgcolor":"lightblue","bordercolor":"darkblue","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(do, buy, medium)\u003cbr\u003e\n        High Scenario\u003cbr\u003e\n        MEU: 736.00\u003cbr\u003e\n        Impact: +15.00\u003cbr\u003e\n        Optimal Decisions: T: do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[7.5],"y":["U(do, buy, medium)"],"type":"scatter"},{"hoverinfo":"skip","marker":{"color":"lightcoral","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[0.0],"y":["U(do, buy, high)"],"type":"bar"},{"hoverinfo":"skip","marker":{"color":"lightblue","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[9.200000000000045],"y":["U(do, buy, high)"],"type":"bar"},{"hoverlabel":{"bgcolor":"lightcoral","bordercolor":"darkred","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(do, buy, high)\u003cbr\u003e\n        Low Scenario\u003cbr\u003e\n        MEU: 721.00\u003cbr\u003e\n        Impact: +0.00\u003cbr\u003e\n        Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[0.0],"y":["U(do, buy, high)"],"type":"scatter"},{"hoverlabel":{"bgcolor":"lightblue","bordercolor":"darkblue","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(do, buy, high)\u003cbr\u003e\n        High Scenario\u003cbr\u003e\n        MEU: 730.20\u003cbr\u003e\n        Impact: +9.20\u003cbr\u003e\n        Optimal Decisions: T: do, B: [pass: buy, fail: not_buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[4.600000000000023],"y":["U(do, buy, high)"],"type":"scatter"},{"hoverinfo":"skip","marker":{"color":"lightcoral","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[0.0],"y":["U(do, not_buy)"],"type":"bar"},{"hoverinfo":"skip","marker":{"color":"lightblue","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[8.200000000000045],"y":["U(do, not_buy)"],"type":"bar"},{"hoverlabel":{"bgcolor":"lightcoral","bordercolor":"darkred","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(do, not_buy)\u003cbr\u003e\n        Low Scenario\u003cbr\u003e\n        MEU: 721.00\u003cbr\u003e\n        Impact: +0.00\u003cbr\u003e\n        Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[0.0],"y":["U(do, not_buy)"],"type":"scatter"},{"hoverlabel":{"bgcolor":"lightblue","bordercolor":"darkblue","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(do, not_buy)\u003cbr\u003e\n        High Scenario\u003cbr\u003e\n        MEU: 729.20\u003cbr\u003e\n        Impact: +8.20\u003cbr\u003e\n        Optimal Decisions: T: do, B: [pass: buy, fail: not_buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[4.100000000000023],"y":["U(do, not_buy)"],"type":"scatter"},{"hoverinfo":"skip","marker":{"color":"lightcoral","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[0.0],"y":["U(do, buy, low)"],"type":"bar"},{"hoverinfo":"skip","marker":{"color":"lightblue","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[0.0],"y":["U(do, buy, low)"],"type":"bar"},{"hoverlabel":{"bgcolor":"lightcoral","bordercolor":"darkred","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(do, buy, low)\u003cbr\u003e\n        High Scenario\u003cbr\u003e\n        MEU: 721.00\u003cbr\u003e\n        Impact: +0.00\u003cbr\u003e\n        Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[0.0],"y":["U(do, buy, low)"],"type":"scatter"},{"hoverlabel":{"bgcolor":"lightblue","bordercolor":"darkblue","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(do, buy, low)\u003cbr\u003e\n        Low Scenario\u003cbr\u003e\n        MEU: 721.00\u003cbr\u003e\n        Impact: +0.00\u003cbr\u003e\n        Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[0.0],"y":["U(do, buy, low)"],"type":"scatter"},{"hoverinfo":"skip","marker":{"color":"lightcoral","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[0.0],"y":["U(not_do, not_buy)"],"type":"bar"},{"hoverinfo":"skip","marker":{"color":"lightblue","line":{"color":"black","width":0.5}},"name":"","offsetgroup":"1","orientation":"h","showlegend":false,"width":0.6,"x":[0.0],"y":["U(not_do, not_buy)"],"type":"bar"},{"hoverlabel":{"bgcolor":"lightcoral","bordercolor":"darkred","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(not_do, not_buy)\u003cbr\u003e\n        High Scenario\u003cbr\u003e\n        MEU: 721.00\u003cbr\u003e\n        Impact: +0.00\u003cbr\u003e\n        Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[0.0],"y":["U(not_do, not_buy)"],"type":"scatter"},{"hoverlabel":{"bgcolor":"lightblue","bordercolor":"darkblue","font":{"color":"black"}},"hovertemplate":"\n        Variable: U(not_do, not_buy)\u003cbr\u003e\n        Low Scenario\u003cbr\u003e\n        MEU: 721.00\u003cbr\u003e\n        Impact: +0.00\u003cbr\u003e\n        Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n        \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[0.0],"y":["U(not_do, not_buy)"],"type":"scatter"}],
              {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"}}},"annotations":[{"font":{"size":10},"showarrow":false,"text":"-24.0","x":-26.45499999999995,"xanchor":"right","y":"U(not_do, buy, medium)"},{"font":{"size":10},"showarrow":false,"text":"45.0","x":49.5,"xanchor":"left","y":"U(not_do, buy, medium)"},{"font":{"size":10},"showarrow":false,"text":"-24.0","x":-26.45499999999995,"xanchor":"right","y":"U(not_do, buy, high)"},{"font":{"size":10},"showarrow":false,"text":"35.0","x":38.5,"xanchor":"left","y":"U(not_do, buy, high)"},{"font":{"size":10},"showarrow":false,"text":"-20.0","x":-22.0,"xanchor":"right","y":"U(not_do, buy, low)"},{"font":{"size":10},"showarrow":false,"text":"20.0","x":22.0,"xanchor":"left","y":"U(not_do, buy, low)"},{"font":{"size":10},"showarrow":false,"text":"0.0","x":-1.0,"xanchor":"left","y":"U(do, buy, medium)"},{"font":{"size":10},"showarrow":false,"text":"15.0","x":16.5,"xanchor":"left","y":"U(do, buy, medium)"},{"font":{"size":10},"showarrow":false,"text":"0.0","x":-1.0,"xanchor":"left","y":"U(do, buy, high)"},{"font":{"size":10},"showarrow":false,"text":"9.2","x":10.12000000000005,"xanchor":"left","y":"U(do, buy, high)"},{"font":{"size":10},"showarrow":false,"text":"0.0","x":-1.0,"xanchor":"left","y":"U(do, not_buy)"},{"font":{"size":10},"showarrow":false,"text":"8.2","x":9.02000000000005,"xanchor":"left","y":"U(do, not_buy)"},{"font":{"size":10},"showarrow":false,"text":"0.0","x":-1.0,"xanchor":"left","y":"U(do, buy, low)"},{"font":{"size":10},"showarrow":false,"text":"0.0","x":1.0,"xanchor":"right","y":"U(do, buy, low)"},{"font":{"size":10},"showarrow":false,"text":"0.0","x":-1.0,"xanchor":"left","y":"U(not_do, not_buy)"},{"font":{"size":10},"showarrow":false,"text":"0.0","x":1.0,"xanchor":"right","y":"U(not_do, not_buy)"}],"shapes":[{"line":{"color":"black","width":2},"type":"line","x0":0,"x1":0,"xref":"x","y0":0,"y1":1,"yref":"y domain"}],"title":{"font":{"size":16},"text":"Oil Field Purchase: Utility Sensitivity Analysis (Constant Variation)\u003cbr\u003e\u003csub\u003eBaseline Expected Utility: 721.00 | Utility values varied by ±100 units\u003c\u002fsub\u003e"},"xaxis":{"title":{"text":"Change in Expected Utility from Baseline"},"gridcolor":"lightgray","gridwidth":0.5,"zeroline":true,"zerolinecolor":"black","zerolinewidth":2},"yaxis":{"title":{"text":"Utility Variables"},"categoryorder":"array","categoryarray":["U(not_do, not_buy)","U(do, buy, low)","U(do, not_buy)","U(do, buy, high)","U(do, buy, medium)","U(not_do, buy, low)","U(not_do, buy, high)","U(not_do, buy, medium)"]},"legend":{"orientation":"h","yanchor":"bottom","y":1.02,"xanchor":"right","x":1},"width":700,"height":500,"bargap":0.1,"bargroupgap":0,"hovermode":"closest"},
              {"responsive": true}
            );
          }
        }, 400); // Delay for tornado plot to let previous ones settle
      });
      </script>
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 6.</b> Tornado diagram showing the impact of utility value variations on maximum expected utility</i>
    </td>
  </tr>
</table>
</center>

<p>The analysis reveals that \(\textcolor{blue}{U}(\textcolor{red}{T} = \textcolor{red}{\text{not_do}},\ \textcolor{red}{B} = \textcolor{red}{\text{buy}},\ \textcolor{purple}{Q} = \textcolor{purple}{\text{medium}})\) has the largest impact on our decision. This makes intuitive sense, since medium-quality fields have the highest prior probability (\(0.45\)), so changes to their utility values disproportionately affect the overall expected utility.</p>

<p>Changes to utilities involving testing (\(\textcolor{red}{T} = \textcolor{red}{\text{do}}\) scenarios) have smaller impacts because testing is already suboptimal in our baseline analysis. These utility values would need to change enough to flip the optimal strategy from \(\textcolor{red}{\text{not_do}}\) to \(\textcolor{red}{\text{do}}\) before they could significantly affect the final result.</p>

<p>However, it’s worth noting that while tornado diagrams can technically be applied to any parameter, <strong>they’re most meaningful when applied to underlying variables</strong> that feed into the model through formulas rather than direct utility assignments.</p>

<h4 id="example-2-test-cost-sensitivity">Example 2: Test Cost Sensitivity</h4>

<p>Our second tornado analysis examines how changes in test cost affect the maximum expected utility. This variable would realistically vary based on market conditions, technology improvements, or operational 
factors. We evaluate the test cost parameter by applying a \(\pm25\) million dollar variation while keeping all other parameters constant.</p>

<center>
<table>
  <tr>
    <td align="center">
      <div id="tornado-plot-utility-test-cost" class="plotly-graph-div" style="height:400px; width:100%; max-width:700px;"></div>
      <script type="text/javascript">
      // Ensure syntax highlighting is preserved before creating test cost tornado plot
      document.addEventListener('DOMContentLoaded', function() {
        // Wait a bit longer to ensure previous plots and syntax highlighting are stable
        setTimeout(function() {
          if (typeof Plotly !== 'undefined') {
            window.PLOTLYENV = window.PLOTLYENV || {};
            Plotly.newPlot(
              "tornado-plot-utility-test-cost",
              [{"hoverinfo":"skip","marker":{"color":"lightcoral","line":{"color":"black","width":0.5}},"name":"Lower Impact","offsetgroup":"1","orientation":"h","width":0.6,"x":[0.0],"y":["Test Cost"],"type":"bar"},{"hoverinfo":"skip","marker":{"color":"lightblue","line":{"color":"black","width":0.5}},"name":"Higher Impact","offsetgroup":"1","orientation":"h","width":0.6,"x":[0.9500000000000455],"y":["Test Cost"],"type":"bar"},{"hovertemplate":"\n    Variable: Test Cost\u003cbr\u003e\n    High Cost (Cost: +25)\u003cbr\u003e\n    MEU: 721.00\u003cbr\u003e\n    Impact: +0.00\u003cbr\u003e\n    Optimal Decisions: T: not_do, B: [pass: buy, fail: buy, no_results: buy]\n    \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[0.0],"y":["Test Cost"],"type":"scatter"},{"hovertemplate":"\n    Variable: Test Cost\u003cbr\u003e\n    Low Cost (Cost: -25)\u003cbr\u003e\n    MEU: 721.95\u003cbr\u003e\n    Impact: +0.95\u003cbr\u003e\n    Optimal Decisions: T: do, B: [pass: buy, fail: not_buy, no_results: buy]\n    \u003cextra\u003e\u003c\u002fextra\u003e","marker":{"color":"rgba(0,0,0,0)","size":0.1},"mode":"markers","name":"","showlegend":false,"x":[0.47500000000002274],"y":["Test Cost"],"type":"scatter"}],
              {"template":{"data":{"histogram2dcontour":[{"type":"histogram2dcontour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"choropleth":[{"type":"choropleth","colorbar":{"outlinewidth":0,"ticks":""}}],"histogram2d":[{"type":"histogram2d","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"heatmap":[{"type":"heatmap","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"contourcarpet":[{"type":"contourcarpet","colorbar":{"outlinewidth":0,"ticks":""}}],"contour":[{"type":"contour","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"surface":[{"type":"surface","colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]}],"mesh3d":[{"type":"mesh3d","colorbar":{"outlinewidth":0,"ticks":""}}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"parcoords":[{"type":"parcoords","line":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolargl":[{"type":"scatterpolargl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"scattergeo":[{"type":"scattergeo","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterpolar":[{"type":"scatterpolar","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"scattergl":[{"type":"scattergl","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatter3d":[{"type":"scatter3d","line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermap":[{"type":"scattermap","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattermapbox":[{"type":"scattermapbox","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scatterternary":[{"type":"scatterternary","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"scattercarpet":[{"type":"scattercarpet","marker":{"colorbar":{"outlinewidth":0,"ticks":""}}}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}],"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"pie":[{"automargin":true,"type":"pie"}]},"layout":{"autotypenumbers":"strict","colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"hovermode":"closest","hoverlabel":{"align":"left"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"bgcolor":"#E5ECF6","angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"ternary":{"bgcolor":"#E5ECF6","aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]]},"xaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"yaxis":{"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","automargin":true,"zerolinewidth":2},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white","gridwidth":2}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"geo":{"bgcolor":"white","landcolor":"#E5ECF6","subunitcolor":"white","showland":true,"showlakes":true,"lakecolor":"white"},"title":{"x":0.05},"mapbox":{"style":"light"}}},"annotations":[{"font":{"size":12},"showarrow":false,"text":"0.0","x":-1.0,"xanchor":"left","y":"Test Cost"},{"font":{"size":12},"showarrow":false,"text":"1.0","x":1.0450000000000501,"xanchor":"left","y":"Test Cost"}],"shapes":[{"line":{"color":"black","width":2},"type":"line","x0":0,"x1":0,"xref":"x","y0":0,"y1":1,"yref":"y domain"}],"title":{"font":{"size":16},"text":"Test Cost Tornado Diagram\u003cbr\u003e\u003csub\u003eBaseline Expected Utility: 721.00 | Test cost varied by ±25 units\u003c\u002fsub\u003e"},"xaxis":{"title":{"text":"Change in Expected Utility from Baseline"},"gridcolor":"lightgray","gridwidth":0.5,"zeroline":true,"zerolinecolor":"black","zerolinewidth":2},"yaxis":{"title":{"text":"Variable"},"showticklabels":true},"legend":{"orientation":"h","yanchor":"bottom","y":1.02,"xanchor":"right","x":1},"width":700,"height":400,"bargap":0.1,"bargroupgap":0,"hovermode":"closest"},
              {"responsive": true}
            );
          }
        }, 600); // Longer delay for third plot to let previous ones settle
      });
      </script>
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 7.</b> Tornado diagram showing the impact of test cost variations on maximum expected utility</i>
    </td>
  </tr>
</table>
</center>

<p>The diagram shows that test cost has a limited impact on our decision strategy. Even with a substantial 83% cost reduction (from $30M to $5M), the optimal strategy remains virtually unchanged: the MEU increases from 721 million (not testing) to only 721.95 million (testing when it costs $5M), representing a marginal 0.13% improvement.</p>

<p>This suggests that <strong>cost reduction alone is insufficient</strong> to make testing attractive. To meaningfully shift our strategy toward testing, we would likely need either significant improvements in test reliability (as demonstrated in Example 2 of the single-parameter analysis) or a combination of cost reduction paired with enhanced test accuracy.</p>

<h3 id="interactive-gradio-interface-real-time-multi-parameter-exploration">Interactive Gradio Interface</h3>

<p><a href="https://www.gradio.app/"><code>Gradio</code></a> is an open-source Python library that lets you turn any machine-learning model, API, or plain Python function into a shareable web app in minutes. With its built-in hosting and share links, you can demo your project without writing a single line of JavaScript, CSS, or backend code.</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-08-07-decision-theory-III/gradio-gif.gif" alt="Gradio example" width="800" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 8.</b> Gradio example for image generation</i>
    </td>
  </tr>
</table>
</center>

<p>Although <a href="https://www.gradio.app/"><code>Gradio</code></a> first became popular for showcasing large-language-model and image-generation demos on Hugging Face Spaces, its simplicity is just as useful here. We’ll use the same drag-and-drop interface to create an interactive decision-analysis tool, proving that <a href="https://www.gradio.app/"><code>Gradio</code></a>’s convenience extends well beyond mainstream ML examples.</p>

<p>Single-parameter analyses and tornado diagrams show how each variable influences the model on its own. Real decisions, however, often involve several factors moving at once. To explore those multi-parameter scenarios, we can pair PyAgrum’s visualisation tools (see Figure 3) with <a href="https://www.gradio.app/"><code>Gradio</code></a>’s simple web-app builder to create an interactive playground.</p>

<p>An interactive app brings two key advantages:</p>
<ul>
  <li><strong>Real-time exploration</strong>: Adjust several parameters at once and immediately see how the optimal decision and expected utility change.</li>
  <li><strong>No technical hurdles</strong>: Executives and domain experts can experiment freely without touching the underlying PyAgrum code.</li>
</ul>

<h4 id="implementation-overview">Implementation Overview</h4>

<p>I have built a <a href="https://www.gradio.app/"><code>Gradio</code></a> app with three editable input tables: \(\textcolor{purple}{Q}\), \(\textcolor{purple}{R}\) and \(\textcolor{blue}{U}\). It then returns:</p>

<ul>
  <li><strong>Visual influence diagram</strong> with the optimal decision and MEU</li>
  <li><strong>Decision summary</strong> providing clear, natural language recommendations</li>
</ul>

<p>Here’s the high-level structure of the code:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">gradio</span> <span class="k">as</span> <span class="n">gr</span>
<span class="kn">import</span> <span class="nn">pyagrum</span> <span class="k">as</span> <span class="n">gum</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>

<span class="n">q_cpt</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">({</span>
    <span class="s">"Q"</span><span class="p">:</span> <span class="p">[</span><span class="s">"high"</span><span class="p">,</span> <span class="s">"medium"</span><span class="p">,</span> <span class="s">"low"</span><span class="p">],</span>
    <span class="s">"Probability"</span><span class="p">:</span> <span class="p">[</span><span class="mf">0.35</span><span class="p">,</span> <span class="mf">0.45</span><span class="p">,</span> <span class="mf">0.2</span><span class="p">]</span>
<span class="p">})</span>

<span class="n">r_cpt</span>  <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span>
  <span class="p">...</span>
<span class="p">)</span>

<span class="n">u_table</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span>
  <span class="p">...</span>
<span class="p">)</span>

<span class="k">def</span> <span class="nf">analyze_decision</span><span class="p">(</span><span class="n">q_probabilities</span><span class="p">,</span> <span class="n">r_probabilities</span><span class="p">,</span> <span class="n">utilities</span><span class="p">):</span>
    <span class="c1"># Create influence diagram with user parameters
</span>    <span class="n">influence_diagram</span> <span class="o">=</span> <span class="n">create_influence_diagram</span><span class="p">(</span><span class="n">q_probabilities</span><span class="p">,</span> <span class="n">r_probabilities</span><span class="p">,</span> <span class="n">utilities</span><span class="p">)</span>
    
    <span class="c1"># Solve using PyAgrum inference engine  
</span>    <span class="n">inference_engine</span> <span class="o">=</span> <span class="n">gum</span><span class="p">.</span><span class="n">ShaferShenoyLIMIDInference</span><span class="p">(</span><span class="n">influence_diagram</span><span class="p">)</span>
    <span class="n">inference_engine</span><span class="p">.</span><span class="n">makeInference</span><span class="p">()</span>
    
    <span class="c1"># Generate visualization and recommendations
</span>    <span class="n">diagram_image</span> <span class="o">=</span> <span class="n">generate_diagram_visualization</span><span class="p">(</span><span class="n">influence_diagram</span><span class="p">,</span> <span class="n">inference_engine</span><span class="p">)</span>
    <span class="n">decision_summary</span> <span class="o">=</span> <span class="n">generate_policy_summary</span><span class="p">(</span><span class="n">influence_diagram</span><span class="p">,</span> <span class="n">inference_engine</span><span class="p">)</span>
    
    <span class="k">return</span> <span class="n">diagram_image</span><span class="p">,</span> <span class="n">decision_summary</span>

<span class="c1"># Create Gradio interface with interactive components
</span><span class="k">with</span> <span class="n">gr</span><span class="p">.</span><span class="n">Blocks</span><span class="p">()</span> <span class="k">as</span> <span class="n">demo</span><span class="p">:</span>
    <span class="c1"># Input components for probabilities and utilities
</span>    <span class="n">q_input</span> <span class="o">=</span> <span class="n">gr</span><span class="p">.</span><span class="n">Dataframe</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s">"Oil Field Quality Probabilities"</span><span class="p">)</span>
    <span class="n">r_input</span> <span class="o">=</span> <span class="n">gr</span><span class="p">.</span><span class="n">Dataframe</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s">"Test Result Probabilities"</span><span class="p">)</span> 
    <span class="n">u_input</span> <span class="o">=</span> <span class="n">gr</span><span class="p">.</span><span class="n">Dataframe</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s">"Utility Values"</span><span class="p">)</span>
    
    <span class="c1"># Output components
</span>    <span class="n">diagram_output</span> <span class="o">=</span> <span class="n">gr</span><span class="p">.</span><span class="n">Image</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s">"Influence Diagram"</span><span class="p">)</span>
    <span class="n">summary_output</span> <span class="o">=</span> <span class="n">gr</span><span class="p">.</span><span class="n">Textbox</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s">"Decision Recommendations"</span><span class="p">)</span>
    
    <span class="c1"># Connect inputs to analysis function
</span>    <span class="n">calculate_btn</span> <span class="o">=</span> <span class="n">gr</span><span class="p">.</span><span class="n">Button</span><span class="p">(</span><span class="s">"Calculate Optimal Decision"</span><span class="p">)</span>
    <span class="n">calculate_btn</span><span class="p">.</span><span class="n">click</span><span class="p">(</span><span class="n">analyze_decision</span><span class="p">,</span> 
                       <span class="n">inputs</span><span class="o">=</span><span class="p">[</span><span class="n">q_input</span><span class="p">,</span> <span class="n">r_input</span><span class="p">,</span> <span class="n">u_input</span><span class="p">],</span>
                       <span class="n">outputs</span><span class="o">=</span><span class="p">[</span><span class="n">diagram_output</span><span class="p">,</span> <span class="n">summary_output</span><span class="p">])</span>

<span class="n">demo</span><span class="p">.</span><span class="n">launch</span><span class="p">(</span><span class="n">share</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
<a href="https://github.com/ferjorosa/decision-theory-llms/tree/main/decision_problems/oil_field_purchase/gradio_app">You can find  the complete source code for this implementation on GitHub</a>
</div>
<div style="height: 1.1em;"></div>

<h4 id="live-interactive-interface">Demo</h4>

<p>I have deployed the Gradio application using <a href="https://huggingface.co/docs/hub/spaces-overview">Hugging Face spaces</a>. Try adjusting different parameters to see how they affect the optimal strategy and expected utility:</p>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
If after 10 seconds or so you don't see the loaded application, <a href="https://huggingface.co/spaces/ferjorosa/oil-field-purchase-decision"><b>you can go here and restart the space</b></a>. It is a public HuggingFace space so you dont need permissions to restart it.
</div>
<div style="height: 1.1em;"></div>

<script type="text/javascript">
// Preserve page formatting and prevent Gradio CSS interference
function preservePageFormatting() {
  // Store original styles for key elements
  var originalStyles = new Map();
  
  // Elements to protect from Gradio CSS changes
  var protectedSelectors = [
    '.post-content p',
    '.post-content h1, .post-content h2, .post-content h3, .post-content h4, .post-content h5, .post-content h6',
    '.post-content li',
    '.post-content blockquote',
    '.highlight',
    'body'
  ];
  
  // Store original computed styles
  protectedSelectors.forEach(function(selector) {
    var elements = document.querySelectorAll(selector);
    elements.forEach(function(element) {
      var computedStyle = window.getComputedStyle(element);
      originalStyles.set(element, {
        lineHeight: computedStyle.lineHeight,
        fontSize: computedStyle.fontSize,
        fontFamily: computedStyle.fontFamily,
        margin: computedStyle.margin,
        padding: computedStyle.padding
      });
    });
  });
  
  // Store highlighted code blocks and their HTML
  var highlightedBlocks = document.querySelectorAll('.highlight');
  var preservedHTML = [];
  
  highlightedBlocks.forEach(function(block, index) {
    preservedHTML[index] = block.innerHTML;
  });
  
  // Function to restore both syntax highlighting and original formatting
  function restoreFormatting() {
    // Restore syntax highlighting
    var currentBlocks = document.querySelectorAll('.highlight');
    currentBlocks.forEach(function(block, index) {
      if (preservedHTML[index] && block.innerHTML !== preservedHTML[index]) {
        block.innerHTML = preservedHTML[index];
      }
    });
    
    // Restore original styles
    originalStyles.forEach(function(styles, element) {
      if (document.contains(element)) {
        element.style.lineHeight = styles.lineHeight;
        element.style.fontSize = styles.fontSize;
        element.style.fontFamily = styles.fontFamily;
        // Only restore margin/padding if significantly changed
        var currentStyle = window.getComputedStyle(element);
        if (Math.abs(parseFloat(currentStyle.margin) - parseFloat(styles.margin)) > 5) {
          element.style.margin = styles.margin;
        }
      }
    });
  }
  
  return restoreFormatting;
}

// Isolate Gradio loading and prevent CSS conflicts
function loadGradioIsolated() {
  // Create shadow DOM for better isolation (if supported)
  var container = document.getElementById('gradio-container');
  
  // Add extra protection class
  container.classList.add('gradio-isolated');
  
  // Create style isolation
  var isolationStyle = document.createElement('style');
  isolationStyle.textContent = `
    .gradio-isolated {
      /* Create containment boundary */
      contain: layout style;
      /* Isolate font changes */
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
      /* Reset line height */
      line-height: 1.4;
    }
    
    /* Prevent Gradio from affecting parent elements */
    .gradio-isolated * {
      box-sizing: border-box;
    }
    
    /* Additional protection for surrounding content */
    body:not(.gradio-isolated) .post-content {
      line-height: 1.6 !important;
      font-family: inherit !important;
    }
  `;
  
  document.head.appendChild(isolationStyle);
  
  // Load Gradio with isolation
  var script = document.createElement('script');
  script.type = 'module';
  script.src = 'https://gradio.s3-us-west-2.amazonaws.com/5.31.0/gradio.js';
  
  // Apply additional isolation on load
  script.onload = function() {
    var gradioApp = document.createElement('gradio-app');
    gradioApp.setAttribute('src', 'https://ferjorosa-oil-field-purchase-decision.hf.space');
    container.appendChild(gradioApp);
    
    // Apply final isolation styles
    setTimeout(function() {
      gradioApp.style.contain = 'layout style';
      gradioApp.style.isolation = 'isolate';
    }, 100);
  };
  
  document.head.appendChild(script);
}

// Wait for page to be fully loaded
window.addEventListener('load', function() {
  setTimeout(function() {
    // Preserve page formatting first
    var restoreFunction = preservePageFormatting();
    
    // Load Gradio with isolation
    loadGradioIsolated();
    
    // Monitor and restore formatting periodically
    var restoreInterval = setInterval(restoreFunction, 200);
    
    // Stop aggressive restoration after 15 seconds
    setTimeout(function() {
      clearInterval(restoreInterval);
      // Do a final restoration
      restoreFunction();
    }, 15000);
    
    // Also restore on window resize (common trigger for style changes)
    window.addEventListener('resize', restoreFunction);
    
  }, 500);
});
</script>

<div id="gradio-container"></div>

<h2 id="conclusion-building-robust-decision-strategies">Conclusion</h2>

<p>This post concludes our introductory series on decision theory. We’ve explored everything from manual decision trees to programmatic influence diagrams, demonstrating how <a href="https://pyagrum.readthedocs.io"><code>PyAgrum</code></a> can solve real-world problems in milliseconds. More importantly, we’ve shown how sensitivity analysis helps us test whether our decisions are truly robust.</p>

<p>We covered three key approaches: single-parameter analysis, tornado diagrams, and <a href="https://www.gradio.app/"><code>Gradio</code></a> interfaces, each serving a unique purpose. Through these methods, we uncovered an important insight: while changing parameters often affects expected utilities, it doesn’t always change the optimal decision. Recognizing the difference between sensitivity in outcomes and sensitivity in decisions is crucial for practical decision-making.</p>

<p>Looking ahead, <strong>I’m optimistic about integrating Large Language Models (LLMs) with influence diagrams</strong> to enhance decision-making. Here’s how this could unfold:</p>

<ul>
  <li>
    <p><strong>Short-term goal</strong>: Combine LLMs with predefined influence diagrams to improve decision quality, helping generate more rational and data-driven choices.</p>
  </li>
  <li>
    <p><strong>Long-term goal</strong>: Enable LLMs to automatically build decision models from natural language descriptions, generate sensitivity analysis code, and highlight the most critical parameters based on domain expertise.</p>
  </li>
</ul>

<p>We’ll dive deeper into these possibilities in a future post, so stay tuned!</p>

<h2 id="references">References</h2>
<ol>
  <li>Rodriguez, F. (2025, June 8). <a href="https://ferjorosa.github.io/blog/2025/06/08/decision-theory-I.html">Introduction to decision theory: Part I</a>. 
<br /><br /></li>
  <li>Rodriguez, F. (2025, July 4). <a href="https://ferjorosa.github.io/blog/2025/07/04/decision-theory-II.html">Introduction to decision theory: Part II</a>. 
<br /><br /></li>
  <li>Shafer, G., &amp; Shenoy, P. P. (1990). <a href="https://kuscholarworks.ku.edu/server/api/core/bitstreams/c353aa52-11ad-46c0-b867-f5d05f7f1962/content"><u>Probability Propagation</u></a>. Annals of Mathematics and Artificial Intelligence, 2, 327-352.
<br /><br /></li>
  <li>Wikipedia article on <a href="https://en.wikipedia.org/wiki/Tornado_diagram"><u>tornado diagrams</u></a>.
<br /><br /></li>
  <li>Hugging Face documentation page on <a href="https://huggingface.co/docs/hub/spaces-overview">spaces</a>.</li>
</ol>]]></content><author><name>Fernando Rodriguez</name></author><category term="blog" /><category term="Decision Theory" /><summary type="html"><![CDATA[Deep dive into sensitivity analysis for decision problems, implementing the oil field purchase decision using PyAgrum's library, and creating an interactive web interface with Gradio to explore how changes in probabilities and utilities affect optimal decisions.]]></summary></entry><entry><title type="html">Introduction to Decision Theory: Part II</title><link href="https://ferjorosa.github.io/blog/2025/07/04/decision-theory-II.html" rel="alternate" type="text/html" title="Introduction to Decision Theory: Part II" /><published>2025-07-04T00:00:00+00:00</published><updated>2025-07-04T00:00:00+00:00</updated><id>https://ferjorosa.github.io/blog/2025/07/04/decision-theory-II</id><content type="html" xml:base="https://ferjorosa.github.io/blog/2025/07/04/decision-theory-II.html"><![CDATA[<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">
<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">Table of Contents</summary>

<ul style="margin-top: 0.5em;">
  <li style="margin-bottom: 0.5em;"><a href="#decision-trees-strengths-limitations">Strengths and Limitations of Decision Trees</a>
    <ul style="margin-top: 0.3em;">
      <li style="margin-bottom: 0.3em;"><a href="#combinatorial-explosion">Combinatorial Explosion</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#hidden-independence">Hidden Conditional Independencies</a></li>
    </ul>
  </li>
  <li style="margin-bottom: 0.5em;"><a href="#decision_networks">Influence Diagrams</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#modelling_oil_problem">Modelling the Oil Field Decision Problem</a>
    <ul style="margin-top: 0.3em;">
      <li style="margin-bottom: 0.3em;"><a href="#modelling_oil_problem_qualitative">Modelling Qualitative Information</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#modelling_oil_problem_quantitative">Modelling Quantitative Information</a></li>
    </ul>
  </li>
  <li style="margin-bottom: 0.5em;"><a href="#evaluating_influence_diagram">Influence Diagram Evaluation</a>
    <ul style="margin-top: 0.3em;">
      <li style="margin-bottom: 0.3em;"><a href="#local-graph-operations">Four Local Graph Operations</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#node-reduction-algorithm">The Arc-Reversal / Node-Reduction Algorithm</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#relationship-to-bayesian-network-elimination">Relationship to Bayesian Network Variable Elimination</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#related-work-evaluation">Related Work</a></li>
    </ul>
  </li>
  <li style="margin-bottom: 0.5em;"><a href="#evaluating-oil-influence-diagram">Evaluating the Oil Influence Diagram</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#influence-diagram-libraries">Influence Diagram Libraries</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#conclusion">Conclusion</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#references">References</a></li>
</ul>

</details>

<h2 id="decision-trees-strengths-limitations">Strengths and Limitations of Decision Trees</h2>

<p>Decision trees provide a straightforward way to model decisions under uncertainty. Each path from start to finish shows a sequence of choices and events that lead to a specific outcome. The directed layout makes the timing of decisions and chance events visually clear, helping to avoid confusion about what is known at each point.</p>

<p>For small problems with only a few stages, decision trees can be evaluated using basic arithmetic. This simplicity makes them accessible to a wide audience, including those without technical training. They serve as effective tools for teaching, storytelling, and supporting real-world decisions.</p>

<p>Yet this intuitive structure comes with notable drawbacks. One issue is the risk of combinatorial explosion. Another limitation is that decision trees do not explicitly show conditional independencies.</p>

<h3 id="combinatorial-explosion">Combinatorial Explosion</h3>
<p>The memory required to store a decision tree and the time required to process it both <strong>increase
exponentially</strong> with the number of variables and their possible states, whether they are decisions or
probabilistic outcomes. In a symmetric problem with \(n\) variables, each having \(k\) possible outcomes, you face \(k^{n}\) distinct paths. Since a decision tree represents all scenarios explicitly, a problem with 50 binary variables would yield an impractical \(2^{50}\) paths (<a href="https://pshenoy.ku.edu/Papers/EOLSS09.pdf"><u>Shenoy, 2009</u></a>).</p>

<p>The number of decision paths is profoundly affected by the order and meaning of the variables (i.e., the problem’s definition). In our original oil field decision problem from <a href="https://ferjorosa.github.io/blog/2025/06/08/decision-theory-I.html"><u>Part I</u></a>, the options <span style="color:red;">Do not perform test</span> and <span style="color:red;">Do not buy</span> prune the tree, resulting in 12 distinct decision paths. This is an <em>asymmetric</em> problem structure:</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-07-04-decision-theory-II/1_oil_asymmetric_tree_annotated.png" alt="Decision tree diagram of the asymmetric oil problem from Part I" height="240" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 1.</b> Decision tree diagram of the asymmetric oil field investment problem from Part I.</i>
    </td>
  </tr>
</table>
</center>

<p>Conversely, a problem with the same types of variables, but structured <em>symmetrically</em>, would yield significantly more paths. For example, suppose the company must always begin by performing one of two possible geological tests (such as <span style="color:red;">Test X</span> or <span style="color:red;">Test Y</span>, each with different costs and accuracy profiles) on the field. Based on the test result, the company then chooses whether to <span style="color:red;">Invest in Field A</span> or <span style="color:red;">Invest in Field B</span>. After the investment decision, drilling reveals the field’s quality. This structure forces every path to be fully explored, doubling the number of distinct paths from 12 to 24:</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-07-04-decision-theory-II/2_oil_symmetric_tree_annotated.png" alt="Decision tree diagram of a hypothetical symmetric oil problem" height="240" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 2.</b> Decision tree diagram of a hypothetical symmetric oil field investment problem.</i>
    </td>
  </tr>
</table>
</center>

<p>Even this revised example demonstrates how swiftly a decision tree can escalate beyond practical use. For instance, merely replacing the three-level oil quality (<span style="color:purple;">high</span>/<span style="color:purple;">medium</span>/<span style="color:purple;">low</span>) with a more granular five-level scale (<span style="color:purple;">excellent</span>/<span style="color:purple;">good</span>/<span style="color:purple;">average</span>/<span style="color:purple;">poor</span>/<span style="color:purple;">dry</span>) would push the total from 24 to 40 terminal nodes. This occurs without even considering longer time horizons, dynamic market-price scenarios, or additional complex choices.</p>

<p>This <strong>combinatorial explosion</strong> not only affects computational tractability but, even at more modest levels, severely compromises interpretability. As a rule of thumb, once a tree approaches about 100 terminal nodes, it loses its key strength: easy readability and intuitive understanding.</p>

<h3 id="hidden-independence">Hidden Conditional Independencies</h3>

<p>In addition to the issue of combinatorial explosion, decision trees have another important limitation: they assume a strict, linear chain of dependence. In a decision tree, every variable is implicitly conditioned on <strong>all</strong> previous events along its particular path. This rigid structure prevents us from explicitly representing one of the most important concepts in probabilistic modeling: <b><a href="https://en.wikipedia.org/wiki/Conditional_independence"><u>conditional independence</u></a></b>.</p>

<p>To illustrate this, consider a generic problem with four random variables: \(\textcolor{purple}{A}\) and \(\textcolor{purple}{B}\) (each with two possible states, \(\textcolor{purple}{a_1}, \textcolor{purple}{a_2}\) and \(\textcolor{purple}{b_1}, \textcolor{purple}{b_2}\), respectively), and \(\textcolor{purple}{C}\) and \(\textcolor{purple}{D}\) (each with three possible states, \(\textcolor{purple}{c_1}, \textcolor{purple}{c_2}, \textcolor{purple}{c_3}\) and \(\textcolor{purple}{d_1}, \textcolor{purple}{d_2}, \textcolor{purple}{d_3}\)). In a traditional decision tree, where conditional independencies cannot be explicitly represented, you must specify the entire joint probability distribution for all variables. This means assigning a probability to every possible combination of outcomes, as shown in the joint probability table below:</p>

<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">

<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">P(<span style="color:purple;">A</span>, <span style="color:purple;">B</span>, <span style="color:purple;">C</span>, <span style="color:purple;">D</span>)</summary>


<table>
  <thead>
    <tr>
      <th>$$\textcolor{purple}{A}$$</th>
      <th>$$\textcolor{purple}{B}$$</th>
      <th>$$\textcolor{purple}{C}$$</th>
      <th>$$\textcolor{purple}{D}$$</th>
      <th style="text-align: center;">Probability</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{1}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{1}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{2}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}},\textcolor{purple}{b_{2}},\textcolor{purple}{c_{3}},\textcolor{purple}{d_{3}})$$</td>
    </tr>
  </tbody>
</table>

</details>

<p><strong>Total distinct probabilities:</strong> \(2 \; (\text{for } \textcolor{purple}{A}) \cdot 2 \; (\text{for } \textcolor{purple}{B}) \cdot 3 \; (\text{for } \textcolor{purple}{C}) \cdot 3 \; (\text{for } \textcolor{purple}{D}) = \mathbf{36}\).</p>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
  This example demonstrates conditional independencies using a simplified version of a decision tree, where all nodes are probabilistic (often called a <a href="https://en.wikipedia.org/wiki/Tree_diagram_(probability_theory)"><u>probability tree</u></a>). However, the core concepts and benefits of explicit conditional independence representation apply equally to the chance nodes of any general decision tree.
</div>
<div style="height: 1.1em;"></div>

<p>Now, let’s say that conditional independencies do exist in this problem. For instance, let’s say that \(\textcolor{purple}{B}\) is conditionally independent of \(\textcolor{purple}{C}\) and \(\textcolor{purple}{D}\) given \(\textcolor{purple}{A}\). We denote that statement by \((\textcolor{purple}{B} \bot \{\textcolor{purple}{C}, \textcolor{purple}{D}\} \mid \textcolor{purple}{A})\). In that case:</p>

\[P(\textcolor{purple}{B} \mid \textcolor{purple}{A}, \textcolor{purple}{C}, \textcolor{purple}{D}) = P(\textcolor{purple}{B} \mid \textcolor{purple}{A})\]

<p>This fundamental concept allows us to represent relationships far more efficiently. Consider Figure 3, which implies the following conditional independence statements:</p>
<ul>
  <li> \((\textcolor{purple}{B} \bot \{\textcolor{purple}{C}, \textcolor{purple}{D}\} \mid \textcolor{purple}{A})\)</li>
  <li> \((\textcolor{purple}{C} \bot \textcolor{purple}{B} \mid \textcolor{purple}{A})\)</li>
  <li> \((\textcolor{purple}{D} \bot \{\textcolor{purple}{A},\textcolor{purple}{B}\} \mid \textcolor{purple}{C})\)</li>
</ul>

<p>The diagram corresponds to the directed acyclic graph of a <a href="https://en.wikipedia.org/wiki/Bayesian_network"><u>Bayesian network</u></a>, which visually encodes these independencies: arrows indicate direct probabilistic influence, while the absence of an arrow between two nodes reflects a conditional independence given their parents.</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-07-04-decision-theory-II/3_bayesian_network_example.png" alt="Decision tree diagram of a hypothetical symmetric oil problem" height="300" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 3.</b> Bayesian network illustrating conditional independencies among A, B, C, and D.</i>
    </td>
  </tr>
</table>
</center>

<p>When these conditional independencies are recognized and modeled, we no longer need to construct a single large joint probability table. Instead, the full joint probability distribution can be factored into a product of smaller, more manageable conditional probability tables (CPTs). In our example, this means we only need to specify:</p>

<ul>
  <li> \(P(\textcolor{purple}{A}) \rightarrow 2 = 2\) entries</li>
  <li> \(P(\textcolor{purple}{B} \mid \textcolor{purple}{A}) \rightarrow 2 \cdot 2 = 4\) entries</li>
  <li> \(P(\textcolor{purple}{C} \mid \textcolor{purple}{A}) \rightarrow 2 \cdot 3 = 6\) entries</li>
  <li> \(P(\textcolor{purple}{D} \mid \textcolor{purple}{C}) \rightarrow 3 \cdot 3 = 9\) entries</li>
</ul>

<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">

<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">P(<span style="color:purple;">A</span>)</summary>

<table>
  <thead>
    <tr>
      <th>$$\textcolor{purple}{A}$$</th>
      <th style="text-align: center;">Probability</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$P(\textcolor{purple}{a_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$P(\textcolor{purple}{a_{2}})$$</td>
    </tr>
  </tbody>
</table>

</details>

<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">

<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">P(<span style="color:purple;">B</span> | <span style="color:purple;">A</span>)</summary>

<table>
  <thead>
    <tr>
      <th>$$\textcolor{purple}{A}$$</th>
      <th>$$\textcolor{purple}{B}$$</th>
      <th style="text-align: center;">Probability</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$P(\textcolor{purple}{b_{1}} \mid \textcolor{purple}{a_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$P(\textcolor{purple}{b_{2}} \mid \textcolor{purple}{a_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{1}}$$</td>
      <td>$$P(\textcolor{purple}{b_{1}} \mid \textcolor{purple}{a_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{b_{2}}$$</td>
      <td>$$P(\textcolor{purple}{b_{2}} \mid \textcolor{purple}{a_{2}})$$</td>
    </tr>
  </tbody>
</table>

</details>

<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">

<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">P(<span style="color:purple;">C</span> | <span style="color:purple;">A</span>)</summary>

<table>
  <thead>
    <tr>
      <th>$$\textcolor{purple}{A}$$</th>
      <th>$$\textcolor{purple}{C}$$</th>
      <th style="text-align: center;">Probability</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$P(\textcolor{purple}{c_{1}} \mid \textcolor{purple}{a_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$P(\textcolor{purple}{c_{2}} \mid \textcolor{purple}{a_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{1}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$P(\textcolor{purple}{c_{3}} \mid \textcolor{purple}{a_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$P(\textcolor{purple}{c_{1}} \mid \textcolor{purple}{a_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$P(\textcolor{purple}{c_{2}} \mid \textcolor{purple}{a_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{a_{2}}$$</td>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$P(\textcolor{purple}{c_{3}} \mid \textcolor{purple}{a_{2}})$$</td>
    </tr>
  </tbody>
</table>

</details>

<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">

<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">P(<span style="color:purple;">D</span> | <span style="color:purple;">C</span>)</summary>

<table>
  <thead>
    <tr>
      <th>$$\textcolor{purple}{C}$$</th>
      <th>$$\textcolor{purple}{D}$$</th>
      <th style="text-align: center;">Probability</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{d_{1}} \mid \textcolor{purple}{c_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{d_{2}} \mid \textcolor{purple}{c_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{c_{1}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{d_{3}} \mid \textcolor{purple}{c_{1}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{d_{1}} \mid \textcolor{purple}{c_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{d_{2}} \mid \textcolor{purple}{c_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{c_{2}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{d_{3}} \mid \textcolor{purple}{c_{2}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{1}}$$</td>
      <td>$$P(\textcolor{purple}{d_{1}} \mid \textcolor{purple}{c_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{2}}$$</td>
      <td>$$P(\textcolor{purple}{d_{2}} \mid \textcolor{purple}{c_{3}})$$</td>
    </tr>
    <tr>
      <td>$$\textcolor{purple}{c_{3}}$$</td>
      <td>$$\textcolor{purple}{d_{3}}$$</td>
      <td>$$P(\textcolor{purple}{d_{3}} \mid \textcolor{purple}{c_{3}})$$</td>
    </tr>
  </tbody>
</table>

</details>

<p><strong>Total distinct probabilities:</strong> \(2 + 4 + 6 + 9 = \mathbf{21}\).</p>

<p>This represents a <strong>42% decrease</strong> from the 36 entries required in the full joint probability table. By reducing the number of parameters that must be specified, the model becomes much more manageable, transparent, and easier to modify. As decision problems increase in complexity, the advantages of explicitly modeling conditional independencies grow even more significant.</p>

<h2 id="decision_networks">Influence Diagrams</h2>

<p>Building on the foundation of Bayesian networks, <strong>influence diagrams</strong> (<a href=""><u>Howard &amp; Matheson, 1984</u></a>), also known as <strong>decision networks</strong>, provide a powerful extension that seamlessly integrates decision-making into probabilistic models. Unlike decision trees, influence diagrams avoid combinatorial explosion by factorizing the joint probability distribution and naturally express conditional independencies through their graphical structure.</p>

<p>An influence diagram enhances a Bayesian network by adding two types of nodes:</p>

<ul>
  <li><span style="color:red;"><b>Decision nodes</b></span>: Shown as squares, these represent points where the decision-maker chooses among available actions.</li>
  <li><span style="color:blue;"><b>Outcome nodes</b></span>: Illustrated as diamonds, these indicate the resulting utilities or values associated with different decision paths.</li>
</ul>

<p><span style="color:purple;"><b>Chance nodes</b></span> (circles) function as in Bayesian networks; when they are categorical, they are described by CPTs.</p>

<p>In influence diagrams, arcs serve two main purposes: <strong>informational arcs</strong> (into decision nodes) indicate what information is available when a choice is made, while <strong>conditional arcs</strong> (into chance or utility nodes) represent probabilistic or functional dependencies on parent variables, showing which factors affect outcomes or payoffs, without implying causality or temporal order.</p>

<h2 id="modelling_oil_problem">Modelling the Oil Field Decision Problem</h2>

<p>Modeling takes place at multiple levels. Drawing the influence diagram, much like constructing a decision tree, represents the qualitative description of the problem (structural level). Next, quantitative information is incorporated (numerical level) to fully specify the model.</p>

<p>A key limitation of influence diagrams is that <strong>they are only designed to handle symmetric problems</strong>. When faced with an asymmetric problem, it is necessary to transform it into a symmetric one, typically by introducing <em>artificial</em> states (which may be unintuitive). This transformation increases the size and complexity of the model, resulting in greater computational demands.</p>

<p>In large and highly asymmetric problems, using these resources (artificial states, degenerate probabilities, and utilities) to convert them into an equivalent symmetric one is not straightforward. For more information on this topic, see <a href="https://cig.fi.upm.es/wp-content/uploads/2024/01/A-Comparison-of-Graphical-Techniques-for-Asymmetric-Decision-Problems.pdf"><u>Bielza &amp; Shenoy (1999)</u></a>.</p>

<p>To model the oil field decision problem, we will use a standard influence diagram. To maintain problem symmetry, an extra state called <span style="color:purple;">no results</span> should be added to the porosity test results variable (<span style="color:purple;"><b>R</b></span>), since results are only observed when the test is performed.</p>

<h3 id="modelling_oil_problem_qualitative">Modelling Qualitative Information</h3>

<p>The following image displays the influence diagram structure for the decision problem:</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-07-04-decision-theory-II/4_influence_diagram_oil.png" alt="Influence diagram structure of the asymmetric oil problem from Part I" width="320" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 4.</b> Influence diagram for the oil field decision problem. Informational arcs are displayed with dashes.</i>
    </td>
  </tr>
</table>
</center>

<p>This diagram illustrates a traditional influence diagram, which operates under the assumption of perfect recall. The information arcs indicate that the Test / No Test (\(\textcolor{red}{T}\)) decision is made prior to the Buy / No Buy (\(\textcolor{red}{B}\)) decision. Furthermore, no information is available before making the test decision, and the test results (\(\textcolor{purple}{R}\)) are known when making the buy decision. This establishes the temporal sequence of variables: \(\textcolor{red}{T}\), \(\textcolor{purple}{R}\), \(\textcolor{red}{B}\), and finally \(\textcolor{purple}{Q}\) (oil field quality).</p>

<p>However, traditional influence diagrams can become computationally complex to solve, particularly for intricate problems, and they may not accurately reflect the realistic limitations of human decision-making. For these reasons, LIMIDs (<a href="https://web.math.ku.dk/~lauritzen/papers/limids.pdf"><u>Lauritzen &amp; Nilsson, 2001</u></a>) are often the preferred choice. These models relax the perfect recall assumption and allow for explicit representation of limited memory. Memory arcs in LIMIDs explicitly specify which past decisions and observations are remembered and used for each current decision.</p>

<p>The subsequent image presents the corresponding LIMID, enhanced with a green memory arc. This memory arc extends from \(\textcolor{red}{T}\) to \(\textcolor{red}{B}\) because the outcome of the porosity test decision is crucial for the subsequent decision on buying or not buying the field.</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-07-04-decision-theory-II/5_limid_oil.png" alt="Influence diagram structure of the asymmetric oil problem from Part I" width="320" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 5.</b> LIMID for the oil field decision problem with a memory arc shown in green.</i>
    </td>
  </tr>
</table>
</center>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
For this problem, we will utilize the LIMID version of the oil decision problem.
</div>
<div style="height: 1.1em;"></div>

<h3 id="modelling_oil_problem_quantitative">Modelling Quantitative Information</h3>

<p>Since all our random variables are categorical, we can conveniently represent the quantitative information of the model in tabular form. Below, we specify the prior probabilities, the CPTs, and the utility values relevant to the oil field decision problem.</p>

<p>Prior probabilities for the oil field quality (\(\textcolor{purple}{Q}\)):</p>

<table>
  <tr>
    <th colspan="2" style="text-align: center;">$$P(\textcolor{purple}{Q})$$</th>
  </tr>
  <tr>
    <td><span style="color: purple;">high</span></td>
    <td>0.35</td>
  </tr>
  <tr>
    <td><span style="color: purple;">medium</span></td>
    <td>0.45</td>
  </tr>
  <tr>
    <td><span style="color: purple;">low</span></td>
    <td>0.2</td>
  </tr>
</table>

<p>Conditional probabilities of observing each possible test result \(\textcolor{purple}{R}\), given the true oil field quality \(\textcolor{purple}{Q}\) and whether the test was performed \(\textcolor{red}{T}\):</p>

<table>
  <tr>
    <th rowspan="2" style="text-align: center;">$$P(\textcolor{purple}{R} \mid \textcolor{purple}{Q},\, \textcolor{red}{T})$$</th>
    <th colspan="3" style="text-align: center;"><span style="color: red;">perform</span></th>
    <th colspan="3" style="text-align: center;"><span style="color: red;">no perform</span></th>
  </tr>
  <tr>
    <th style="text-align: center;"><span style="color: purple;">high</span></th>
    <th style="text-align: center;"><span style="color: purple;">medium</span></th>
    <th style="text-align: center;"><span style="color: purple;">low</span></th>
    <th style="text-align: center;"><span style="color: purple;">high</span></th>
    <th style="text-align: center;"><span style="color: purple;">medium</span></th>
    <th style="text-align: center;"><span style="color: purple;">low</span></th>
  </tr>
  <tr>
    <td><span style="color: purple;">pass</span></td>
    <td>0.95</td>
    <td>0.7</td>
    <td>0.15</td>
    <td>0</td>
    <td>0</td>
    <td>0</td>
  </tr>
  <tr>
    <td><span style="color: purple;">fail</span></td>
    <td>0.05</td>
    <td>0.3</td>
    <td>0.85</td>
    <td>0</td>
    <td>0</td>
    <td>0</td>
  </tr>
  <tr>
    <td><span style="color: purple;">no results</span></td>
    <td>0</td>
    <td>0</td>
    <td>0</td>
    <td>1</td>
    <td>1</td>
    <td>1</td>
  </tr>
</table>

<p>Utility (<b><span style="color: blue;">U</span></b>) for each combination of test decision (<b><span style="color: red;">T</span></b>), buy decision (<b><span style="color: red;">B</span></b>), and oil field quality (<b><span style="color: purple;">Q</span></b>):</p>

<table>
  <tr>
    <th style="text-align: center;">$$\textcolor{red}{T}$$</th>
    <th style="text-align: center;">$$\textcolor{red}{B}$$</th>
    <th style="text-align: center;">$$\textcolor{purple}{Q}$$</th>
    <th style="text-align: center;">$$\textcolor{blue}{U}$$</th>
  </tr>
  <tr>
    <td rowspan="6"><span style="color: red;">perform</span></td>
    <td rowspan="3"><span style="color: red;">buy</span></td>
    <td><span style="color: purple;">high</span></td>
    <td><span style="color: blue;">1220</span></td>
  </tr>
  <tr>
    <td><span style="color: purple;">medium</span></td>
    <td><span style="color: blue;">600</span></td>
  </tr>
  <tr>
    <td><span style="color: purple;">low</span></td>
    <td><span style="color: blue;">-30</span></td>
  </tr>
  <tr>
    <td rowspan="3"><span style="color: red;">no buy</span></td>
    <td><span style="color: purple;">high</span></td>
    <td><span style="color: blue;">320</span></td>
  </tr>
  <tr>
    <td><span style="color: purple;">medium</span></td>
    <td><span style="color: blue;">320</span></td>
  </tr>
  <tr>
    <td><span style="color: purple;">low</span></td>
    <td><span style="color: blue;">320</span></td>
  </tr>
  <tr>
    <td rowspan="6"><span style="color: red;">no perform</span></td>
    <td rowspan="3"><span style="color: red;">buy</span></td>
    <td><span style="color: purple;">high</span></td>
    <td><span style="color: blue;">1250</span></td>
  </tr>
  <tr>
    <td><span style="color: purple;">medium</span></td>
    <td><span style="color: blue;">630</span></td>
  </tr>
  <tr>
    <td><span style="color: purple;">low</span></td>
    <td><span style="color: blue;">0</span></td>
  </tr>
  <tr>
    <td rowspan="3"><span style="color: red;">no buy</span></td>
    <td><span style="color: purple;">high</span></td>
    <td><span style="color: blue;">350</span></td>
  </tr>
  <tr>
    <td><span style="color: purple;">medium</span></td>
    <td><span style="color: blue;">350</span></td>
  </tr>
  <tr>
    <td><span style="color: purple;">low</span></td>
    <td><span style="color: blue;">350</span></td>
  </tr>
</table>

<h2 id="evaluating_influence_diagram"> Influence Diagram Evaluation </h2>

<p>Influence diagrams were conceived as a compact, intuitive way to describe decision problems, yet practitioners initially had to transform them into a different format (i.e., a decision tree) in order to evaluate them. Until the 1980s, when <a href="http://www.cis.umassd.edu/~x2zhang/courses/CIS561/readings/EvaluatingID.pdf"><u>Shachter (1986)</u></a> showed how to evaluate the network directly, turning the diagram into a self-contained modelling and inference language.</p>

<p>Shachter’s <strong>arc-reversal / node-reduction algorithm</strong> reverses arcs and sequentially eliminates variables, summing over chance nodes and maximising over decision nodes while pushing expected-utility information forward.</p>

<h3 id="local-graph-operations">Four Local Graph Operations</h3>

<p>The arc-reversal / node-reduction algorithm employs a set of fundamental, local graph operations. Each operation ensures that the decision problem remains <em>semantically equivalent</em>, meaning the attainable utilities under any strategy are preserved:</p>

<ol>
  <li>
    <p><strong>Barren-Node Deletion:</strong>
 Any chance or decision node that has no children and is not a parent of an outcome node can be immediately removed from the diagram. Such nodes do not affect the utility and are therefore irrelevant to the decision problem.</p>

    <p>Figure 6 illustrates the process of barren node elimination. The first diagram becomes the second, and then the third, since removing a barren node can create new barren nodes that can also be eliminated.</p>

    <center>
 <table>
   <tr>
     <td align="center">
       <img src="/assets/2025-07-04-decision-theory-II/6_barren_node_elimination.png" alt="Barren node elimination example" height="400" />
     </td>
   </tr>
   <tr>
     <td colspan="2" align="center">
       <i><b>Figure 6.</b> Barren node elimination example.</i>
     </td>
   </tr>
 </table>
 </center>
  </li>
  <li>
    <p><strong>Chance-Node Removal:</strong>
 Once a chance node \(\textcolor{purple}{C}\) becomes a leaf (i.e., <strong>it has no children except outcome nodes</strong>), it can be eliminated via marginalization (taking an expectation). For every outcome node \(\textcolor{blue}{O}\) that has \(\textcolor{purple}{C}\) as a parent, a new utility table, \(u'_{\textcolor{blue}{O}}\), is computed. This new table will depend on the original parents of \(\textcolor{blue}{O}\) (excluding \(\textcolor{purple}{C}\)) and all the parents of \(\textcolor{purple}{C}\).</p>

\[u'_{\textcolor{blue}{O}}\left(\mathbf{\text{Pa}}_{\textcolor{blue}{O}} \cup \mathbf{\text{Pa}}_{\textcolor{purple}{C}} \setminus \{\textcolor{purple}{C}\}\right) = \sum_{\textcolor{purple}{c}} u_{\textcolor{blue}{O}}(\mathbf{\text{Pa}}_{\textcolor{blue}{O}}) \; P(\textcolor{purple}{c} \mid \mathbf{\text{Pa}}_{\textcolor{purple}{C}})\]

    <p>Here:</p>
    <ul>
      <li>\(\mathbf{\text{Pa}}_{\textcolor{blue}{O}}\) denotes the set of parents of \(\textcolor{blue}{O}\) in the diagram <em>before</em> removing \(\textcolor{purple}{C}\).</li>
      <li>\(\mathbf{\text{Pa}}_{\textcolor{purple}{C}}\) denotes the set of parents of \(\textcolor{purple}{C}\).</li>
      <li>\(u'_{\textcolor{blue}{O}}\) represents the <em>new</em> utility table for node \(\textcolor{blue}{O}\).</li>
    </ul>

    <p><br />
 Node \(\textcolor{purple}{C}\) and its CPT are then deleted. This operation “pushes expected utility forward” by embedding the influence of \(\textcolor{purple}{C}\) into the successor utility tables. The outcome node \(\textcolor{blue}{O}\) effectively inherits the predecessors of \(\textcolor{purple}{C}\), ensuring that all relevant dependencies are preserved.</p>

    <p>Figure 7 showcases the process of chance node removal, specifically \(\textcolor{purple}{C_2}\). The first diagram becomes the second, where parents of \(\textcolor{purple}{C_{2}}\) become the parents of \(\textcolor{blue}{O_1}\).</p>

    <center>
 <table>
   <tr>
     <td align="center">
       <img src="/assets/2025-07-04-decision-theory-II/7_chance_node_removal.png" alt="Chance node removal example" height="150" />
     </td>
   </tr>
   <tr>
     <td colspan="2" align="center">
       <i><b>Figure 7.</b> Chance node removal example.</i>
     </td>
   </tr>
 </table>
 </center>
  </li>
  <li>
    <p><strong>Decision-Node Removal:</strong>
 When a decision node \(\textcolor{red}{D}\) becomes a leaf in the influence diagram, meaning its only children are outcome nodes \(\textcolor{blue}{O}\), it can be eliminated. This step requires identifying the optimal decision for \(\textcolor{red}{D}\) in every possible situation, or “information state”, defined by the specific combination of observed values of \(\textcolor{red}{D}\)’s parent nodes.</p>

    <p>For each information state \(i\), we choose the action \(\textcolor{red}{d}\) that maximizes the expected utility \(\mathbb{E}[u(\textcolor{red}{d}, i)]\). This action represents the best possible choice for that information state and forms part of the overall optimal policy:</p>

\[\delta^*(i) = \text{argmax}_{\textcolor{red}{d}} \ \mathbb{E}[u(\textcolor{red}{d}, i)]\]

    <p>The function \(\delta^*(i)\) is recorded as the optimal decision rule for node \(\textcolor{red}{D}\) in information state \(i\). After removing \(\textcolor{red}{D}\), each outcome node \(\textcolor{blue}{O}\) that was a child of \(\textcolor{red}{D}\) has its utility table updated to reflect the maximum expected utility (MEU) achievable by making the optimal decision at \(\textcolor{red}{D}\), given the information state \(i\).</p>

    <p>This process “locks in” the optimal strategy for \(\textcolor{red}{D}\) and propagates the MEU forward through the diagram, similar to how chance nodes \(\textcolor{purple}{C}\) are eliminated by marginalization.</p>

    <p>Figure 8 demonstrates the process of eliminating a decision node, specifically \(\textcolor{red}{D_2}\). In the first diagram, the decision node is present; in the second, it has been removed, and the utility table has been updated to incorporate the optimal decision rule \(\delta^*(\textcolor{red}{D_2})\) for each information state (i.e., each combination of parent values). Only the maximum attainable utilities for each state are preserved.</p>

    <center>
 <table>
   <tr>
     <td align="center">
       <img src="/assets/2025-07-04-decision-theory-II/8_decision_node_removal.png" alt="Decision node removal example" width="600" />
     </td>
   </tr>
           <tr>
       <td colspan="2" align="center">
         <i><b>Figure 8.</b> Decision node removal example.</i>
       </td>
     </tr>
 </table>
 </center>
  </li>
  <li>
    <p><strong>Arc Reversal (between chance nodes):</strong>
 In most influence diagrams, nodes are not naturally leaves. They may have children that prevent us from eliminating them directly. To solve this, we use arc reversal to make a target node into a leaf by pushing its influence “backwards” to its children and adjusting the rest of the diagram so that it still represents the same probabilistic relationships.</p>

    <p>Let’s say we want to reverse an arc \(\textcolor{purple}{X} \rightarrow \textcolor{purple}{Y}\) where \(\mathbf{\text{Pa}}_{\textcolor{purple}{X}}\) is the set of parents of \(\textcolor{purple}{X}\) and \(\mathbf{\text{Pa}}_{\textcolor{purple}{Y}}\) is the parents of \(\textcolor{purple}{Y}\), including \(\textcolor{purple}{X}\) itself.</p>

    <p>To reverse, we remove the arc \(\textcolor{purple}{X} \rightarrow \textcolor{purple}{Y}\), add a new arc \(\textcolor{purple}{Y} \rightarrow \textcolor{purple}{X}\), add arcs from \(\mathbf{\text{Pa}}_{\textcolor{purple}{X}}\) to \(\textcolor{purple}{Y}\) if they are not already parents of \(\textcolor{purple}{Y}\), and add arcs from \(\mathbf{\text{Pa}}_{\textcolor{purple}{Y}}\) to \(\textcolor{purple}{X}\), if needed, to preserve dependencies. This means the new parents of \(\textcolor{purple}{X}\) and \(\textcolor{purple}{Y}\) are:</p>

    <ul>
      <li> \(\mathbf{\text{Pa}}^{\text{new}}_{\textcolor{purple}{Y}} = \mathbf{\text{Pa}}_{\textcolor{purple}{X}} \cup \mathbf{\text{Pa}}_{\textcolor{purple}{Y}}  \setminus \{\textcolor{purple}{Y}\}\)</li>
      <li> \(\mathbf{\text{Pa}}^{\text{new}}_{\textcolor{purple}{X}} = \mathbf{\text{Pa}}_{\textcolor{purple}{X}} \cup \mathbf{\text{Pa}}_{\textcolor{purple}{Y}}  \cup \{\textcolor{purple}{Y}\} \setminus \{\textcolor{purple}{X}\}\)</li>
    </ul>

    <p><br />
 To ensure the joint distribution remains unchanged under the new structure, we compute the new CPT using Bayes’ Theorem:</p>

\[\begin{aligned}
 P(\textcolor{purple}{Y} \mid \mathbf{\text{Pa}}^{\text{new}}_{\textcolor{purple}{Y}}) 
 &amp;= \sum_{\textcolor{purple}{X}} P(\textcolor{purple}{Y} \mid \mathbf{\text{Pa}}_{\textcolor{purple}{Y}}) \cdot P(\textcolor{purple}{X} \mid \mathbf{\text{Pa}}_{\textcolor{purple}{X}}) \\ \\
    
 P(\textcolor{purple}{X} \mid \mathbf{\text{Pa}}^{\text{new}}_{\textcolor{purple}{X}}) 
 &amp;= \frac{P(\textcolor{purple}{Y} \mid \mathbf{\text{Pa}}_{\textcolor{purple}{Y}}) \cdot P(\textcolor{purple}{X} \mid \mathbf{\text{Pa}}_{\textcolor{purple}{X}})}{P(\textcolor{purple}{Y} \mid \mathbf{\text{Pa}}^{\text{new}}_{\textcolor{purple}{Y}})}
 \end{aligned}\]

    <p>As an example, consider the influence diagram shown in Figure 9, which contains three chance nodes. We will reverse the arc \(\textcolor{purple}{C_2} \rightarrow \textcolor{purple}{C_3}\). Before reversal, the parent sets are:</p>

    <ul>
      <li> \(\mathbf{\text{Pa}}_{\textcolor{purple}{C_2}} = \{\textcolor{purple}{C_1}\}\)</li>
      <li> \(\mathbf{\text{Pa}}_{\textcolor{purple}{C_3}} = \{\textcolor{purple}{C_2}\}\)</li>
    </ul>

    <div style="height: 1.1em;"></div>

    <p>After reversal, the new parent sets become:</p>

    <ul>
      <li> \(\mathbf{\text{Pa}}^{\text{new}}_{\textcolor{purple}{C_2}} = \{\textcolor{purple}{C_1}, \textcolor{purple}{C_3}\}\)</li>
      <li> \(\mathbf{\text{Pa}}^{\text{new}}_{\textcolor{purple}{C_3}} = \{\textcolor{purple}{C_1}\}\)</li>
    </ul>

    <div style="height: 1.1em;"></div>

    <center>
 <table>
   <tr>
     <td align="center">
       <img src="/assets/2025-07-04-decision-theory-II/9_arc_reversal.png" alt="Decision node removal example" width="600" />
     </td>
   </tr>
           <tr>
       <td colspan="2" align="center">
         <i><b>Figure 9.</b> Arc reversal example.</i>
       </td>
     </tr>
 </table>
 </center>

    <p>We are given the following initial CPTs:</p>

    <table>
   <thead>
     <tr>
       <th colspan="2" style="text-align:center">$$P(\textcolor{purple}{C_1})$$</th>
     </tr>
   </thead>
   <tbody>
     <tr><td>$$\textcolor{purple}{c_{1,1}}$$</td><td>0.7</td></tr>
     <tr><td>$$\textcolor{purple}{c_{1,2}}$$</td><td>0.3</td></tr>
   </tbody>
 </table>

    <table>
   <thead>
     <tr>
       <th>$$P(\textcolor{purple}{C_2} \mid \textcolor{purple}{C_1})$$</th><th>$$\textcolor{purple}{c_{1,1}}$$</th><th>$$\textcolor{purple}{c_{1,2}}$$</th>
     </tr>
   </thead>
   <tbody>
     <tr><td>$$\textcolor{purple}{c_{2,1}}$$</td><td>0.6</td><td>0.1</td></tr>
     <tr><td>$$\textcolor{purple}{c_{2,2}}$$</td><td>0.4</td><td>0.9</td></tr>
   </tbody>
 </table>

    <table>
   <thead>
     <tr>
       <th>$$P(\textcolor{purple}{C_3} \mid \textcolor{purple}{C_2})$$</th><th>$$\textcolor{purple}{c_{2,1}}$$</th><th>$$\textcolor{purple}{c_{2,2}}$$</th>
     </tr>
   </thead>
   <tbody>
     <tr><td>$$\textcolor{purple}{c_{3,1}}$$</td><td>0.9</td><td>0.2</td></tr>
     <tr><td>$$\textcolor{purple}{c_{3,2}}$$</td><td>0.1</td><td>0.8</td></tr>
   </tbody>
 </table>

    <p><!-- To compute the new CPT for $$C_3$$ we have to marginalize $$C_2$$: --></p>

    <p><strong>Step 1: Compute new CPT for \(P(\textcolor{purple}{C_3} \mid \textcolor{purple}{C_1})\)</strong></p>

    <p>Using marginalization:</p>

\[P(\textcolor{purple}{C_3} \mid \textcolor{purple}{C_1}) = \sum_{\textcolor{purple}{c_2}} P(\textcolor{purple}{C_3} \mid \textcolor{purple}{c_2}) P(\textcolor{purple}{c_2} \mid \textcolor{purple}{C_1}).\]

    <p>\(\textcolor{purple}{c_{1,1}}\):</p>

\[\begin{aligned}
 P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{1,1}}) &amp;= P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{2,2}})P(\textcolor{purple}{c_{2,2}} \mid \textcolor{purple}{c_{1,1}}) + P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{2,1}})P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,1}}) \\
                     &amp;= 0.2 \cdot 0.4 + 0.9 \cdot 0.6 \\
                     &amp;= 0.08 + 0.54 = 0.62 \\
 P(\textcolor{purple}{c_{3,2}} \mid \textcolor{purple}{c_{1,1}}) &amp;= 1 - P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{1,1}}) = 1 - 0.62 = 0.38
 \end{aligned}\]

    <p>\(\textcolor{purple}{c_{1,2}}\):</p>

\[\begin{aligned}
 P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{1,2}}) &amp;= P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{2,2}})P(\textcolor{purple}{c_{2,2}} \mid \textcolor{purple}{c_{1,2}}) + P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{2,1}})P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,2}}) \\
                     &amp;= 0.2 \cdot 0.9 + 0.9 \cdot 0.1 \\
                     &amp;= 0.18 + 0.09 = 0.27 \\
 P(\textcolor{purple}{c_{3,2}} \mid \textcolor{purple}{c_{1,2}}) &amp;= 1 - P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{1,2}}) = 1 - 0.27 = 0.73
 \end{aligned}\]

    <p>Summarized as:</p>

    <table>
   <thead>
     <tr><th>$$P(\textcolor{purple}{C_3} \mid \textcolor{purple}{C_1})$$</th><th>$$\textcolor{purple}{c_{1,1}}$$</th><th>$$\textcolor{purple}{c_{1,2}}$$</th></tr>
   </thead>
   <tbody>
     <tr><td>$$\textcolor{purple}{c_{3,1}}$$</td><td>0.62</td><td>0.27</td></tr>
     <tr><td>$$\textcolor{purple}{c_{3,2}}$$</td><td>0.38</td><td>0.73</td></tr>
   </tbody>
 </table>

    <p><strong>Step 2: Compute new CPT for \(P(\textcolor{purple}{C_2} \mid \textcolor{purple}{C_1}, \textcolor{purple}{C_3})\)</strong></p>

    <p>Using Bayes’ Theorem, rounding results to three decimal places:</p>

\[P(\textcolor{purple}{C_2} \mid \textcolor{purple}{C_1}, \textcolor{purple}{C_3}) = \frac{P(\textcolor{purple}{C_3} \mid \textcolor{purple}{C_2}) \, P(\textcolor{purple}{C_2} \mid \textcolor{purple}{C_1})}{P(\textcolor{purple}{C_3} \mid \textcolor{purple}{C_1})}.\]

    <p>(\(\textcolor{purple}{c_{1,1}}\), \(\textcolor{purple}{c_{3,1}}\)):</p>

\[\begin{aligned}
 &amp;\quad P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,1}}, \textcolor{purple}{c_{3,1}}) = \frac{P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{2,1}}) \, P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,1}})}{P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{1,1}})} = \frac{0.9 \cdot 0.6}{0.62} = 0.871 \\
 &amp;\quad P(\textcolor{purple}{c_{2,2}} \mid \textcolor{purple}{c_{1,1}}, \textcolor{purple}{c_{3,1}}) = 1 - P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,1}}, \textcolor{purple}{c_{3,1}}) = 1 - 0.871 = 0.129
 \end{aligned}\]

    <p>(\(\textcolor{purple}{c_{1,2}}\), \(\textcolor{purple}{c_{3,1}}\)):</p>

\[\begin{aligned}
 &amp;\quad P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,2}}, \textcolor{purple}{c_{3,1}}) = \frac{P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{2,1}}) \, P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,2}})}{P(\textcolor{purple}{c_{3,1}} \mid \textcolor{purple}{c_{1,2}})} = \frac{0.9 \cdot 0.1}{0.27} = 0.333 \\
 &amp;\quad P(\textcolor{purple}{c_{2,2}} \mid \textcolor{purple}{c_{1,2}}, \textcolor{purple}{c_{3,1}}) = 1 - P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,2}}, \textcolor{purple}{c_{3,1}}) = 1 - 0.333 = 0.667 \\[3ex]
 \end{aligned}\]

    <p>(\(\textcolor{purple}{c_{1,1}}\), \(\textcolor{purple}{c_{3,2}}\)):</p>

\[\begin{aligned}
 &amp;\quad P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,1}}, \textcolor{purple}{c_{3,2}}) = \frac{P(\textcolor{purple}{c_{3,2}} \mid \textcolor{purple}{c_{2,1}}) \, P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,1}})}{P(\textcolor{purple}{c_{3,2}} \mid \textcolor{purple}{c_{1,1}})} = \frac{0.1 \cdot 0.6}{0.38} = 0.158 \\
 &amp;\quad P(\textcolor{purple}{c_{2,2}} \mid \textcolor{purple}{c_{1,1}}, \textcolor{purple}{c_{3,2}}) = 1 - P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,1}}, \textcolor{purple}{c_{3,2}}) = 1 - 0.158 = 0.842 \\[3ex]
 \end{aligned}\]

    <p>(\(\textcolor{purple}{c_{1,2}}\), \(\textcolor{purple}{c_{3,2}}\)):</p>

\[\begin{aligned}
 &amp;\quad P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,2}}, \textcolor{purple}{c_{3,2}}) = \frac{P(\textcolor{purple}{c_{3,2}} \mid \textcolor{purple}{c_{2,1}}) \, P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,2}})}{P(\textcolor{purple}{c_{3,2}} \mid \textcolor{purple}{c_{1,2}})} = \frac{0.1 \cdot 0.1}{0.73} = 0.014 \\
 &amp;\quad P(\textcolor{purple}{c_{2,2}} \mid \textcolor{purple}{c_{1,2}}, \textcolor{purple}{c_{3,2}}) = 1 - P(\textcolor{purple}{c_{2,1}} \mid \textcolor{purple}{c_{1,2}}, \textcolor{purple}{c_{3,2}}) = 1 - 0.014 = 0.986 \\[3ex]
 \end{aligned}\]

    <p>Summarized as:</p>

    <table>
   <thead>
     <tr>
       <th rowspan="2" style="text-align: center;">$$P(\textcolor{purple}{C_2} \mid \textcolor{purple}{C_1}, \textcolor{purple}{C_3})$$</th>
       <th colspan="2" style="text-align: center;">$$\textcolor{purple}{c_{3,1}}$$</th>
       <th colspan="2" style="text-align: center;">$$\textcolor{purple}{c_{3,2}}$$</th>
     </tr>
     <tr>
       <th style="text-align: center;">$$\textcolor{purple}{c_{1,1}}$$</th>
       <th style="text-align: center;">$$\textcolor{purple}{c_{1,2}}$$</th>
       <th style="text-align: center;">$$\textcolor{purple}{c_{1,1}}$$</th>
       <th style="text-align: center;">$$\textcolor{purple}{c_{1,2}}$$</th>
     </tr>
   </thead>
   <tbody>
     <tr>
       <td>$$\textcolor{purple}{c_{2,1}}$$</td>
       <td>0.871</td>
       <td>0.333</td>
       <td>0.158</td>
       <td>0.014</td>
     </tr>
     <tr>
       <td>$$\textcolor{purple}{c_{2,2}}$$</td>
       <td>0.129</td>
       <td>0.667</td>
       <td>0.842</td>
       <td>0.986</td>
     </tr>
   </tbody>
 </table>
  </li>
</ol>

<h3 id="node-reduction-algorithm">The Arc-Reversal / Node-Reduction Algorithm</h3>

<p>The algorithm incrementally eliminates nodes by repeatedly applying the four local graph operations described above, until only a single value node remains. The number stored in this final value node is the <strong>MEU</strong>, and the collection of recorded decision rules forms an <strong>optimal policy</strong> for the original decision problem.</p>

<p><strong>Input:</strong> A well-formed influence diagram (or LIMID).<br />
<strong>Output:</strong> The MEU and an optimal policy for each decision node.</p>

<p><strong>Preparatory steps:</strong></p>
<ul>
  <li><strong>Canonical form:</strong> If the diagram does not already satisfy the standard conventions (total order of decisions, and no arcs from decisions to chance nodes), perform a sequence of <strong>Arc Reversals (Rule 4)</strong> to obtain a canonical influence diagram.</li>
  <li><strong>LIMID transformation:</strong> Transform the influence diagram into a LIMID by adding <em>memory arcs</em> so that each decision node has, as parents, all information variables that are remembered at the time of the decision.</li>
</ul>

<hr />

<p><strong>Main loop - repeat until only one value node remains:</strong></p>

<ol>
  <li><strong>Select a node \(N\) to eliminate</strong>
    <ul>
      <li>If there is any <em>barren node</em> (a node with no children), delete it immediately using <strong>Barren-Node Deletion (Rule 1)</strong>.</li>
      <li>Otherwise, select any <em>leaf node</em> (a chance or decision node whose only children are value nodes).</li>
      <li>If no leaf exists, choose a non-value node and repeatedly apply <strong>Arc Reversal (Rule 4)</strong> to its outgoing arcs until it becomes a leaf.</li>
    </ul>
  </li>
  <li><strong>Eliminate \(N\)</strong>
    <ul>
      <li>If \(N\) is a <strong>chance node</strong>, apply <strong>Chance-Node Removal (Rule 2)</strong>: marginalize over \(N\) and update the relevant value tables.</li>
      <li>If \(N\) is a <strong>decision node</strong>, apply <strong>Decision-Node Removal (Rule 3)</strong>: maximize over the possible actions of \(N\), record the optimal decision rule \(\delta^*\), and update the value tables.</li>
    </ul>
  </li>
  <li><strong>Merge any duplicate value nodes</strong> that may have arisen during elimination.</li>
</ol>

<hr />

<p>When the loop ends, only one value node remains. Its single numerical entry is the MEU. The set \(\{\delta^*\}\) collected during the process provides an optimal decision rule for each decision node.</p>

<h3 id="relationship-to-bayesian-network-elimination">Relationship to Bayesian Network Variable Elimination</h3>

<p>Arc reversal/node reduction in influence diagrams is structurally similar to <a href="https://artint.info/3e/html/ArtInt3e.Ch4.S5.html"><u>variable elimination</u></a> in Bayesian networks. The main difference is the handling of utilities via <strong>maximization</strong> over decision nodes (instead of <strong>summation</strong> over chance nodes). In both approaches, information is propagated through the graph by combining local factors (such as CPTs or utility functions) and eliminating variables, either by summing over uncertainties for chance nodes or optimizing (maximizing) over decisions for decision nodes.</p>

<p>This similarity also extends to computational complexity: since both methods generate and manipulate similar intermediate factors, their efficiency is determined by the treewidth of the chosen elimination order.</p>

<h3 id="related-work-evaluation">Related Work</h3>

<p>There are several alternative strategies for evaluating influence diagrams beyond the arc-reversal and node-reduction procedures described above.</p>

<p>A more compact exact method is <strong>junction-tree propagation</strong>, which is also inspired by techniques from Bayesian networks. In this approach, the influence diagram is first moralized and triangulated, then compiled into a tree of cliques. Local probability and utility factors are passed between cliques using message-passing algorithms such as Shafer-Shenoy (<a href="https://kuscholarworks.ku.edu/server/api/core/bitstreams/c353aa52-11ad-46c0-b867-f5d05f7f1962/content"><u>Shafer &amp; Shenoy, 1990</u></a>) or HUGIN until convergence is reached. Junction-tree algorithms are often more memory-efficient than straightforward variable elimination and form the foundation of many commercial and open-source tools, including PyAgrum (<a href="https://arxiv.org/pdf/1302.6824"><u>Jensen et al., 1994</u></a>; <a href="https://arxiv.org/pdf/1301.6716"><u>Madsen &amp; Jensen, 1999</u></a>; <a href="https://www.stats.ox.ac.uk/~steffen/papers/limids.pdf"><u>Lauritzen &amp; Nilsson, 2001</u></a>).</p>

<p>However, even junction-tree propagation can become impractical for very complex or densely connected models, as the required clique tables may grow prohibitively large. Additionally, exact arc-reversal is difficult when the diagram contains continuous variables. In these situations, we need to rely on <strong>approximate methods</strong>. The most common of these is Monte Carlo sampling, which estimates expected utility by simulating random scenarios (<a href="https://www.jstor.org/stable/2632102"><u>Shachter &amp; Kenley, 1989</u></a>; <a href="https://proceedings.mlr.press/r0/jenzarli95a/jenzarli95a.pdf"><u>Jenzarli, 1995</u></a>). Later research has shown that Monte Carlo methods can be extended to handle non-Gaussian or hybrid influence diagrams (<a href="https://cig.fi.upm.es/wp-content/uploads/2024/01/Decision-Analysis-by-Augmented-Probability-Simulation.pdf"><u>Bielza et al., 1999</u></a>; <a href="https://doi.org/10.1016/j.ejor.2007.01.036"><u>Cobb &amp; Shenoy, 2008</u></a>).</p>

<p>Finally, another avenue is <strong>variational inference</strong>, although I haven’t yet found published work applying it to influence diagrams. In principle, one could adapt techniques such as variational message passing (<a href="https://jmlr.org/papers/volume6/winn05a/winn05a.pdf"><u>Winn &amp; Bishop, 2005</u></a>) to do so.</p>

<h2 id="evaluating-oil-influence-diagram">Evaluating the Oil Influence Diagram</h2>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
<b>IMPORTANT:</b> To keep the section clear and focused, detailed computations are placed inside expandable sections below. Click to reveal them as needed.
</div>
<div style="height: 1.1em;"></div>

<p>We will use the arc-reversal / node-reduction algorithm to solve the oil field decision problem. Note that the influence diagram is already a LIMID, since we added the arc \(\textcolor{red}{T} \rightarrow \textcolor{red}{B}\), and it is in canonical form.</p>

<p>In Figure 5, we observe that there are neither barren nodes nor leaf nodes. Therefore, we must select one of the chance nodes and apply arc reversal until it becomes a leaf.</p>

<p>For the first step, we select node \(\textcolor{purple}{Q}\) (oil field quality). Therefore, we need to reverse the arc \(\textcolor{purple}{Q} \rightarrow \textcolor{purple}{R}\). To do this, we remove the arc \(\textcolor{purple}{Q} \rightarrow \textcolor{purple}{R}\), add the arc \(\textcolor{purple}{R} \rightarrow \textcolor{purple}{Q}\), and add arcs from the parents of \(\textcolor{purple}{R}\) to \(\textcolor{purple}{Q}\) if they are not already parents of \(\textcolor{purple}{Q}\). This also means adding the arc \(\textcolor{red}{T} \rightarrow \textcolor{purple}{R}\).</p>

<p>Figure 10 shows the result of reversing \(\textcolor{purple}{Q} \rightarrow \textcolor{purple}{R}\):</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-07-04-decision-theory-II/10_oil_reverse_q.png" alt="Influence diagram after reversing arc Q &rarr; R" width="320" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 10.</b> Influence diagram after reversing arc Q &rarr; R.</i>
    </td>
  </tr>
</table>
</center>

<p>To obtain the distribution \(P(\textcolor{purple}{R} \mid \textcolor{red}{T})\), we first marginalize over \(\textcolor{purple}{Q}\) in \(P(\textcolor{purple}{R} \mid \textcolor{purple}{Q})\):</p>

<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">
<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">Posteriors for <span style="color:purple;">pass</span> and <span style="color:purple;">fail</span> results</summary>

$$
\begin{aligned}
P(\textcolor{purple}{\text{pass}} \mid \textcolor{purple}{Q}) &amp;= P(\textcolor{purple}{\text{pass}}  \mid \textcolor{purple}{\text{high}})P(\textcolor{purple}{\text{high}}) + P(\textcolor{purple}{\text{pass}}  \mid \textcolor{purple}{\text{medium}})P(\textcolor{purple}{\text{medium}}) + P(\textcolor{purple}{\text{pass}}  \mid \textcolor{purple}{\text{low}})P(\textcolor{purple}{\text{low}}) \\
                &amp;= 0.95 \cdot 0.35 + 0.7 \cdot 0.45 + 0.15 \cdot 0.2 \\
                &amp;= 0.3325 + 0.315 + 0.03 \\
                &amp;= 0.6775 \\[1em]
P(\textcolor{purple}{\text{fail}} \mid \textcolor{purple}{Q}) &amp;= P(\textcolor{purple}{\text{fail}}  \mid \textcolor{purple}{\text{high}})P(\textcolor{purple}{\text{high}}) + P(\textcolor{purple}{\text{fail}}  \mid \textcolor{purple}{\text{medium}})P(\textcolor{purple}{\text{medium}}) + P(\textcolor{purple}{\text{fail}}  \mid \textcolor{purple}{\text{low}})P(\textcolor{purple}{\text{low}}) \\
                &amp;= 0.05 \cdot 0.35 + 0.3 \cdot 0.45 + 0.85 \cdot 0.2 \\
                &amp;= 0.0175 + 0.135 + 0.17 \\
                &amp;= 0.3225 \\
\end{aligned}
$$

</details>

<p>Now, given that <span style="color: purple;">R</span> only applies when we make the test, we know that 
\(P\left(\textcolor{purple}{R} \mid \textcolor{purple}{Q},\, \textcolor{red}{T} = \textcolor{red}{\text{perform}}\right)\) 
is simply 
\(P\left(\textcolor{purple}{R} \mid \textcolor{purple}{Q}\right)\), 
and that 
\(P\left(\textcolor{purple}{R} \mid \textcolor{purple}{Q},\, \textcolor{red}{T} = \textcolor{red}{\text{no perform}}\right)\) 
is all zeros except for the <span style="color: purple;">no results</span> case. Therefore:</p>

<table>
  <tr>
    <th>$$P(\textcolor{purple}{R} \mid \textcolor{red}{T})$$</th>
    <th style="text-align:center;"><span style="color:red;">perform</span></th>
    <th style="text-align:center;"><span style="color:red;">no perform</span></th>      
  </tr>
  <tr>
    <td><span style="color:purple;">pass</span></td>
    <td>0.6775</td>
    <td>0</td>   
  </tr>
  <tr>
    <td><span style="color:purple;">fail</span></td>
    <td>0.3225</td>
    <td>0</td>
  </tr>
  <tr>
    <td><span style="color:purple;">no results</span></td>
    <td>0</td>
    <td>1</td>
  </tr>
</table>

<p>Now for \(P(\textcolor{purple}{Q} \mid \textcolor{purple}{R})\), we need to apply Bayes’ theorem:</p>

<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">
<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">
P(<span style="color:purple;">Q</span> | <span style="color:purple;">R</span> = <span style="color:purple;">pass</span>)
</summary>

$$
\begin{aligned}
P(\textcolor{purple}{\text{high}} \mid \textcolor{purple}{\text{pass}}) &amp;= \frac{P(\textcolor{purple}{\text{pass}} \mid \textcolor{purple}{\text{high}})P(\textcolor{purple}{\text{high}})}{P(\textcolor{purple}{\text{pass}})} \\
&amp;= \frac{0.95 \cdot 0.35}{0.6775} = \frac{0.3325}{0.6775} \approx 0.4908 \\[1em]
P(\textcolor{purple}{\text{medium}} \mid \textcolor{purple}{\text{pass}}) &amp;= \frac{P(\textcolor{purple}{\text{pass}} \mid \textcolor{purple}{\text{medium}})P(\textcolor{purple}{\text{medium}})}{P(\textcolor{purple}{\text{pass}})} \\
&amp;= \frac{0.7 \cdot 0.45}{0.6775} = \frac{0.315}{0.6775} \approx 0.4649 \\[1em]
P(\textcolor{purple}{\text{low}} \mid \textcolor{purple}{\text{pass}}) &amp;= \frac{P(\textcolor{purple}{\text{pass}} \mid \textcolor{purple}{\text{low}})P(\textcolor{purple}{\text{low}})}{P(\textcolor{purple}{\text{pass}})} \\
&amp;= \frac{0.15 \cdot 0.2}{0.6775} = \frac{0.03}{0.6775} \approx 0.0443
\end{aligned}
$$

</details>

<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">
<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">P(<span style="color:purple;">Q</span> | <span style="color:purple;">R</span> = <span style="color:purple;">fail</span>)</summary>

$$
\begin{aligned}
P(\textcolor{purple}{\text{high}} \mid \textcolor{purple}{\text{fail}}) &amp;= \frac{P(\textcolor{purple}{\text{fail}} \mid \textcolor{purple}{\text{high}})P(\textcolor{purple}{\text{high}})}{P(\textcolor{purple}{\text{fail}})} \\
&amp;= \frac{0.05 \cdot 0.35}{0.3225} = \frac{0.0175}{0.3225} \approx 0.0543 \\[1em]
P(\textcolor{purple}{\text{medium}} \mid \textcolor{purple}{\text{fail}}) &amp;= \frac{P(\textcolor{purple}{\text{fail}} \mid \textcolor{purple}{\text{medium}})P(\textcolor{purple}{\text{medium}})}{P(\textcolor{purple}{\text{fail}})} \\
&amp;= \frac{0.3 \cdot 0.45}{0.3225} = \frac{0.135}{0.3225} \approx 0.4186 \\[1em]
P(\textcolor{purple}{\text{low}} \mid \textcolor{purple}{\text{fail}}) &amp;= \frac{P(\textcolor{purple}{\text{fail}} \mid \textcolor{purple}{\text{low}})P(\textcolor{purple}{\text{low}})}{P(\textcolor{purple}{\text{fail}})} \\
&amp;= \frac{0.85 \cdot 0.2}{0.3225} = \frac{0.17}{0.3225} \approx 0.5271
\end{aligned}
$$

</details>

<p>When \(\textcolor{red}{T} = \textcolor{red}{\text{no perform}}\), then \(\textcolor{purple}{R}\) does not make sense, so \(P\left(\textcolor{purple}{Q} \mid \textcolor{purple}{R},\, \textcolor{red}{T} = \textcolor{red}{\text{no perform}}\right)\) is simply \(P\left(\textcolor{purple}{Q}\right)\). Therefore:</p>

<table>
  <tr>
    <th rowspan="2" style="text-align: center;">$$P(\textcolor{purple}{Q} \mid \textcolor{purple}{R},\, \textcolor{red}{T})$$</th>
    <th colspan="3" style="text-align: center;"><span style="color:red;">perform</span></th>
    <th colspan="3" style="text-align: center;"><span style="color:red;">no perform</span></th>
  </tr>
  <tr>
    <th style="text-align: center;"><span style="color:purple;">pass</span></th>
    <th style="text-align: center;"><span style="color:purple;">fail</span></th>
    <th style="text-align: center;"><span style="color:purple;">no results</span></th>
    <th style="text-align: center;"><span style="color:purple;">pass</span></th>
    <th style="text-align: center;"><span style="color:purple;">fail</span></th>
    <th style="text-align: center;"><span style="color:purple;">no results</span></th>
  </tr>
  <tr>
    <td><span style="color:purple;">high</span></td>
    <td>0.4908</td>
    <td>0.0543</td>
    <td>x</td>
    <td>x</td>
    <td>x</td>
    <td>0.35</td>
  </tr>
  <tr>
    <td><span style="color:purple;">medium</span></td>
    <td>0.4649</td>
    <td>0.4186</td>
    <td>x</td>
    <td>x</td>
    <td>x</td>
    <td>0.45</td>
  </tr>
  <tr>
    <td><span style="color:purple;">low</span></td>
    <td>0.0443</td>
    <td>0.5271</td>
    <td>x</td>
    <td>x</td>
    <td>x</td>
    <td>0.2</td>
  </tr>
</table>

<p>By making the problem symmetric, we have introduced many zero probabilities, which increases the likelihood of encountering undefined expressions such as \(0/0\). Recall that a conditional probability \(P(\textcolor{purple}{a} \mid \textcolor{purple}{b})\) is only defined when \(P(\textcolor{purple}{b}) &gt; 0\), so we should not expect to be able to compute every conditional probability when reversing arcs. However, as will be shown below, these “x” values will not affect the outcome of the problem.</p>

<p>After reversing the arc \(\textcolor{purple}{Q} \rightarrow \textcolor{purple}{R}\), the node \(\textcolor{purple}{Q}\) becomes a leaf and can be eliminated. Figure 11 illustrates the resulting diagram.</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-07-04-decision-theory-II/11_oil_remove_q.png" alt="Influence diagram after removing node Q" width="320" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 11.</b> Influence diagram after removing node Q.</i>
    </td>
  </tr>
</table>
</center>

<p>By removing \(\textcolor{purple}{Q}\), we need to marginalize it and update the utility table of \(\textcolor{blue}{U}\)</p>

\[u'_\textcolor{blue}{U}(\textcolor{red}{T}, \textcolor{purple}{R}, \textcolor{red}{B}) = \sum_{\textcolor{purple}{q}} u_\textcolor{blue}{U}(\textcolor{red}{T}, \textcolor{red}{B}, \textcolor{purple}{Q})P(\textcolor{purple}{q} \mid \textcolor{red}{T}, \textcolor{purple}{R})\]

<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">
<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">
<span style="color:blue;">U'</span>(<span style="color:purple;">R</span>, <span style="color:red;">B</span>, <span style="color:red;">T</span> = <span style="color:red;">perform</span>)
</summary>
$$
\begin{aligned}
u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}},\ \textcolor{purple}{\text{pass}},\ \textcolor{red}{\text{buy}}) &amp;= u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;= 1220 \cdot 0.4908 + 600 \cdot 0.4649 + (-30) \cdot 0.0443 \\
&amp;= 598.776 + 278.94 - 1.329 \\
&amp;= 876.387 \\[1em]
% -------------------
u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}},\ \textcolor{purple}{\text{pass}},\ \textcolor{red}{\text{no buy}}) &amp;= u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;= 320 \cdot 0.4908 + 320 \cdot 0.4649 + 320 \cdot 0.0443 \\
&amp;= 157.056 + 148.768 + 14.176 \\
&amp;= 320
\end{aligned}
$$

$$
\begin{aligned}
u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}},\ \textcolor{purple}{\text{fail}},\ \textcolor{red}{\text{buy}}) &amp;= u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;= 1220 \cdot 0.0543 + 600 \cdot 0.4186 + (-30) \cdot 0.5271 \\
&amp;= 66.246 + 251.16 - 15.813 \\
&amp;= 301.593\\[1em]
u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}},\ \textcolor{purple}{\text{fail}},\ \textcolor{red}{\text{no buy}}) &amp;= u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;= 320 \cdot 0.0543 + 320 \cdot 0.4186 + 320 \cdot 0.5271 \\
&amp;= 17.376 + 133.952 + 168.672 \\
&amp;= 320
\end{aligned}
$$

$$
\begin{aligned}
u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}},\ \textcolor{purple}{\text{no results}},\ \textcolor{red}{\text{buy}}) &amp;= u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;\quad + u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;\quad + u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;= 1220 \cdot x + 600 \cdot x + (-30) \cdot x \\
&amp;= 1220x + 600x - 30x \\
&amp;= 1790x \\[1em]
% -------------------
u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}},\ \textcolor{purple}{\text{no results}},\ \textcolor{red}{\text{no buy}}) &amp;= u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;\quad + u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;\quad + u'_\textcolor{blue}{U}(\textcolor{red}{\text{perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;= 320 \cdot x + 320 \cdot x + 320 \cdot x \\
&amp;= 320x + 320x + 320x \\
&amp;= 960x
\end{aligned}
$$
</details>

<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">
<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">
<span style="color:blue;">U'</span>(<span style="color:purple;">R</span>, <span style="color:red;">B</span>, <span style="color:red;">T</span> = <span style="color:red;">no perform</span>)
</summary>
$$
\begin{aligned}
u'_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}},\ \textcolor{purple}{\text{pass}},\ \textcolor{red}{\text{buy}}) &amp;= u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;= 1250 \cdot x + 630 \cdot x + 0 \cdot x \\
&amp;= 1250x + 630x + 0x \\
&amp;= 1880x
\end{aligned}
$$

$$
\begin{aligned}
u'_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}},\ \textcolor{purple}{\text{pass}},\ \textcolor{red}{\text{no buy}}) &amp;= u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{pass}}) \\
&amp;= 350 \cdot x + 350 \cdot x + 350 \cdot x \\
&amp;= 350x + 350x + 350x \\
&amp;= 1050x
\end{aligned}
$$

$$
\begin{aligned}
u'_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}},\ \textcolor{purple}{\text{fail}},\ \textcolor{red}{\text{buy}}) &amp;= u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;= 1250 \cdot x + 630 \cdot x + 0 \cdot x \\
&amp;= 1250x + 630x + 0x \\
&amp;= 1880x
\end{aligned}
$$

$$
\begin{aligned}
u'_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}},\ \textcolor{purple}{\text{fail}},\ \textcolor{red}{\text{no buy}}) &amp;= u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{fail}}) \\
&amp;= 350 \cdot x + 350 \cdot x + 350 \cdot x \\
&amp;= 350x + 350x + 350x \\
&amp;= 1050x
\end{aligned}
$$

$$
\begin{aligned}
u'_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}},\ \textcolor{purple}{\text{no results}},\ \textcolor{red}{\text{buy}}) &amp;= u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;= 1250 \cdot 0.35 + 630 \cdot 0.45 + 0 \cdot 0.2 \\
&amp;= 437.5 + 283.5 + 0 \\
&amp;= 721
\end{aligned}
$$

$$
\begin{aligned}
u'_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}},\ \textcolor{purple}{\text{no results}},\ \textcolor{red}{\text{no buy}}) &amp;= u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{high}}) P(\textcolor{purple}{\text{high}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{medium}}) P(\textcolor{purple}{\text{medium}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;\quad + u_\textcolor{blue}{U}(\textcolor{red}{\text{no perform}}, \textcolor{red}{\text{no buy}}, \textcolor{purple}{\text{low}}) P(\textcolor{purple}{\text{low}} \mid \textcolor{red}{\text{no perform}}, \textcolor{purple}{\text{no results}}) \\
&amp;= 350 \cdot 0.35 + 350 \cdot 0.45 + 350 \cdot 0.2 \\
&amp;= 122.5 + 157.5 + 70 \\
&amp;= 350
\end{aligned}
$$
</details>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
In practice, it is not necessary to estimate the cases that are not applicable (i.e., the ones marked multiplied by "x"); we can simply assign them as "None" and disregard them in subsequent calculations.
</div>
<div style="height: 1.1em;"></div>

<p>The following table shows the updated utility table \(u'_\textcolor{blue}{U}\) table after removing \(\textcolor{purple}{Q}\):</p>

<table>
  <tr>
    <th style="text-align: center;">$$\textcolor{red}{T}$$</th>
    <th style="text-align: center;">$$\textcolor{purple}{R}$$</th>
    <th style="text-align: center;">$$\textcolor{red}{B}$$</th>
    <th style="text-align: center;">$$\textcolor{blue}{U}$$</th>
  </tr>
  <tr>
    <td rowspan="6"><span style="color: red;">perform</span></td>
    <td rowspan="2"><span style="color: purple;">pass</span></td>
    <td><span style="color: red;">buy</span></td>
    <td><span style="color: blue;">876.387</span></td>
  </tr>
  <tr>
    <td><span style="color: red;">no buy</span></td>
    <td><span style="color: blue;">320</span></td>
  </tr>
  <tr>
    <td rowspan="2"><span style="color: purple;">fail</span></td>
    <td><span style="color: red;">buy</span></td>
    <td><span style="color: blue;">301.593</span></td>
  </tr>
  <tr>
    <td><span style="color: red;">no buy</span></td>
    <td><span style="color: blue;">320</span></td>
  </tr>
  <tr>
    <td rowspan="2"><span style="color: purple;">no results</span></td>
    <td><span style="color: red;">buy</span></td>
    <td><span style="color: blue;">1790x</span></td>
  </tr>
  <tr>
    <td><span style="color: red;">no buy</span></td>
    <td><span style="color: blue;">960x</span></td>
  </tr>
  <tr>
    <td rowspan="6"><span style="color: red;">no perform</span></td>
    <td rowspan="2"><span style="color: purple;">pass</span></td>
    <td><span style="color: red;">buy</span></td>
    <td><span style="color: blue;">1880x</span></td>
  </tr>
  <tr>
    <td><span style="color: red;">no buy</span></td>
    <td><span style="color: blue;">1050x</span></td>
  </tr>
  <tr>
    <td rowspan="2"><span style="color: purple;">fail</span></td>
    <td><span style="color: red;">buy</span></td>
    <td><span style="color: blue;">1880x</span></td>
  </tr>
  <tr>
    <td><span style="color: red;">no buy</span></td>
    <td><span style="color: blue;">1050x</span></td>
  </tr>
  <tr>
    <td rowspan="2"><span style="color: purple;">no results</span></td>
    <td><span style="color: red;">buy</span></td>
    <td><span style="color: blue;">721</span></td>
  </tr>
  <tr>
    <td><span style="color: red;">no buy</span></td>
    <td><span style="color: blue;">350</span></td>
  </tr>
</table>

<p>We can now remove the decision node \(\textcolor{red}{B}\), as it is a leaf node. The resulting influence diagram is shown below:</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-07-04-decision-theory-II/12_oil_remove_b.png" alt="Influence diagram after removing decision node B" width="300" />
    </td>
  </tr>
  <tr>
    <td colspan="1" align="center">
      <i><b>Figure 12.</b> Influence diagram after removing decision node B.</i>
    </td>
  </tr>
</table>
</center>

<p>By removing \(\textcolor{red}{B}\), we must determine the optimal choice for \(\textcolor{red}{B}\) in every possible scenario. This yields the following utility table, \(u''_\textcolor{blue}{U}\):</p>

<table>
  <tr>
    <th style="text-align: center;">$$\textcolor{red}{T}$$</th>
    <th style="text-align: center;">$$\textcolor{purple}{R}$$</th>
    <th style="text-align: center;">$$\textcolor{red}{\delta^*(B)}$$</th>
    <th style="text-align: center;">$$\textcolor{blue}{U}$$</th>
  </tr>
  <tr>
    <td rowspan="3"><span style="color: red;">perform</span></td>
    <td rowspan="1"><span style="color: purple;">pass</span></td>
    <td><span style="color: red;">buy</span></td>
    <td><span style="color: blue;">876.387</span></td>
  </tr>
  <tr>
    <td rowspan="1"><span style="color: purple;">fail</span></td>
    <td><span style="color: red;">no buy</span></td>
    <td><span style="color: blue;">320</span></td>
  </tr>
  <tr>
    <td rowspan="1"><span style="color: purple;">no results</span></td>
    <td><span style="color: red;">buy</span></td>
    <td><span style="color: blue;">1790x</span></td>
  </tr>
  <tr>
    <td rowspan="3"><span style="color: red;">no perform</span></td>
    <td rowspan="1"><span style="color: purple;">pass</span></td>
    <td><span style="color: red;">buy</span></td>
    <td><span style="color: blue;">1880x</span></td>
  </tr>
  <tr>
    <td rowspan="1"><span style="color: purple;">fail</span></td>
    <td><span style="color: red;">buy</span></td>
    <td><span style="color: blue;">1880x</span></td>
  </tr>
  <tr>
    <td rowspan="1"><span style="color: purple;">no results</span></td>
    <td><span style="color: red;">buy</span></td>
    <td><span style="color: blue;">721</span></td>
  </tr>
</table>

<p>After removing \(\textcolor{red}{B}\), \(\textcolor{purple}{R}\) becomes a leaf node, allowing us to eliminate it by marginalization.</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-07-04-decision-theory-II/13_oil_remove_r.png" alt="Influence diagram after removing chance node R" width="180" />
    </td>
  </tr>
  <tr>
    <td colspan="1" align="center">
      <i><b>Figure 13.</b> Influence diagram after removing chance node R.</i>
    </td>
  </tr>
</table>
</center>

<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">
<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">
<span style="color:blue;">U'''</span>(<span style="color:red;">T</span>)
</summary>

$$
\begin{aligned}
u'''_{\textcolor{blue}{U}}(\textcolor{red}{\text{perform}}) &amp;= u''_{\textcolor{blue}{U}}(\textcolor{red}{\text{perform}},\,\textcolor{purple}{\text{pass}},\,\textcolor{red}{\text{buy}})\; P(\textcolor{purple}{\text{pass}} \mid \textcolor{red}{\text{perform}}) \\
&amp;\quad + u''_{\textcolor{blue}{U}}(\textcolor{red}{\text{perform}},\,\textcolor{purple}{\text{fail}},\,\textcolor{red}{\text{no buy}})\; P(\textcolor{purple}{\text{fail}} \mid \textcolor{red}{\text{perform}}) \\
&amp;\quad + u''_{\textcolor{blue}{U}}(\textcolor{red}{\text{perform}},\,\textcolor{purple}{\text{no results}},\,\textcolor{red}{\text{buy}})\; P(\textcolor{purple}{\text{no results}} \mid \textcolor{red}{\text{perform}}) \\
&amp;= 876.387 \cdot 0.6775 + 320 \cdot 0.3225 + 1790x \cdot 0 \\
&amp;= 593.738 + 103.2 + 0 \\
&amp;= 696.938 \\[1em]
% -------------------
u'''_{\textcolor{blue}{U}}(\textcolor{red}{\text{no perform}}) &amp;= u''_{\textcolor{blue}{U}}(\textcolor{red}{\text{no perform}},\,\textcolor{purple}{\text{pass}},\,\textcolor{red}{\text{buy}})\; P(\textcolor{purple}{\text{pass}} \mid \textcolor{red}{\text{no perform}}) \\
&amp;\quad + u''_{\textcolor{blue}{U}}(\textcolor{red}{\text{no perform}},\,\textcolor{purple}{\text{fail}},\,\textcolor{red}{\text{buy}})\; P(\textcolor{purple}{\text{fail}} \mid \textcolor{red}{\text{no perform}}) \\
&amp;\quad + u''_{\textcolor{blue}{U}}(\textcolor{red}{\text{no perform}},\,\textcolor{purple}{\text{no results}},\,\textcolor{red}{\text{buy}})\; P(\textcolor{purple}{\text{no results}} \mid \textcolor{red}{\text{no perform}}) \\
&amp;= 1880x \cdot 0 + 1880x \cdot 0 + 721 \cdot 1 \\
&amp;= 0 + 0 + 721 \\
&amp;= 721 \\
\end{aligned}
$$

</details>

<p>The table below shows the updated utility values \(u'''_{\textcolor{blue}{U}}\) after removing \(\textcolor{purple}{R}\):</p>

<table>
  <thead>
    <tr>
      <th style="text-align: center;">$$\textcolor{red}{T}$$</th>
      <th style="text-align: center;">$$\textcolor{blue}{U}$$</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><span style="color: red;">perform</span></td>
      <td><span style="color: blue;">696.938</span></td>
    </tr>
    <tr>
      <td><span style="color: red;">no perform</span></td>
      <td><span style="color: blue;">721</span></td>
    </tr>
  </tbody>
</table>

<p>At this stage, the only remaining node is the decision node \(\textcolor{red}{T}\), which we can now eliminate by selecting the optimal action. The table below summarizes the optimal decision for \(\textcolor{red}{T}\), and Figure 14 shows the final influence diagram after its removal:</p>

<table>
  <thead>
    <tr>
    <th style="text-align: center;">$$\textcolor{red}{\delta^*(T)}$$</th>
      <th style="text-align: center;">$$\textcolor{blue}{U}$$</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><span style="color: red;">no perform</span></td>
      <td><span style="color: blue;">721</span></td>
    </tr>
  </tbody>
</table>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-07-04-decision-theory-II/14_oil_remove_t.png" alt="Final influence diagram after removing decision node T" width="60" />
    </td>
  </tr>
  <tr>
    <td colspan="1" align="center">
      <i><b>Figure 14.</b> Final influence diagram after removing decision node T.</i>
    </td>
  </tr>
</table>
</center>

<p>As we can see, this yields the same result as the decision tree in <a href="https://ferjorosa.github.io/blog/2025/06/08/decision-theory-I.html"><u>Part I</u></a>: <strong>the company should not perform the test and should buy the oil field</strong>.</p>

<h2 id="influence-diagram-libraries">Influence Diagram Libraries</h2>

<p>In practice, we do not need to manually perform each step of the arc-reversal or node-reduction algorithm to evaluate an influence diagram. Several open-source libraries automate this entire process and provide sophisticated inference algorithms that handle the computational complexity for us.</p>

<p><a href="https://pyagrum.readthedocs.io"><code>PyAgrum</code></a> is currently the most widely supported open-source library for influence diagrams. Written in C++ with a Python interface, it implements the Shafer-Shenoy algorithm for LIMIDs (<a href="https://kuscholarworks.ku.edu/server/api/core/bitstreams/c353aa52-11ad-46c0-b867-f5d05f7f1962/content"><u>Shafer &amp; Shenoy, 1990</u></a>). PyAgrum builds a junction tree representation of the influence diagram and uses message passing, alternating between summation (for chance nodes) and maximization (for decision nodes), to efficiently evaluate the diagram.</p>

<p>Other notable libraries include:</p>

<ul>
  <li>
    <p><a href="https://support.bayesfusion.com/docs/"><code>GeNIe/SMILE</code></a>: Implemented in C++, GeNIe is a useful, though somewhat dated, tool for working with Bayesian networks and influence diagrams. SMILE is the underlying engine. Both are free for academic use but are not open-source.</p>
  </li>
  <li>
    <p><a href="https://github.com/causalincentives/pycid"><code>PyCID</code></a>: Written in Python, PyCID is a specialized open-source library designed for working with causal influence diagrams.</p>
  </li>
</ul>

<h2>Conclusion</h2>

<p>This post has shown how influence diagrams can be used to model and solve decision problems under uncertainty. By applying the arc-reversal and node-reduction algorithms to the oil-field LIMID, we obtained a maximum expected utility of <b>721</b> and confirmed that the optimal strategy is to <b>skip the porosity test and buy the field</b>. As expected, this matches the recommendation from the equivalent decision tree discussed in <a href="https://ferjorosa.github.io/blog/2025/06/08/decision-theory-I.html"><u>Part I</u></a>.</p>

<p>Influence diagrams excel at capturing conditional independencies, which helps control the combinatorial explosion that often plagues decision trees. However, their main limitation is that they are best suited for symmetric problems. Highly asymmetric scenarios may require introducing artificial states or degenerate probabilities, which can increase both the size and computational complexity of the model.</p>

<p><strong>In the next post</strong>, we’ll demonstrate how to build and evaluate LIMIDs using open-source tools like <a href="https://pyagrum.readthedocs.io"><code>PyAgrum</code></a>, perform sensitivity analysis and value-of-information calculations, and explore advanced features such as multiple utility nodes and decision planes. Finally, we’ll show how to integrate Gradio with PyAgrum to create interactive, web-based decision problem demos, making it easy to experiment with and communicate complex decision models.</p>

<!-- Future exploration could delve deeper into topics such as causality, the relationship with Large 
Language Models (LLMs), and handling continuous probabilistic variables. -->

<h2 id="references">References</h2>

<ol>
  <li>Shenoy, P. P. (2009). <a href="https://pshenoy.ku.edu/Papers/EOLSS09.pdf"><u>Decision trees and influence diagrams</u></a>. Encyclopedia of life support systems, 280-298.
<br /><br /></li>
  <li>Rodriguez, F. (2025, June 8). <a href="https://ferjorosa.github.io/blog/2025/06/08/decision-theory-I.html">Introduction to decision theory: Part I</a>. 
<br /><br /></li>
  <li>Wikipedia article on <u><a href="https://en.wikipedia.org/wiki/Conditional_independence">conditional independence</a></u>.
<br /><br /></li>
  <li>Wikipedia article on <u><a href="https://en.wikipedia.org/wiki/Tree_diagram_(probability_theory)">probability trees</a></u>.
<br /><br /></li>
  <li>Wikipedia article on <u><a href="https://en.wikipedia.org/wiki/Bayesian_network">Bayesian networks</a></u>.
<br /><br /></li>
  <li>Howard, R. A., &amp; Matheson, J. E. (1984). <u>Influence diagrams</u>. The Principles and Applications of Decision Analysis (Vol. II), 719-762.
<br /><br /></li>
  <li>Bielza, C., &amp; Shenoy, P. P. (1999). <a href="https://cig.fi.upm.es/wp-content/uploads/2024/01/A-Comparison-of-Graphical-Techniques-for-Asymmetric-Decision-Problems.pdf"><u>A comparison of graphical techniques for asymmetric decision problems</u></a>. European Journal of Operational Research, 119(1), 1-13.
<br /><br /></li>
  <li>Lauritzen, S. L., &amp; Nilsson, D. (2001). <a href="https://web.math.ku.dk/~lauritzen/papers/limids.pdf"><u>Representing and solving decision problems with limited information</u></a>. Management Science, 47(9), 1235-1251.
<br /><br /></li>
  <li>Shachter, R. D. (1986). <a href="http://www.cis.umassd.edu/~x2zhang/courses/CIS561/readings/EvaluatingID.pdf"><u>Evaluating influence diagrams</u></a>. Operations research, 34(6), 871-882.
<br /><br /></li>
  <li>Wikipedia article on <u><a href="https://artint.info/3e/html/ArtInt3e.Ch4.S5.html">variable elimination</a></u>.
<br /><br /></li>
  <li>Jensen, F., Jensen, F. V., &amp; Dittmer, S. (1994). <a href="https://arxiv.org/pdf/1302.6824"><u>From influence diagrams to junction trees</u></a>. In Proceedings of the 10th Conference on Uncertainty in Artificial Intelligence (UAI) (pp. 367-373).
<br /><br /></li>
  <li>Madsen, A. L., &amp; Jensen, F. (1999). <a href="https://arxiv.org/pdf/1301.6716"><u>Lazy evaluation of symmetric Bayesian decision problems</u></a>. In Proceedings of the Fifteenth Conference on Uncertainty in Artificial Intelligence (UAI) (pp. 382–390). Morgan Kaufmann.
<br /><br /></li>
  <li>Shachter, R. D., &amp; Kenley, C. R. (1989). <a href="https://www.jstor.org/stable/2632102"><u>Gaussian influence diagrams</u></a>. Management Science, 35(5), 527–550.
<br /><br /></li>
  <li>Jenzarli, A. (1995). <a href="https://proceedings.mlr.press/r0/jenzarli95a/jenzarli95a.pdf"><u>Solving influence diagrams using Gibbs sampling</u></a>. In Pre-proceedings of the Fifth International Workshop on Artificial Intelligence and Statistics (pp. 278-284). PMLR.
<br /><br /></li>
  <li>Bielza, C., Müller, P., &amp; Ríos-Insua, D. (1999). <a href="https://cig.fi.upm.es/wp-content/uploads/2024/01/Decision-Analysis-by-Augmented-Probability-Simulation.pdf"><u>Decision analysis by augmented probability simulation</u></a>. Management Science, 45(7), 995–1007.
<br /><br /></li>
  <li>Cobb, B. R., &amp; Shenoy, P. P. (2008). <a href="https://doi.org/10.1016/j.ejor.2007.01.036"><u>Decision making with hybrid influence diagrams using mixtures of truncated exponentials</u></a>. European Journal of Operational Research, 186(1), 261-275.
<br /><br /></li>
  <li>Winn, J., &amp; Bishop, C. M. (2005). <a href="https://jmlr.org/papers/volume6/winn05a/winn05a.pdf"><u>Variational message passing</u></a>. Journal of Machine Learning Research, 6, 661–694.
<br /><br /></li>
  <li>Shafer, G., &amp; Shenoy, P. P. (1990). <a href="https://kuscholarworks.ku.edu/server/api/core/bitstreams/c353aa52-11ad-46c0-b867-f5d05f7f1962/content"><u>Probability Propagation</u></a>. Annals of Mathematics and Artificial Intelligence, 2, 327-352.</li>
</ol>]]></content><author><name>Fernando Rodriguez</name></author><category term="blog" /><category term="Decision Theory" /><summary type="html"><![CDATA[Explores the strengths and limitations of decision trees, introduces influence diagrams as a scalable alternative, details their evaluation using the arc-reversal / node-reduction algorithm, and surveys Python libraries (PyAgrum, PyCID) for practical decision analysis.]]></summary></entry><entry><title type="html">Introduction to Decision Theory: Part I</title><link href="https://ferjorosa.github.io/blog/2025/06/08/decision-theory-I.html" rel="alternate" type="text/html" title="Introduction to Decision Theory: Part I" /><published>2025-06-08T00:00:00+00:00</published><updated>2025-06-08T00:00:00+00:00</updated><id>https://ferjorosa.github.io/blog/2025/06/08/decision-theory-I</id><content type="html" xml:base="https://ferjorosa.github.io/blog/2025/06/08/decision-theory-I.html"><![CDATA[<details style="margin: 1em 0; padding: 0.5em; border: 1px solid #ddd; border-radius: 4px;">
<summary style="cursor: pointer; font-weight: bold; padding: 0.5em;">Table of Contents</summary>

<ul style="margin-top: 0.5em;">
  <li style="margin-bottom: 0.5em;"><a href="#the-challenge-of-decision-making">The Challenge of Decision-Making</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#the-anatomy-of-a-decision-problem">The Anatomy of a Decision Problem</a>
    <ul style="margin-top: 0.3em;">
      <li style="margin-bottom: 0.3em;"><a href="#structuring-the-oil-field-decision-problem">Structuring the Oil Field Decision Problem</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#calculating-expected-monetary-value">Calculating Expected Monetary Value</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#beyond-money-utility-and-risk-preferences">Beyond Money: Utility and Risk Preferences</a></li>
    </ul>
  </li>
  <li style="margin-bottom: 0.5em;"><a href="#decision-analysis-a-dynamic-iterative-process">Decision Analysis: A Dynamic, Iterative Process</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#when-new-information-becomes-an-option">When New Information Becomes an Option</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#modelling-the-problem-with-a-decision-tree">Modelling the Problem with a Decision Tree</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#evaluating-the-decision-tree">Evaluating the Decision Tree</a>
    <ul style="margin-top: 0.3em;">
      <li style="margin-bottom: 0.3em;"><a href="#perform-the-test-and-the-result-is-pass">Perform the Test and the Result is "pass"</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#perform-the-test-and-the-result-is-fail">Perform the Test and the Result is "fail"</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#no-test-performed">No Test Performed</a></li>
      <li style="margin-bottom: 0.3em;"><a href="#evaluating-the-root-decision-test-vs-no-test">Evaluating the Root Decision: Test vs. No Test</a></li>
    </ul>
  </li>
  <li style="margin-bottom: 0.5em;"><a href="#conclusion">Conclusion</a></li>
  <li style="margin-bottom: 0.5em;"><a href="#references">References</a></li>
</ul>

</details>

<h2 id="the-challenge-of-decision-making">The Challenge of Decision-Making</h2>

<p>Imagine you are the CEO of an oil company and you are offered the opportunity to purchase a new oil field. Like any diligent executive, you gather your team to examine satellite images, geological surveys, and consult the team’s experience with similar fields in the region.</p>

<p>This research helps form your initial assessment of the field’s potential. However, the reality is that until you actually start drilling, there’s no way to know for sure how much oil is down there. This leaves you with a classic dilemma:</p>

<ul>
  <li>Play it safe and walk away.</li>
  <li>Make a calculated bet based on the evidence you’ve gathered.</li>
</ul>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-06-08-decision-theory-I/oil_field_image.jpg" alt="Oil field image" width="400" />
    </td>
    <td align="center">
      <img src="/assets/2025-06-08-decision-theory-I/oil_field_heatmap.jpg" alt="Oil field heatmap" width="400" />
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <i><b>Figure 1.</b> Satellite imagery and heatmap of the oil field (<a href="https://www.satimagingcorp.com/applications/energy/exploration/oil-exploration/">source</a>)</i>
    </td>
  </tr>
</table>
</center>

<p>This tension between what you know, what you don’t know, and what you truly value is at the heart of every important decision. How do you weigh the potential upside against the risk of a bad draw? How much should your assessment count in the final call?</p>

<p><u><a href="https://en.wikipedia.org/wiki/Decision_theory">Decision Theory</a></u> offers a framework to answer exactly these questions. It’s about systematically looking at the likelihood of different scenarios and weighing them against how much you value each potential result. By doing this, it guides you toward the action that’s most likely to give you the best overall outcome.</p>

<p>Let’s return to the oil field example. Suppose you’ve sized up the field and think it could fall into one of three quality levels:</p>
<ul>
  <li><strong>High</strong>, promising oil reserves.</li>
  <li><strong>Medium</strong>, meaning a decent output but nothing groundbreaking.</li>
  <li><strong>Low</strong>, where you’d barely break even or could even end up losing money.</li>
</ul>

<p>The dilemma, then, becomes quite clear. If you decide to buy and the field turns out to be high-quality, you’ve struck gold. If you buy and it’s low-quality, you’ll lose your investment. But if you choose not to buy, you avoid any potential loss, though you might also miss out on a good opportunity.</p>

<h2 id="the-anatomy-of-a-decision-problem">The Anatomy of a Decision Problem</h2>

<p>At its core, any decision problem can be broken down into a few fundamental components: the actions we can take, the uncertain conditions that might influence the outcome (often referred to as states of nature), the probabilities we assign to these conditions based on our best estimates, and the potential outcomes for each action under each condition.</p>

<p>So, let’s use the decision theory framework for our oil field case.</p>

<h3 id="structuring-the-oil-field-decision-problem">Structuring the Oil Field Decision Problem</h3>

<p>First, what are the <span style="color:red; font-weight:bold;">possible actions</span>? The company faces a straightforward choice: either <span style="color:red;">buy the oil field</span>, investing capital now with the hope of future profits, or <span style="color:red;">do not buy</span>, which means avoiding the risk but also potentially missing out on gains.</p>

<p>Next, we consider the <span style="color:purple; font-weight:bold;">states of nature</span> – the things we can’t control. In this case, it’s the true quality of the oil field. We’ve simplified this into three possibilities: the field could be <span style="color:purple;">high</span> quality, <span style="color:purple;">medium</span> quality, or <span style="color:purple;">low</span> quality.</p>

<p>Then, we need to assign <span style="color:purple; font-weight:bold;">probabilities</span> to these states. The company doesn’t know the field’s true quality for sure, but based on all the geological data and expert opinions, they’ve estimated the chances: a <span style="color:purple;">35%</span> chance of it being high quality, a <span style="color:purple;">45%</span> chance for medium quality, and a <span style="color:purple;">20%</span> chance for low quality.</p>

<p>Finally, let’s look at the <span style="color:blue; font-weight:bold;">outcomes</span>, specifically the financial implications (in millions of dollars) for each scenario. These are summarized in the table below:</p>

<center>
<table align="center">
  <tr>
    <th style="color:red;">Action</th>
    <th style="color:purple;">Field Quality</th>
    <th style="color:blue;">Monetary Outcome</th>
  </tr>
  <tr>
    <td style="color:red;">Buy</td>
    <td style="color:purple;">High</td>
    <td style="color:blue;">+$1250M</td>
  </tr>
  <tr>
    <td style="color:red;">Buy</td>
    <td style="color:purple;">Medium</td>
    <td style="color:blue;">+$630M</td>
  </tr>
  <tr>
    <td style="color:red;">Buy</td>
    <td style="color:purple;">Low</td>
    <td style="color:blue;">+$0M</td>
  </tr>
  <tr>
    <td style="color:red;">Do not buy</td>
    <td style="color:purple;">Any</td>
    <td style="color:blue;">+$350M</td>
  </tr>
</table>
</center>

<blockquote>
  <p><strong>Why is there a profit for not buying?</strong></p>

  <p>This could represent a baseline alternative, like investing the capital elsewhere for a guaranteed return of $350M.</p>
</blockquote>

<h3 id="calculating-expected-monetary-value">Calculating Expected Monetary Value</h3>

<p>So, how do we weigh these possibilities financially? A common approach is to calculate the Expected Monetary Value (EMV). For the ‘Buy’ option, the EMV considers each potential outcome, its likelihood, and its financial value. Here’s how it breaks down:</p>

\[\begin{align*}
\mathbb{E}[MV(\text{Buy})] &amp;= (0.35 \cdot \$1250\text{M}) + (0.45 \cdot \$630\text{M}) + (0.20 \cdot \$0\text{M}) \\
&amp;= \$437.5\text{M} + \$283.5\text{M} + \$0\text{M} \\
&amp;= \$721\text{M}
\end{align*}\]

<p>This gives us an EMV of $721M if we decide to buy. Now, let’s look at the ‘Do not buy’ option. Its EMV is simpler:</p>

\[\mathbb{E}[MV(\text{Do not buy})] = \$350\text{M}\]

<p>Purely from an EMV perspective, buying the field seems to be the stronger choice, offering an expected $721M versus $350M.</p>

<h3 id="beyond-money-utility-and-risk-preferences">Beyond Money: Utility and Risk Preferences</h3>

<p>But EMV doesn’t always tell the whole story. What if not making a profit from this project could be disastrous for our company, or on the flip side, a big payout isn’t really necessary? EMV treats every dollar the same. However, real-world decisions often depend on how much risk we’re willing to take.</p>

<p>That’s where <a href="https://plato.stanford.edu/entries/rationality-normative-utility/"><u>utility theory</u></a> comes in. Instead of just looking at dollar amounts, we give each outcome a “utility score” to show how much it really matters to us. EMV assumes linear utility, which only holds if the decision maker is risk-neutral. Utility theory allows us to account for different risk preferences. Then we calculate an Expected Utility (EU) by weighing these scores by their probabilities (<a href="https://dwulff.github.io/_Goodchoices/Literature/Von%20NeumannMorgenstern1944TheoryOfGamesAndEconomicBehaviour.pdf"><u>von Neumann &amp; Morgenstern, 1944</u></a>), just like we do with EMV.</p>

<p><strong>So how do we figure out these utility scores?</strong> We start by anchoring the utility scale to simplify comparisons:</p>

<ul>
  <li>Set best monetary outcome → \(U(\$1250\text{M}) = 1\)</li>
  <li>Set worst monetary outcome → \(U(\$0) = 0\)</li>
</ul>

<p>Then, we need to find utility values for those outcomes in the middle ($350M, $630M). This depends on the 
<strong>decision maker’s risk preferences</strong>. One popular approach is the <a href="https://ontosight.ai/glossary/term/von-neumann-morgenstern-standard-gamble-theory--679f4e9e38099fda3c01d216"><u>standard gamble</u></a>. In this method, you ask the decision maker what probability of achieving the best outcome (i.e., $1250M) they would accept in a lottery compared to taking a guaranteed amount.</p>

<p>For instance, consider the $350M outcome:</p>

<p><em>“Would you rather take a sure $350M, or a gamble with a 70% chance of $1250M and 30% chance of $0M?”</em></p>

<p>If they say they’re indifferent, we assign: \(U(\$350\text{M}) = 0.7\).</p>

<p>Using the same logic for the $630M outcome:</p>

<p><em>“Would you rather take a sure $630M, or a gamble with a 90% chance of $1250M and 10% chance of $0M?”</em></p>

<p>If they express indifference here as well, then: \(U(\$630\text{M}) = 0.9\).</p>

<center>
<table align="center">
  <tr>
    <th style="color:red;">Action</th>
    <th style="color:purple;">Field Quality</th>
    <th style="color:blue;">Monetary Outcome</th>
    <th style="color:blue;">Utility Outcome</th>
  </tr>
  <tr>
    <td style="color:red;">Buy</td>
    <td style="color:purple;">High</td>
    <td style="color:blue;">+$1250M</td>
    <td style="color:blue;">1</td>    
  </tr>
  <tr>
    <td style="color:red;">Buy</td>
    <td style="color:purple;">Medium</td>
    <td style="color:blue;">+$630M</td>
    <td style="color:blue;">0.9</td>        
  </tr>
  <tr>
    <td style="color:red;">Buy</td>
    <td style="color:purple;">Low</td>
    <td style="color:blue;">+$0M</td>
    <td style="color:blue;">0</td>    
  </tr>
  <tr>
    <td style="color:red;">Do not buy</td>
    <td style="color:purple;">Any</td>
    <td style="color:blue;">+$350M</td>
    <td style="color:blue;">0.7</td>    
  </tr>
</table>
</center>

<p>Let’s compute the EU:</p>

\[\begin{align*}
&amp;\mathbb{E}[U(\text{Buy})] = (0.35 \cdot 1.0) + (0.45 \cdot 0.9) + (0.20 \cdot 0.0) = 0.755 \\ \\
&amp;\mathbb{E}[U(\text{Do not buy})] = 0.7
\end{align*}\]

<p>EMV suggests to <strong>Buy</strong> ($721M &gt; $350M). EU also suggests to <strong>Buy</strong>, but the margin is smaller (0.755 &gt; 0.7). A more risk-averse person (e.g., someone with \(U(\$350\text{M})=0.8\)) would flip the decision.</p>

<p>Previous case is just a hypothetical example. For this article, we’ll keep things straightforward and <strong>assume the decision maker is risk neutral</strong>. Therefore, in our decision tree analysis below, we can use Expected Utility (EU) where utility values are directly proportional to monetary values, so <strong>a utility of 1000 corresponds to $1000M</strong>, etc. This makes EU and EMV equivalent for our analysis. In reality, though, considering non-linear utility can change which option looks best.</p>

<blockquote>
  <p>Another well-known example illustrating EMV’s limitations is the <a href="https://en.wikipedia.org/wiki/St._Petersburg_paradox"><u>St. Petersburg Paradox</u></a>. In this scenario, a casino offers a gamble where a fair coin is tossed until heads appears. If the first head appears on the nth toss, the prize is \(2^{n}\). Assuming the game continues indefinitely and the casino has unlimited resources, the EMV is infinite. This suggests one should pay any amount to play, yet most people wouldn’t pay more than $8 - $16. The reason is that the large payouts are so improbable that we mentally discount them, thus creating the paradox.</p>
</blockquote>

<h2 id="decision-analysis-a-dynamic-iterative-process">Decision Analysis: A Dynamic, Iterative Process</h2>

<p>Decision-making isn’t a one-shot task. It’s a cycle of refinement. As new information emerges or priorities shift, we revisit and update our analysis. This structured approach ensures that our choices are not only well-founded but also adaptable.</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-06-08-decision-theory-I/decision_analysis.png" alt="Decision analysis process" width="220" />
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 2.</b> Flow diagram of the decision analysis process</i>
    </td>
  </tr>
</table>
</center>

<p>The process begins with getting clear on what we’re trying to achieve. Instead of a vague goal like “maximize profits,” we break it down into specific, measurable objectives. For our oil company, this means not only aiming for the highest return but also minimizing downside risk, limiting upfront costs, and ensuring the project aligns with their strategic reserves.</p>

<p>With these objectives in mind, the next step is to brainstorm all feasible actions, not just the obvious ones. Beyond simply buying or not buying the field, perhaps there’s a third path, like delaying the decision to commission an extra study for more data.</p>

<p>Once the alternatives are on the table, we model the decision. This involves structuring the uncertainties (like the field’s quality), assigning probabilities (a 35% chance of high quality, etc.), and mapping outcomes to their values. This is where tools like <u><a href="https://en.wikipedia.org/wiki/Decision_tree">decision trees</a></u> and <u><a href="https://en.wikipedia.org/wiki/Influence_diagram">influence diagrams</a></u> (i.e., decision networks) become useful for visualizing the entire problem.</p>

<p>With the model built, we can calculate the optimal path forward. As we saw, computing the EU helps us compare the options. Based on the EU, we know that buying is the stronger choice. But a good analysis doesn’t stop there. We need to ask, “what if?” This is the role of <u><a href="https://en.wikipedia.org/wiki/Sensitivity_analysis">sensitivity analysis</a></u>: testing how robust our decision is by tweaking the key inputs. What if the outcome for a “low quality” field isn’t breaking even, but a loss of $200M?</p>

\[\mathbb{E}[U(\text{Buy})] = (0.35 \cdot 1250) + (0.45 \cdot 630) + (0.20 \cdot -200) = 681.5\]

<p>The EU for buying is now 681.5, still the optimal choice, but the risk profile has clearly changed.</p>

<p>This stress-testing leads to the final step: implement or iterate. If the optimal choice proves robust and aligns with the company’s objectives, it’s time to move forward. But if the analysis reveals too much uncertainty or uncovers new risks, it’s a signal to revisit the earlier stages. Maybe the uncertainty is too high, and it’s worth gathering more data. Perhaps other variables, like environmental costs, need to be factored into the model. Or maybe new alternatives, like exploring a partnership to share the risk, have become more attractive.</p>

<h2 id="when-new-information-becomes-an-option">When New Information Becomes an Option</h2>

<p>Just as the company is about to move forward, a new opportunity arises: it can choose to perform a geological test before deciding whether to purchase the oil field. This test won’t reveal the true quality of the field, but it will measure the rock’s porosity, which measures how much empty space the rock contains that could hold oil. The test has two possible outcomes:</p>

<ul>
  <li><strong>Pass:</strong> Porosity is ≥ 15%, indicating a significant amount of pore (void) space in the rocks, which suggests a higher likelihood of finding oil.</li>
  <li><strong>Fail:</strong> Porosity is &lt; 15%, indicating less void space and therefore a lower potential for oil.</li>
</ul>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-06-08-decision-theory-I/rock_porosity.jpg" alt="Rock porosity illustration" width="600" />
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 3.</b> Reservoir quality illustrated through porosity and permeability characteristics (<a href="https://www.parliament.wa.gov.au/publications/tabledpapers.nsf/displaypaper/3913541ae03e783bf52cf5b948257ee5000a9d20/$file/3541.pdf">source</a>)</i>
    </td>
  </tr>
</table>
</center>

<p>In an ideal situation, the test would be extremely accurate. However, real-world tests are not perfect. The table below illustrates these measurement inaccuracies by presenting the conditional probability of each test result based on the quality of the oil field:</p>

<table>
  <tr>
    <th></th>
    <th><span style="color: purple;">high</span></th>
    <th><span style="color: purple;">medium</span></th>
    <th><span style="color: purple;">low</span></th>      
  </tr>
  <tr>
    <td><span style="color: purple;">pass</span></td>
    <td>0.95</td>
    <td>0.7</td>
    <td>0.15</td>      
  </tr>
  <tr>
    <td><span style="color: purple;">fail</span></td>
    <td>0.05</td>
    <td>0.3</td>
    <td>0.85</td> 
  </tr>
</table>

<p><strong>The test costs $30 million</strong>, and even after getting the results, the company still has to decide whether to buy the field. This means there are now two decisions to make: first, whether to conduct the test, and second, whether to purchase the field based on the test results. This kind of two-step decision-making, where each choice affects the next and involves probabilities, can’t be handled with simple payoff tables. Instead, we’ll need to use a decision tree or an influence diagram to figure it out.</p>

<h2 id="modelling-the-problem-with-a-decision-tree">Modelling the Problem with a Decision Tree</h2>

<p>Decision trees, originating from the work of <a href="https://gwern.net/doc/statistics/decision/1961-raiffa-appliedstatisticaldecisiontheory.pdf"><u><b>Raiffa &amp; Schlaifer (1961)</b></u></a>, are a powerful tool for visualizing and analyzing decision-making problems. They map out the sequence of decisions and chance events, providing a clear picture of the possible outcomes and their associated probabilities. A decision tree consists of three types of nodes:</p>

<ul>
  <li>
    <p><span style="color:red;"><strong>Decision nodes</strong></span>. These are points where you need make a choice and take an action. In our case, the first decision here is whether to do the geological test. If the test is conducted, the next decision is whether to buy the oil field based on the test results.</p>
  </li>
  <li>
    <p><span style="color:purple;"><strong>Chance nodes</strong></span>. These nodes represent states of nature or events that can affect the outcome. For our problem, the chance nodes include the possible results of the geological test and the actual quality of the oil field.</p>
  </li>
  <li>
    <p><span style="color:blue;"><strong>Outcome nodes</strong></span>. These are the final nodes that show the result of a particular path through the tree.</p>
  </li>
</ul>

<p>To construct the tree, begin by identifying the root node, which represents the first event observed over time: either a decision or an uncertainty factor. From the root, add chance or decision nodes, outlining the different paths to follow, until you reach a terminal node, where the corresponding consequence will be indicated. The decision tree is then completed by including the utilities at the terminal nodes. At these nodes, a value is assigned to a final result, assuming this result has been achieved without considering probabilities.</p>

<p>Below is the decision tree for the oil drilling scenario. In this diagram, <span style="color:red;"><strong>T</strong></span> represents the decision node for conducting the test, <span style="color:purple;"><strong>R</strong></span> indicates the test result, <span style="color:red;"><strong>B</strong></span> denotes the decision to buy or not buy, and <span style="color:purple;"><strong>Q</strong></span> signifies the quality of the oil field.</p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-06-08-decision-theory-I/oil_decision_tree.png" alt="Oil decision tree" width="400" />
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 4.</b> Oil decision tree</i>
    </td>
  </tr>
</table>
</center>

<h2 id="evaluating-the-decision-tree">Evaluating the Decision Tree</h2>

<p>To figure out the best course of action in a decision tree, we need to look at every possible decision path. This boils down to two key steps:</p>

<ol>
  <li><strong>Estimating Probabilities</strong>. This involves using both marginal and conditional probabilities.</li>
  <li><strong>Calculating Expected Utilities</strong>. This requires evaluating the outcomes for each decision.</li>
</ol>

<p>Same as before, the EU of a decision is computed by multiplying the utility of each outcome by its associated probability and summing these products across all possible outcomes under that decision. Since we’re assuming risk neutrality, utilities are proportional to monetary values. The decision with the highest EU at each decision node is the optimal choice.</p>

<h3 id="perform-the-test-and-the-result-is-pass">Perform the Test and the Result is "pass"</h3>

<p>From the test accuracy table, we know  \(P(R \mid Q)\), which is the probability of each test result given the true field quality. But to evaluate the decision tree, we need the opposite: \(P(Q \mid R)\), the probability of each field quality given the observed test result. This is important because once we see the test result, we have to decide whether to buy based on the updated belief about the field quality. We’ll use <strong>Bayes’ Theorem</strong> to calculate these posterior probabilities of <span style="color:purple;"><strong>Q</strong></span> given that the test result is a “pass”.</p>

<p>First, we compute the marginal probability of obtaining a “pass” result:</p>

\[\begin{align*}
P(R = \text{pass}) &amp;= P(R = \text{pass} | Q = \text{high}) \cdot P(Q = \text{high}) \\
&amp;\quad + P(R = \text{pass} | Q = \text{medium}) \cdot P(Q = \text{medium}) \\
&amp;\quad + P(R = \text{pass} | Q = \text{low}) \cdot P(Q = \text{low}) \\
&amp;= 0.95 \cdot 0.35 + 0.7 \cdot 0.45 + 0.15 \cdot 0.20 = 0.3325 + 0.315 + 0.03 = 0.6775
\end{align*}\]

<p>Then, we apply the theorem:</p>

\[\begin{align*}
P(Q = \text{high} \mid R = \text{pass}) &amp;= \frac{0.95 \cdot 0.35}{0.6775} = 0.4908 \\
P(Q = \text{medium} \mid R = \text{pass}) &amp;= \frac{0.7 \cdot 0.45}{0.6775} = 0.4649 \\
P(Q = \text{low} \mid R = \text{pass}) &amp;= \frac{0.15 \cdot 0.20}{0.6775} = 0.0443
\end{align*}\]

<p>We now compute the EU of buying the oil field after a “pass” result:</p>

\[\mathbb{E}[U \mid R = \text{pass}, \text{Buy}] = 0.4908 \cdot 1220 + 0.4649 \cdot 600 + 0.0443 \cdot (-30) = 876.39\]

<p>We compare the EU of buying versus not buying after a “pass” result:</p>

<ul>
  <li><strong>Buying:</strong> 876.39</li>
  <li><strong>Not Buying:</strong> 320</li>
</ul>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
Since 876.39 &gt; 320, it is better to <b>buy</b> the oil field if the test result is <b>pass</b>.
</div>
<p><br /></p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-06-08-decision-theory-I/evaluated_oil_tree_1.png" alt="Evaluated Oil decision tree #1" width="400" />
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 5.</b> Evaluated Oil decision tree #1</i>
    </td>
  </tr>
</table>
</center>

<h3 id="perform-the-test-and-the-result-is-fail">Perform the test and the result is "fail"</h3>

<p>As in the previous scenario, we first calculate the marginal probability of obtaining a “fail” result:</p>

\[P(R = \text{fail}) = 1 - P(R = \text{pass}) = 1 - 0.6775 = 0.3225\]

<p>Next, we apply <strong>Bayes’ Theorem</strong> to determine the posterior probabilities of <span style="color:purple;"><strong>Q</strong></span> given that the test result is “fail”:</p>

\[\begin{align*}
P(Q = \text{high} \mid R = \text{fail}) &amp;= \frac{0.05 \cdot 0.35}{0.3225} = 0.0543 \\
P(Q = \text{medium} \mid R = \text{fail}) &amp;= \frac{0.3 \cdot 0.45}{0.3225} = 0.4186 \\
P(Q = \text{low} \mid R = \text{fail}) &amp;= \frac{0.85 \cdot 0.20}{0.3225} = 0.5271
\end{align*}\]

<p>We then calculate the EU of purchasing the oil field after a “fail” result:</p>

\[\mathbb{E}[U \mid R = \text{fail}, \text{Buy}] = 0.0543 \cdot 1220 + 0.4186 \cdot 600 + 0.5271 \cdot (-30) = 301.59\]

<p>We compare the EU of buying versus not buying after a “fail” result:</p>

<ul>
  <li><strong>Buying:</strong> 301.59</li>
  <li><strong>Not Buying:</strong> 320</li>
</ul>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
  Since 301.59 &lt; 320, it is better to <strong>not buy</strong> the oil field if the test result is <strong>fail</strong>.
</div>
<p><br /></p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-06-08-decision-theory-I/evaluated_oil_tree_2.png" alt="Evaluated Oil decision tree #2" width="400" />
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 6.</b> Evaluated Oil decision tree #2</i>
    </td>
  </tr>
</table>
</center>

<h3 id="no-test-performed">No Test Performed</h3>

<p>If the company decides not to conduct the porosity test, it must choose whether to purchase the oil field based solely on the <strong>prior probabilities</strong> of the field’s quality.</p>

<p>We calculate the EU of purchasing the field using the provided prior distribution for field quality:</p>

\[\begin{aligned}
\mathbb{E}[U \mid \text{No test}, \text{Buy}] &amp;= 0.35 \cdot 1250 + 0.45 \cdot 630 + 0.20 \cdot 0 \\
&amp;= 437.5 + 283.5 + 0 \\
&amp;= 721 \\
\end{aligned}\]

<p>We then compare the EU of buying versus not buying:</p>

<ul>
  <li><strong>Buying:</strong> 721</li>
  <li><strong>Not Buying:</strong> 350</li>
</ul>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
Since 721 &gt; 350, it is better to <b>buy</b> the oil field if the company opts <b>not to test</b>.
</div>
<p><br /></p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-06-08-decision-theory-I/evaluated_oil_tree_3.png" alt="Evaluated Oil decision tree #3" width="400" />
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 7.</b> Evaluated Oil decision tree #3</i>
    </td>
  </tr>
</table>
</center>

<h3 id="evaluating-the-root-decision-test-vs-no-test">Evaluating the Root Decision: Test vs. No Test</h3>

<p>The final step is to determine whether the company should <strong>conduct the porosity test</strong> or <strong>proceed without testing</strong>. This hinges on comparing the EU of both options.</p>

<p>If the company performs the test, the overall EU is computed by weighting the outcomes of both possible test results:</p>

\[\begin{aligned}
\mathbb{E}[U \mid \text{Test}] &amp;= P(R = \text{pass}) \cdot \mathbb{E}[U \mid R = \text{pass}] \\
&amp;\quad + P(R = \text{fail}) \cdot \mathbb{E}[U \mid R = \text{fail}] \\
&amp;= 0.6775 \cdot 876.39 + 0.3225 \cdot 320 \\
&amp;= 696.95 
\end{aligned}\]

<p>Here, we assume the company <strong>buys</strong> the field if the test <strong>passes</strong>, and <strong>does not buy</strong> if it <strong>fails</strong> (i.e., the rational decision). Without conducting the test, the company’s best decision is to buy the field outright, resulting in an EU of 721.</p>

<p>We then compare the options:</p>

<ul>
  <li><strong>Test:</strong> 696.95</li>
  <li><strong>No Test:</strong> 721</li>
</ul>

<div style="background-color: #e0f7fa; padding: 10px; border-radius: 5px;">
Since 721 &gt; 696.95, the company should <b>not perform the test</b> and proceed directly to <b>buy</b> the oil field.
</div>
<p><br /></p>

<center>
<table>
  <tr>
    <td align="center">
      <img src="/assets/2025-06-08-decision-theory-I/evaluated_oil_tree_4.png" alt="Evaluated Oil decision tree #4" width="400" />
    </td>
  </tr>
  <tr>
    <td align="center">
      <i><b>Figure 8.</b> Evaluated Oil decision tree #4</i>
    </td>
  </tr>
</table>
</center>

<h2 id="conclusion">Conclusion</h2>

<p>In this post, we explored the foundations of decision theory through a practical investment scenario. We learned how to structure decision problems by identifying actions, uncertainties, probabilities, and outcomes. We looked at how to use EU to guide decision-making, and how risk preferences can shape the optimal choice. We also introduced decision trees as a valuable tool for analyzing sequential decisions under uncertainty, and showed how new information, such as a geological test result, can be incorporated into the analysis.</p>

<p><strong>In the next post</strong>, we’ll discuss the limitations of decision trees and introduce influence diagrams, which offer a more compact and flexible way to represent complex decision problems with multiple variables and dependencies.</p>

<p><strong>For more examples</strong> of decision analysis, check out:</p>
<ul>
  <li><a href="https://github.com/ferjorosa/decision-theory-llms/tree/main/decision_problems/ride_hailing">Ride-hailing subscription service</a>: Should a ride-hailing company offer a retention deal to prevent customer churn?</li>
  <li><a href="https://github.com/ferjorosa/decision-theory-llms/tree/main/decision_problems/automated_logistics_center">Logistics center automation</a>: Should an e-commerce company upgrade its logistics center with robotics?</li>
</ul>

<p><strong>To read more</strong> about decision theory and its applications consider the following bibliography:</p>

<center>
<table>
  <tr>
    <th>Book Cover</th>
    <th>Reference</th>
    <th>Key Focus</th>
  </tr>
  <tr>
    <td align="center"><img src="/assets/2025-06-08-decision-theory-I/howard_matheson_1983.jpg" width="100" height="100" style="object-fit: cover;" /></td>
    <td><strong>Howard &amp; Matheson (1983)</strong><br /><em>Readings on Decision Analysis</em><br /><a href="https://gwern.net/doc/statistics/decision/1983-howard-readingsondecisionanalysis-v1.pdf">PDF link</a></td>
    <td>Classic collection of papers on decision analysis methodology and applications</td>
  </tr>
  <tr>
    <td align="center"><img src="/assets/2025-06-08-decision-theory-I/robert_clemens_1995.jpg" width="100" height="100" style="object-fit: cover;" /></td>
    <td><strong>Robert T. Clemens (1995)</strong><br /><em>Making Hard Decisions</em></td>
    <td>Practical guide to structuring decisions and handling uncertainty with real-world examples</td>
  </tr>
  <tr>
    <td align="center"><img src="/assets/2025-06-08-decision-theory-I/insua_lozoya_2002.jpg" width="100" height="100" style="object-fit: cover;" /></td>
    <td><strong>Ríos Insua et al. (2002)</strong><br /><em>Fundamentos de los Sistemas de Ayuda a la Decisión</em></td>
    <td>Comprehensive introduction to decision support systems with emphasis on theoretical foundations</td>
  </tr>
  <tr>
    <td align="center"><img src="/assets/2025-06-08-decision-theory-I/koller_friedman.jpg" width="100" height="100" style="object-fit: cover;" /></td>
    <td><strong>Koller &amp; Friedman (2009)</strong><br /><em>Probabilistic Graphical Models</em><br />(Ch. 22, 23)<br /><a href="http://mcb111.org/w06/KollerFriedman.pdf">PDF Link</a></td>
    <td>Advanced coverage of influence diagrams and their integration with probabilistic reasoning</td>
  </tr>
  <tr>
    <td align="center"><img src="/assets/2025-06-08-decision-theory-I/russel_norvig_2021.jpg" width="100" height="100" style="object-fit: cover;" /></td>
    <td><strong>Russell &amp; Norvig (2010)</strong><br /><em>AI: A Modern Approach</em><br />(Ch. 16)<br /><a href="http://lib.ysu.am/disciplines_bk/efdd4d1d4c2087fe1cbe03d9ced67f34.pdf">PDF Link</a></td>
    <td>Introduction to decision theory &amp; influence diagrams</td>
  </tr>  
</table>
</center>

<h2 id="references">References</h2>

<ol>
  <li>Wikipedia page on <u><a href="https://en.wikipedia.org/wiki/Decision_theory">decision theory</a></u>.
<br /><br /></li>
  <li>Stanford’s Encyclopedia page on <a href="https://plato.stanford.edu/entries/rationality-normative-utility/"><u>utility theory</u></a>.
<br /><br /></li>
  <li>von Neumann J., Morgenstern, O. (1944). <a href="https://dwulff.github.io/_Goodchoices/Literature/Von%20NeumannMorgenstern1944TheoryOfGamesAndEconomicBehaviour.pdf"><u>Theory of Games and Economic Behavior</u></a>. Princeton University Press.
<br /><br /></li>
  <li>Ontosight article on <a href="https://ontosight.ai/glossary/term/von-neumann-morgenstern-standard-gamble-theory--679f4e9e38099fda3c01d216"><u>standard gamble</u></a>.
<br /><br /></li>
  <li>Wikipedia article on <a href="https://en.wikipedia.org/wiki/St._Petersburg_paradox"><u>St. Petersburg Paradox</u></a>.
<br /><br /></li>
  <li>Wikipedia article on <u><a href="https://en.wikipedia.org/wiki/Decision_tree">decision trees</a></u>.
<br /><br /></li>
  <li>Wikipedia article on <u><a href="https://en.wikipedia.org/wiki/Influence_diagram">influence diagrams</a></u>.
<br /><br /></li>
  <li>Wikipedia article on <u><a href="https://en.wikipedia.org/wiki/Sensitivity_analysis">sensitivity analysis</a></u>.
<br /><br /></li>
  <li>Raiffa, H., Schlaifer, R. (1961). <a href="https://gwern.net/doc/statistics/decision/1961-raiffa-appliedstatisticaldecisiontheory.pdf"><u>Applied statistical decision theory</u></a>. John Wiley &amp; Sons.</li>
</ol>]]></content><author><name>Fernando Rodriguez</name></author><category term="blog" /><category term="Decision Theory" /><summary type="html"><![CDATA[An introduction to decision theory through a practical oil field investment example, covering key concepts like expected utility, risk preferences, and decision trees.]]></summary></entry></feed>