{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "2ef3a8ca",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:12.695007Z",
     "iopub.status.busy": "2026-10-02T14:42:12.694785Z",
     "iopub.status.idle": "2026-10-02T14:42:12.700935Z",
     "shell.execute_reply": "2026-10-02T14:42:12.699742Z"
    },
    "papermill": {
     "duration": 0.009906,
     "end_time": "2026-10-02T14:42:12.701538+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:12.691632+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "active-ipynb",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    from openmdao.utils.notebook_utils import notebook_mode  # noqa: F401\n",
    "except ImportError:\n",
    "    !python -m pip install openmdao[notebooks]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c99bcd0e",
   "metadata": {
    "papermill": {
     "duration": 0.001791,
     "end_time": "2026-10-02T14:42:12.717450+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:12.715659+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# ArmijoGoldsteinLS\n",
    "\n",
    "ArmijoGoldsteinLS checks bounds and backtracks to a point that satisfies them. From there,\n",
    "further backtracking is performed, until the termination criteria are satisfied.\n",
    "The main termination criteria is the Armijo-Goldstein condition, which checks for a sufficient\n",
    "decrease from the initial point by measuring the slope. There is also an iteration maximum.\n",
    "\n",
    "Here is a simple example where ArmijoGoldsteinLS is used to backtrack during the Newton solver's iteration on\n",
    "a system that contains an implicit component with 3 states that are confined to a small range of values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "3b3ce287",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:12.721859Z",
     "iopub.status.busy": "2026-10-02T14:42:12.721661Z",
     "iopub.status.idle": "2026-10-02T14:42:15.179499Z",
     "shell.execute_reply": "2026-10-02T14:42:15.178180Z"
    },
    "papermill": {
     "duration": 2.460887,
     "end_time": "2026-10-02T14:42:15.180076+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:12.719189+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "application/papermill.record/text/html": "<style>pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.output_html .hll { background-color: #ffffcc }\n.output_html { background: #f8f8f8; }\n.output_html .c { color: #3D7B7B; font-style: italic } /* Comment */\n.output_html .err { border: 1px solid #F00 } /* Error */\n.output_html .k { color: #008000; font-weight: bold } /* Keyword */\n.output_html .o { color: #666 } /* Operator */\n.output_html .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */\n.output_html .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */\n.output_html .cp { color: #9C6500 } /* Comment.Preproc */\n.output_html .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */\n.output_html .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */\n.output_html .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */\n.output_html .gd { color: #A00000 } /* Generic.Deleted */\n.output_html .ge { font-style: italic } /* Generic.Emph */\n.output_html .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */\n.output_html .gr { color: #E40000 } /* Generic.Error */\n.output_html .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.output_html .gi { color: #008400 } /* Generic.Inserted */\n.output_html .go { color: #717171 } /* Generic.Output */\n.output_html .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n.output_html .gs { font-weight: bold } /* Generic.Strong */\n.output_html .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.output_html .gt { color: #04D } /* Generic.Traceback */\n.output_html .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n.output_html .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n.output_html .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n.output_html .kp { color: #008000 } /* Keyword.Pseudo */\n.output_html .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n.output_html .kt { color: #B00040 } /* Keyword.Type */\n.output_html .m { color: #666 } /* Literal.Number */\n.output_html .s { color: #BA2121 } /* Literal.String */\n.output_html .na { color: #687822 } /* Name.Attribute */\n.output_html .nb { color: #008000 } /* Name.Builtin */\n.output_html .nc { color: #00F; font-weight: bold } /* Name.Class */\n.output_html .no { color: #800 } /* Name.Constant */\n.output_html .nd { color: #A2F } /* Name.Decorator */\n.output_html .ni { color: #717171; font-weight: bold } /* Name.Entity */\n.output_html .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */\n.output_html .nf { color: #00F } /* Name.Function */\n.output_html .nl { color: #767600 } /* Name.Label */\n.output_html .nn { color: #00F; font-weight: bold } /* Name.Namespace */\n.output_html .nt { color: #008000; font-weight: bold } /* Name.Tag */\n.output_html .nv { color: #19177C } /* Name.Variable */\n.output_html .ow { color: #A2F; font-weight: bold } /* Operator.Word */\n.output_html .w { color: #BBB } /* Text.Whitespace */\n.output_html .mb { color: #666 } /* Literal.Number.Bin */\n.output_html .mf { color: #666 } /* Literal.Number.Float */\n.output_html .mh { color: #666 } /* Literal.Number.Hex */\n.output_html .mi { color: #666 } /* Literal.Number.Integer */\n.output_html .mo { color: #666 } /* Literal.Number.Oct */\n.output_html .sa { color: #BA2121 } /* Literal.String.Affix */\n.output_html .sb { color: #BA2121 } /* Literal.String.Backtick */\n.output_html .sc { color: #BA2121 } /* Literal.String.Char */\n.output_html .dl { color: #BA2121 } /* Literal.String.Delimiter */\n.output_html .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n.output_html .s2 { color: #BA2121 } /* Literal.String.Double */\n.output_html .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */\n.output_html .sh { color: #BA2121 } /* Literal.String.Heredoc */\n.output_html .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */\n.output_html .sx { color: #008000 } /* Literal.String.Other */\n.output_html .sr { color: #A45A77 } /* Literal.String.Regex */\n.output_html .s1 { color: #BA2121 } /* Literal.String.Single */\n.output_html .ss { color: #19177C } /* Literal.String.Symbol */\n.output_html .bp { color: #008000 } /* Name.Builtin.Pseudo */\n.output_html .fm { color: #00F } /* Name.Function.Magic */\n.output_html .vc { color: #19177C } /* Name.Variable.Class */\n.output_html .vg { color: #19177C } /* Name.Variable.Global */\n.output_html .vi { color: #19177C } /* Name.Variable.Instance */\n.output_html .vm { color: #19177C } /* Name.Variable.Magic */\n.output_html .il { color: #666 } /* Literal.Number.Integer.Long */</style><div class=\"highlight\"><pre><span></span><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ImplCompTwoStatesArrays</span><span class=\"p\">(</span><span class=\"n\">om</span><span class=\"o\">.</span><span class=\"n\">ImplicitComponent</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    A Simple Implicit Component with an additional output equation.</span>\n\n<span class=\"sd\">    f(x,z) = xz + z - 4</span>\n<span class=\"sd\">    y = x + 2z</span>\n\n<span class=\"sd\">    Sol : when x = 0.5, z = 2.666</span>\n<span class=\"sd\">    Sol : when x = 2.0, z = 1.333</span>\n\n<span class=\"sd\">    Coupled derivs:</span>\n\n<span class=\"sd\">    y = x + 8/(x+1)</span>\n<span class=\"sd\">    dy_dx = 1 - 8/(x+1)**2 = -2.5555555555555554</span>\n\n<span class=\"sd\">    z = 4/(x+1)</span>\n<span class=\"sd\">    dz_dx = -4/(x+1)**2 = -1.7777777777777777</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_input</span><span class=\"p\">(</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_output</span><span class=\"p\">(</span><span class=\"s1\">&#39;y&#39;</span><span class=\"p\">,</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_output</span><span class=\"p\">(</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">,</span> <span class=\"mf\">2.0</span><span class=\"o\">*</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">ones</span><span class=\"p\">((</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">)),</span> <span class=\"n\">lower</span><span class=\"o\">=</span><span class=\"mf\">1.5</span><span class=\"p\">,</span>\n            <span class=\"n\">upper</span><span class=\"o\">=</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">2.6</span><span class=\"p\">,</span> <span class=\"mf\">2.5</span><span class=\"p\">,</span> <span class=\"mf\">2.65</span><span class=\"p\">])</span><span class=\"o\">.</span><span class=\"n\">reshape</span><span class=\"p\">((</span><span class=\"mi\">3</span><span class=\"p\">,</span><span class=\"mi\">1</span><span class=\"p\">)))</span>\n\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">maxiter</span> <span class=\"o\">=</span> <span class=\"mi\">10</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">atol</span> <span class=\"o\">=</span> <span class=\"mf\">1.0e-12</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">setup_partials</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">declare_partials</span><span class=\"p\">(</span><span class=\"n\">of</span><span class=\"o\">=</span><span class=\"s1\">&#39;*&#39;</span><span class=\"p\">,</span> <span class=\"n\">wrt</span><span class=\"o\">=</span><span class=\"s1\">&#39;*&#39;</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">apply_nonlinear</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"p\">,</span> <span class=\"n\">outputs</span><span class=\"p\">,</span> <span class=\"n\">residuals</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Don&#39;t solve; just calculate the residual.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n\n        <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">]</span>\n        <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">outputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;y&#39;</span><span class=\"p\">]</span>\n        <span class=\"n\">z</span> <span class=\"o\">=</span> <span class=\"n\">outputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">]</span>\n\n        <span class=\"n\">residuals</span><span class=\"p\">[</span><span class=\"s1\">&#39;y&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">y</span> <span class=\"o\">-</span> <span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"mf\">2.0</span><span class=\"o\">*</span><span class=\"n\">z</span>\n        <span class=\"n\">residuals</span><span class=\"p\">[</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">x</span><span class=\"o\">*</span><span class=\"n\">z</span> <span class=\"o\">+</span> <span class=\"n\">z</span> <span class=\"o\">-</span> <span class=\"mf\">4.0</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">linearize</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"n\">inputs</span><span class=\"p\">,</span> <span class=\"n\">outputs</span><span class=\"p\">,</span> <span class=\"n\">jac</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Analytical derivatives.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n\n        <span class=\"c1\"># Output equation</span>\n        <span class=\"n\">jac</span><span class=\"p\">[(</span><span class=\"s1\">&#39;y&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;x&#39;</span><span class=\"p\">)]</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">diag</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">]))</span>\n        <span class=\"n\">jac</span><span class=\"p\">[(</span><span class=\"s1\">&#39;y&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;y&#39;</span><span class=\"p\">)]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">diag</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">]))</span>\n        <span class=\"n\">jac</span><span class=\"p\">[(</span><span class=\"s1\">&#39;y&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;z&#39;</span><span class=\"p\">)]</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">diag</span><span class=\"p\">(</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">2.0</span><span class=\"p\">,</span> <span class=\"mf\">2.0</span><span class=\"p\">,</span> <span class=\"mf\">2.0</span><span class=\"p\">]))</span>\n\n        <span class=\"c1\"># State equation</span>\n        <span class=\"n\">jac</span><span class=\"p\">[(</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;z&#39;</span><span class=\"p\">)]</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"n\">inputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"mf\">1.0</span><span class=\"p\">)</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">eye</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n        <span class=\"n\">jac</span><span class=\"p\">[(</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;x&#39;</span><span class=\"p\">)]</span> <span class=\"o\">=</span> <span class=\"n\">outputs</span><span class=\"p\">[</span><span class=\"s1\">&#39;z&#39;</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">eye</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n</pre></div>\n",
      "application/papermill.record/text/latex": "\\begin{Verbatim}[commandchars=\\\\\\{\\}]\n\\PY{k}{class}\\PY{+w}{ }\\PY{n+nc}{ImplCompTwoStatesArrays}\\PY{p}{(}\\PY{n}{om}\\PY{o}{.}\\PY{n}{ImplicitComponent}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{    }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{    A Simple Implicit Component with an additional output equation.}\n\n\\PY{l+s+sd}{    f(x,z) = xz + z \\PYZhy{} 4}\n\\PY{l+s+sd}{    y = x + 2z}\n\n\\PY{l+s+sd}{    Sol : when x = 0.5, z = 2.666}\n\\PY{l+s+sd}{    Sol : when x = 2.0, z = 1.333}\n\n\\PY{l+s+sd}{    Coupled derivs:}\n\n\\PY{l+s+sd}{    y = x + 8/(x+1)}\n\\PY{l+s+sd}{    dy\\PYZus{}dx = 1 \\PYZhy{} 8/(x+1)**2 = \\PYZhy{}2.5555555555555554}\n\n\\PY{l+s+sd}{    z = 4/(x+1)}\n\\PY{l+s+sd}{    dz\\PYZus{}dx = \\PYZhy{}4/(x+1)**2 = \\PYZhy{}1.7777777777777777}\n\\PY{l+s+sd}{    \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}input}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{np}\\PY{o}{.}\\PY{n}{zeros}\\PY{p}{(}\\PY{p}{(}\\PY{l+m+mi}{3}\\PY{p}{,} \\PY{l+m+mi}{1}\\PY{p}{)}\\PY{p}{)}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}output}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{np}\\PY{o}{.}\\PY{n}{zeros}\\PY{p}{(}\\PY{p}{(}\\PY{l+m+mi}{3}\\PY{p}{,} \\PY{l+m+mi}{1}\\PY{p}{)}\\PY{p}{)}\\PY{p}{)}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{add\\PYZus{}output}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+m+mf}{2.0}\\PY{o}{*}\\PY{n}{np}\\PY{o}{.}\\PY{n}{ones}\\PY{p}{(}\\PY{p}{(}\\PY{l+m+mi}{3}\\PY{p}{,} \\PY{l+m+mi}{1}\\PY{p}{)}\\PY{p}{)}\\PY{p}{,} \\PY{n}{lower}\\PY{o}{=}\\PY{l+m+mf}{1.5}\\PY{p}{,}\n            \\PY{n}{upper}\\PY{o}{=}\\PY{n}{np}\\PY{o}{.}\\PY{n}{array}\\PY{p}{(}\\PY{p}{[}\\PY{l+m+mf}{2.6}\\PY{p}{,} \\PY{l+m+mf}{2.5}\\PY{p}{,} \\PY{l+m+mf}{2.65}\\PY{p}{]}\\PY{p}{)}\\PY{o}{.}\\PY{n}{reshape}\\PY{p}{(}\\PY{p}{(}\\PY{l+m+mi}{3}\\PY{p}{,}\\PY{l+m+mi}{1}\\PY{p}{)}\\PY{p}{)}\\PY{p}{)}\n\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{maxiter} \\PY{o}{=} \\PY{l+m+mi}{10}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{atol} \\PY{o}{=} \\PY{l+m+mf}{1.0e\\PYZhy{}12}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{setup\\PYZus{}partials}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{)}\\PY{p}{:}\n        \\PY{n+nb+bp}{self}\\PY{o}{.}\\PY{n}{declare\\PYZus{}partials}\\PY{p}{(}\\PY{n}{of}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{*}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{n}{wrt}\\PY{o}{=}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{*}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{apply\\PYZus{}nonlinear}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{inputs}\\PY{p}{,} \\PY{n}{outputs}\\PY{p}{,} \\PY{n}{residuals}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{        }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{        Don\\PYZsq{}t solve; just calculate the residual.}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n        \\PY{n}{x} \\PY{o}{=} \\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{n}{y} \\PY{o}{=} \\PY{n}{outputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n        \\PY{n}{z} \\PY{o}{=} \\PY{n}{outputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]}\n\n        \\PY{n}{residuals}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n}{y} \\PY{o}{\\PYZhy{}} \\PY{n}{x} \\PY{o}{\\PYZhy{}} \\PY{l+m+mf}{2.0}\\PY{o}{*}\\PY{n}{z}\n        \\PY{n}{residuals}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{=} \\PY{n}{x}\\PY{o}{*}\\PY{n}{z} \\PY{o}{+} \\PY{n}{z} \\PY{o}{\\PYZhy{}} \\PY{l+m+mf}{4.0}\n\n    \\PY{k}{def}\\PY{+w}{ }\\PY{n+nf}{linearize}\\PY{p}{(}\\PY{n+nb+bp}{self}\\PY{p}{,} \\PY{n}{inputs}\\PY{p}{,} \\PY{n}{outputs}\\PY{p}{,} \\PY{n}{jac}\\PY{p}{)}\\PY{p}{:}\n\\PY{+w}{        }\\PY{l+s+sd}{\\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\\PY{l+s+sd}{        Analytical derivatives.}\n\\PY{l+s+sd}{        \\PYZdq{}\\PYZdq{}\\PYZdq{}}\n\n        \\PY{c+c1}{\\PYZsh{} Output equation}\n        \\PY{n}{jac}\\PY{p}{[}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\\PY{p}{]} \\PY{o}{=} \\PY{o}{\\PYZhy{}}\\PY{n}{np}\\PY{o}{.}\\PY{n}{diag}\\PY{p}{(}\\PY{n}{np}\\PY{o}{.}\\PY{n}{array}\\PY{p}{(}\\PY{p}{[}\\PY{l+m+mf}{1.0}\\PY{p}{,} \\PY{l+m+mf}{1.0}\\PY{p}{,} \\PY{l+m+mf}{1.0}\\PY{p}{]}\\PY{p}{)}\\PY{p}{)}\n        \\PY{n}{jac}\\PY{p}{[}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\\PY{p}{]} \\PY{o}{=} \\PY{n}{np}\\PY{o}{.}\\PY{n}{diag}\\PY{p}{(}\\PY{n}{np}\\PY{o}{.}\\PY{n}{array}\\PY{p}{(}\\PY{p}{[}\\PY{l+m+mf}{1.0}\\PY{p}{,} \\PY{l+m+mf}{1.0}\\PY{p}{,} \\PY{l+m+mf}{1.0}\\PY{p}{]}\\PY{p}{)}\\PY{p}{)}\n        \\PY{n}{jac}\\PY{p}{[}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{y}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\\PY{p}{]} \\PY{o}{=} \\PY{o}{\\PYZhy{}}\\PY{n}{np}\\PY{o}{.}\\PY{n}{diag}\\PY{p}{(}\\PY{n}{np}\\PY{o}{.}\\PY{n}{array}\\PY{p}{(}\\PY{p}{[}\\PY{l+m+mf}{2.0}\\PY{p}{,} \\PY{l+m+mf}{2.0}\\PY{p}{,} \\PY{l+m+mf}{2.0}\\PY{p}{]}\\PY{p}{)}\\PY{p}{)}\n\n        \\PY{c+c1}{\\PYZsh{} State equation}\n        \\PY{n}{jac}\\PY{p}{[}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\\PY{p}{]} \\PY{o}{=} \\PY{p}{(}\\PY{n}{inputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{+} \\PY{l+m+mf}{1.0}\\PY{p}{)} \\PY{o}{*} \\PY{n}{np}\\PY{o}{.}\\PY{n}{eye}\\PY{p}{(}\\PY{l+m+mi}{3}\\PY{p}{)}\n        \\PY{n}{jac}\\PY{p}{[}\\PY{p}{(}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{,} \\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{x}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{)}\\PY{p}{]} \\PY{o}{=} \\PY{n}{outputs}\\PY{p}{[}\\PY{l+s+s1}{\\PYZsq{}}\\PY{l+s+s1}{z}\\PY{l+s+s1}{\\PYZsq{}}\\PY{p}{]} \\PY{o}{*} \\PY{n}{np}\\PY{o}{.}\\PY{n}{eye}\\PY{p}{(}\\PY{l+m+mi}{3}\\PY{p}{)}\n\\end{Verbatim}\n",
      "application/papermill.record/text/plain": "class ImplCompTwoStatesArrays(om.ImplicitComponent):\n    \"\"\"\n    A Simple Implicit Component with an additional output equation.\n\n    f(x,z) = xz + z - 4\n    y = x + 2z\n\n    Sol : when x = 0.5, z = 2.666\n    Sol : when x = 2.0, z = 1.333\n\n    Coupled derivs:\n\n    y = x + 8/(x+1)\n    dy_dx = 1 - 8/(x+1)**2 = -2.5555555555555554\n\n    z = 4/(x+1)\n    dz_dx = -4/(x+1)**2 = -1.7777777777777777\n    \"\"\"\n\n    def setup(self):\n        self.add_input('x', np.zeros((3, 1)))\n        self.add_output('y', np.zeros((3, 1)))\n        self.add_output('z', 2.0*np.ones((3, 1)), lower=1.5,\n            upper=np.array([2.6, 2.5, 2.65]).reshape((3,1)))\n\n        self.maxiter = 10\n        self.atol = 1.0e-12\n\n    def setup_partials(self):\n        self.declare_partials(of='*', wrt='*')\n\n    def apply_nonlinear(self, inputs, outputs, residuals):\n        \"\"\"\n        Don't solve; just calculate the residual.\n        \"\"\"\n\n        x = inputs['x']\n        y = outputs['y']\n        z = outputs['z']\n\n        residuals['y'] = y - x - 2.0*z\n        residuals['z'] = x*z + z - 4.0\n\n    def linearize(self, inputs, outputs, jac):\n        \"\"\"\n        Analytical derivatives.\n        \"\"\"\n\n        # Output equation\n        jac[('y', 'x')] = -np.diag(np.array([1.0, 1.0, 1.0]))\n        jac[('y', 'y')] = np.diag(np.array([1.0, 1.0, 1.0]))\n        jac[('y', 'z')] = -np.diag(np.array([2.0, 2.0, 2.0]))\n\n        # State equation\n        jac[('z', 'z')] = (inputs['x'] + 1.0) * np.eye(3)\n        jac[('z', 'x')] = outputs['z'] * np.eye(3)"
     },
     "metadata": {
      "scrapbook": {
       "mime_prefix": "application/papermill.record/",
       "name": "code_src19"
      }
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from openmdao.utils.notebook_utils import get_code\n",
    "from myst_nb import glue\n",
    "glue(\"code_src19\", get_code(\"openmdao.test_suite.components.implicit_newton_linesearch.ImplCompTwoStatesArrays\"), display=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "058757be",
   "metadata": {
    "papermill": {
     "duration": 0.001677,
     "end_time": "2026-10-02T14:42:15.183481+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:15.181804+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    ":::{dropdown} `ImplCompTwoStatesArrays` class definition \n",
    "\n",
    "{glue:}`code_src19`\n",
    ":::"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "f29eea07",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:15.186987Z",
     "iopub.status.busy": "2026-10-02T14:42:15.186808Z",
     "iopub.status.idle": "2026-10-02T14:42:16.422446Z",
     "shell.execute_reply": "2026-10-02T14:42:16.421753Z"
    },
    "papermill": {
     "duration": 1.238628,
     "end_time": "2026-10-02T14:42:16.423488+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:15.184860+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1790952136.398976] [runnervm8df0l:7030 :0]        ib_iface.c:1269 UCX  ERROR mana_0: iface 0x55b5fec69280 failed to create UD QP TX wr:256 sge:6 inl:64 resp:0 RX wr:4096 sge:1 resp:0 failed: Operation not supported\n",
      "[1790952136.399263] [runnervm8df0l:7030 :0]      ucp_worker.c:1412 UCX  ERROR uct_iface_open(ud_verbs/mana_0:1) failed: Input/output error\n",
      "NL: NewtonSolver 'NL: Newton' on system '' failed to converge in 10 iterations.\n",
      "[1.5]\n",
      "[1.5]\n",
      "[1.5]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[runnervm8df0l:07030] pml_ucx.c:313  Error: Failed to create UCP worker\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import openmdao.api as om\n",
    "\n",
    "from openmdao.test_suite.components.implicit_newton_linesearch import ImplCompTwoStatesArrays\n",
    "\n",
    "top = om.Problem()\n",
    "top.model.add_subsystem('comp', ImplCompTwoStatesArrays(), promotes_inputs=['x'])\n",
    "\n",
    "top.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "top.model.nonlinear_solver.options['maxiter'] = 10\n",
    "top.model.linear_solver = om.ScipyKrylov()\n",
    "\n",
    "top.model.nonlinear_solver.linesearch = om.ArmijoGoldsteinLS()\n",
    "\n",
    "top.setup()\n",
    "top.set_val('x', np.array([2., 2, 2]).reshape(3, 1))\n",
    "# Test lower bounds: should go to the lower bound and stall\n",
    "top.set_val('comp.y', 0.)\n",
    "top.set_val('comp.z', 1.6)\n",
    "top.run_model()\n",
    "\n",
    "for ind in range(3):\n",
    "    print(top.get_val('comp.z', indices=ind))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "24887749",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:16.428995Z",
     "iopub.status.busy": "2026-10-02T14:42:16.428787Z",
     "iopub.status.idle": "2026-10-02T14:42:16.432760Z",
     "shell.execute_reply": "2026-10-02T14:42:16.432037Z"
    },
    "papermill": {
     "duration": 0.00737,
     "end_time": "2026-10-02T14:42:16.433303+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.425933+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "from openmdao.utils.assert_utils import assert_near_equal\n",
    "\n",
    "for ind in range(3):\n",
    "    assert_near_equal(top.get_val('comp.z', indices=ind), [1.5], 1e-8)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "79c67189",
   "metadata": {
    "papermill": {
     "duration": 0.001595,
     "end_time": "2026-10-02T14:42:16.436611+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.435016+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## ArmijoGoldsteinLS Options"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0ef55791",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:16.440768Z",
     "iopub.status.busy": "2026-10-02T14:42:16.440572Z",
     "iopub.status.idle": "2026-10-02T14:42:16.445640Z",
     "shell.execute_reply": "2026-10-02T14:42:16.444778Z"
    },
    "papermill": {
     "duration": 0.007972,
     "end_time": "2026-10-02T14:42:16.446189+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.438217+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<!DOCTYPE html>\n",
       "<html lang=\"en\">\n",
       "<head>\n",
       "    <style>\n",
       "        h2 {\n",
       "            text-align: center;\n",
       "        }\n",
       "    </style>\n",
       "</head>\n",
       "<body>\n",
       "    <h2></h2>\n",
       "        <table style=\"border: 1px solid #999; border-collapse: collapse;\">\n",
       "        <tr><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Option</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Default</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Acceptable Values</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Acceptable Types</th><th style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; background-color: #E9E9E9; text-align: left;\">Description</th></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">alpha</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1.0</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Initial line search step.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">atol</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1e-10</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">absolute error tolerance</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">bound_enforcement</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">scalar</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;vector&#x27;, &#x27;scalar&#x27;, &#x27;wall&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If this is set to &#x27;vector&#x27;, the entire vector is backtracked together when a bound is violated. If this is set to &#x27;scalar&#x27;, only the violating entries are set to the bound and then the backtracking occurs on the vector as a whole. If this is set to &#x27;wall&#x27;, only the violating entries are set to the bound, and then the backtracking follows the wall - i.e., the violating entries do not change during the line search.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">c</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">0.1</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Slope parameter for line of sufficient decrease. The larger the step, the more decrease is required to terminate the line search.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">debug_print</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, the values of input and output variables at the start of iteration are printed and written to a file after a failure to converge or when encountering aninvalid value in the residual.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">err_on_non_converge</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">When True, AnalysisError will be raised if we don&#x27;t converge.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">iprint</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;int&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">whether to print output</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">maxiter</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">5</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;int&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">maximum number of iterations</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">method</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Armijo</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;Armijo&#x27;, &#x27;Goldstein&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Method to calculate stopping condition.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">print_bound_enforce</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Set to True to print out names and values of variables that are pulled back to their bounds.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">restart_from_successful</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">False</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[True, False]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;bool&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">If True, the states are cached after a successful solve and used to restart the solver in the case of a failed solve.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">retry_on_analysis_error</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">True</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Backtrack and retry if an AnalysisError is raised.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">rho</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">0.5</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Contraction factor.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">rtol</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1e-10</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">relative error tolerance</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">stall_limit</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">0</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Number of iterations after which, if the residual norms are identical within the stall_tol, then terminate as if max iterations were reached. Default is 0, which disables this feature.</td></tr>\n",
       "       <tr style=\"background-color: #F3F3F3;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">stall_tol</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">1e-12</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">When stall checking is enabled, the threshold below which the residual norm is considered unchanged.</td></tr>\n",
       "       <tr style=\"background-color: ghostwhite;\"><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">stall_tol_type</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">rel</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">[&#x27;abs&#x27;, &#x27;rel&#x27;]</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">N/A</td><td style=\"border: 1px solid #999; border-collapse: collapse; padding: 5px; text-align: left;\">Specifies whether the absolute or relative norm of the residual is used for stall detection.</td></tr>\n",
       "    </table>\n",
       "</body>\n",
       "</html>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "om.show_options_table(\"openmdao.solvers.linesearch.backtracking.ArmijoGoldsteinLS\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "840c51ca",
   "metadata": {
    "papermill": {
     "duration": 0.001578,
     "end_time": "2026-10-02T14:42:16.449924+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.448346+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "## ArmijoGoldsteinLS Constructor\n",
    "\n",
    "The call signature for the `ArmijoGoldsteinLS` constructor is:\n",
    "\n",
    "```{eval-rst}\n",
    "    .. automethod:: openmdao.solvers.linesearch.backtracking.ArmijoGoldsteinLS.__init__\n",
    "        :noindex:\n",
    "```\n",
    "\n",
    "## ArmijoGoldsteinLS Option Examples\n",
    "\n",
    "**bound_enforcement**\n",
    "\n",
    "ArmijoGoldsteinLS includes the `bound_enforcement` option in its options dictionary. This option has a dual role:\n",
    "\n",
    "1. Behavior of the non-bounded variables when the bounded ones are capped.\n",
    "2. Direction of the further backtracking.\n",
    "\n",
    "There are three different acceptable values for bounds-enforcement schemes available in this option.\n",
    "\n",
    "With \"scalar\" bounds enforcement, only the variables that violate their bounds are pulled back to feasible values; the\n",
    "remaining values are kept at the Newton-stepped point. This changes the direction of the backtracking vector so that\n",
    "it still moves in the direction of the initial point.\n",
    "\n",
    "![BT2](images/BT2.jpg)\n",
    "\n",
    "With \"vector\" bounds enforcement, the solution in the output vector is pulled back to a point where none of the\n",
    "variables violate any upper or lower bounds. Further backtracking continues along the Newton gradient direction vector back towards the\n",
    "initial point.\n",
    "\n",
    "![BT1](images/BT1.jpg)\n",
    "\n",
    "With \"wall\" bounds enforcement, only the variables that violate their bounds are pulled back to feasible values; the\n",
    "remaining values are kept at the Newton-stepped point. Further backtracking only occurs in the direction of the non-violating\n",
    "variables, so that it will move along the wall.\n",
    "\n",
    "![BT3](images/BT3.jpg)\n",
    "\n",
    "Here are examples of each acceptable value for the **bound_enforcement** option:\n",
    "\n",
    "- bound_enforcement: vector\n",
    "\n",
    "  The `bound_enforcement` option in the options dictionary is used to specify how the output bounds\n",
    "  are enforced. When this is set to \"vector\", the output vector is rolled back along the computed gradient until\n",
    "  it reaches a point where the earliest bound violation occurred. The backtracking continues along the original\n",
    "  computed gradient.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "5a1a9eb1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:16.453691Z",
     "iopub.status.busy": "2026-10-02T14:42:16.453550Z",
     "iopub.status.idle": "2026-10-02T14:42:16.469803Z",
     "shell.execute_reply": "2026-10-02T14:42:16.469155Z"
    },
    "papermill": {
     "duration": 0.018879,
     "end_time": "2026-10-02T14:42:16.470275+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.451396+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: NewtonSolver 'NL: Newton' on system '' failed to converge in 10 iterations.\n",
      "[1.5]\n",
      "[1.5]\n",
      "[1.5]\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.implicit_newton_linesearch import ImplCompTwoStatesArrays\n",
    "\n",
    "top = om.Problem()\n",
    "top.model.add_subsystem('comp', ImplCompTwoStatesArrays(), promotes_inputs=['x'])\n",
    "\n",
    "top.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "top.model.nonlinear_solver.options['maxiter'] = 10\n",
    "top.model.linear_solver = om.ScipyKrylov()\n",
    "\n",
    "top.model.nonlinear_solver.linesearch = om.ArmijoGoldsteinLS(bound_enforcement='vector')\n",
    "\n",
    "top.setup()\n",
    "\n",
    "top.set_val('x', np.array([2., 2, 2]).reshape(3, 1))\n",
    "\n",
    "# Test lower bounds: should go to the lower bound and stall\n",
    "top.set_val('comp.y', 0.)\n",
    "top.set_val('comp.z', 1.6)\n",
    "top.run_model()\n",
    "\n",
    "for ind in range(3):\n",
    "    print(top.get_val('comp.z', indices=ind))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "25c6f2f6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:16.475522Z",
     "iopub.status.busy": "2026-10-02T14:42:16.475331Z",
     "iopub.status.idle": "2026-10-02T14:42:16.478394Z",
     "shell.execute_reply": "2026-10-02T14:42:16.477664Z"
    },
    "papermill": {
     "duration": 0.006397,
     "end_time": "2026-10-02T14:42:16.478875+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.472478+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "for ind in range(3):\n",
    "    assert_near_equal(top.get_val('comp.z', indices=ind), [1.5], 1e-8)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0781d0aa",
   "metadata": {
    "papermill": {
     "duration": 0.0015,
     "end_time": "2026-10-02T14:42:16.481954+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.480454+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "- bound_enforcement: scalar\n",
    "\n",
    "  The `bound_enforcement` option in the options dictionary is used to specify how the output bounds\n",
    "  are enforced. When this is set to \"scaler\", then the only indices in the output vector that are rolled back\n",
    "  are the ones that violate their upper or lower bounds. The backtracking continues along the modified gradient."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "58028ba4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:16.494171Z",
     "iopub.status.busy": "2026-10-02T14:42:16.493980Z",
     "iopub.status.idle": "2026-10-02T14:42:16.505396Z",
     "shell.execute_reply": "2026-10-02T14:42:16.504713Z"
    },
    "papermill": {
     "duration": 0.022452,
     "end_time": "2026-10-02T14:42:16.505942+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.483490+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: NewtonSolver 'NL: Newton' on system '' failed to converge in 10 iterations.\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.implicit_newton_linesearch import ImplCompTwoStatesArrays\n",
    "\n",
    "top = om.Problem()\n",
    "top.model.add_subsystem('comp', ImplCompTwoStatesArrays(), promotes_inputs=['x'])\n",
    "\n",
    "top.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "top.model.nonlinear_solver.options['maxiter'] = 10\n",
    "top.model.linear_solver = om.ScipyKrylov()\n",
    "\n",
    "ls = top.model.nonlinear_solver.linesearch = om.ArmijoGoldsteinLS(bound_enforcement='scalar')\n",
    "\n",
    "top.setup()\n",
    "top.set_val('x', np.array([2., 2, 2]).reshape(3, 1))\n",
    "top.run_model()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d92c39c4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:16.511131Z",
     "iopub.status.busy": "2026-10-02T14:42:16.510941Z",
     "iopub.status.idle": "2026-10-02T14:42:16.522292Z",
     "shell.execute_reply": "2026-10-02T14:42:16.521535Z"
    },
    "papermill": {
     "duration": 0.014966,
     "end_time": "2026-10-02T14:42:16.522865+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.507899+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: NewtonSolver 'NL: Newton' on system '' failed to converge in 10 iterations.\n"
     ]
    }
   ],
   "source": [
    "# Test lower bounds: should stop just short of the lower bound\n",
    "top.set_val('comp.y', 0.)\n",
    "top.set_val('comp.z', 1.6)\n",
    "top.run_model()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "01013678",
   "metadata": {
    "papermill": {
     "duration": 0.002727,
     "end_time": "2026-10-02T14:42:16.527996+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.525269+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "- bound_enforcement: wall\n",
    "\n",
    "  The `bound_enforcement` option in the options dictionary is used to specify how the output bounds\n",
    "  are enforced. When this is set to \"wall\", then the only indices in the output vector that are rolled back\n",
    "  are the ones that violate their upper or lower bounds. The backtracking continues along a modified gradient\n",
    "  direction that follows the boundary of the violated output bounds."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "568fb564",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:16.546125Z",
     "iopub.status.busy": "2026-10-02T14:42:16.545989Z",
     "iopub.status.idle": "2026-10-02T14:42:16.561811Z",
     "shell.execute_reply": "2026-10-02T14:42:16.561172Z"
    },
    "papermill": {
     "duration": 0.026522,
     "end_time": "2026-10-02T14:42:16.562428+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.535906+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: NewtonSolver 'NL: Newton' on system '' failed to converge in 10 iterations.\n",
      "[2.6]\n",
      "[2.5]\n",
      "[2.65]\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.implicit_newton_linesearch import ImplCompTwoStatesArrays\n",
    "\n",
    "top = om.Problem()\n",
    "top.model.add_subsystem('comp', ImplCompTwoStatesArrays(), promotes_inputs=['x'])\n",
    "\n",
    "top.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "top.model.nonlinear_solver.options['maxiter'] = 10\n",
    "top.model.linear_solver = om.ScipyKrylov()\n",
    "\n",
    "top.model.nonlinear_solver.linesearch = om.ArmijoGoldsteinLS(bound_enforcement='wall')\n",
    "\n",
    "top.setup()\n",
    "\n",
    "top.set_val('x', np.array([0.5, 0.5, 0.5]).reshape(3, 1))\n",
    "\n",
    "# Test upper bounds: should go to the upper bound and stall\n",
    "top.set_val('comp.y', 0.)\n",
    "top.set_val('comp.z', 2.4)\n",
    "top.run_model()\n",
    "\n",
    "print(top.get_val('comp.z', indices=0))\n",
    "print(top.get_val('comp.z', indices=1))\n",
    "print(top.get_val('comp.z', indices=2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "2bb60b0b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:16.567185Z",
     "iopub.status.busy": "2026-10-02T14:42:16.567009Z",
     "iopub.status.idle": "2026-10-02T14:42:16.571047Z",
     "shell.execute_reply": "2026-10-02T14:42:16.570331Z"
    },
    "papermill": {
     "duration": 0.007126,
     "end_time": "2026-10-02T14:42:16.571502+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.564376+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(0.0)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert_near_equal(top.get_val('comp.z', indices=0), [2.6], 1e-8)\n",
    "assert_near_equal(top.get_val('comp.z', indices=1), [2.5], 1e-8)\n",
    "assert_near_equal(top.get_val('comp.z', indices=2), [2.65], 1e-8)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "351c5d47",
   "metadata": {
    "papermill": {
     "duration": 0.001599,
     "end_time": "2026-10-02T14:42:16.574808+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.573209+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "**maxiter**\n",
    "\n",
    "  The \"maxiter\" option is a termination criteria that specifies the maximum number of backtracking steps to allow.\n",
    "\n",
    "**alpha**\n",
    "\n",
    "  The \"alpha\" option is used to specify the initial length of the Newton step. Since NewtonSolver assumes a\n",
    "  step size of 1.0, this value usually shouldn't be changed.\n",
    "\n",
    "**rho**\n",
    "\n",
    "  The \"rho\" option controls how far to backtrack in each successive backtracking step. It is applied as a multiplier to\n",
    "  the step, so a higher value (approaching 1.0) is a very small step, while a low value takes you close to the initial\n",
    "  point. The default value is 0.5.\n",
    "\n",
    "**c**\n",
    "\n",
    "  In the `ArmijoGoldsteinLS`, the \"c\" option is a multiplier on the slope check. Setting it to a smaller value means a more\n",
    "  gentle slope will satisfy the condition and terminate.\n",
    "\n",
    "**print_bound_enforce**\n",
    "\n",
    "  When the \"print_bound_enforce\" option is set to True, the line-search will print the name and values of any variables\n",
    "  that exceeded their lower or upper bounds and were drawn back during bounds enforcement."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "01c6ac35",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:16.579178Z",
     "iopub.status.busy": "2026-10-02T14:42:16.578986Z",
     "iopub.status.idle": "2026-10-02T14:42:16.588719Z",
     "shell.execute_reply": "2026-10-02T14:42:16.588002Z"
    },
    "papermill": {
     "duration": 0.012642,
     "end_time": "2026-10-02T14:42:16.589324+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.576682+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NL: Newton 0 ; 9.1126286 1\n",
      "|  LN: SCIPY 0 ; 0.18556153 1\n",
      "|  LN: SCIPY 1 ; 5.87797659e-16 3.16766982e-15\n",
      "|  LS: BCHK 0 ; 5.69539287 0.625\n",
      "NL: Newton 1 ; 5.69539287 0.625\n",
      "|  LN: SCIPY 0 ; 0.0742246119 1\n",
      "|  LN: SCIPY 1 ; 2.20006239e-16 2.96406048e-15\n",
      "|  LS: BCHK 0 ; 5.69539287 1\n",
      "NL: Newton 2 ; 5.69539287 0.625\n",
      "NL: NewtonSolver 'NL: Newton' on system '' failed to converge in 2 iterations.\n",
      "[1.5]\n",
      "[1.5]\n",
      "[1.5]\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages/openmdao/solvers/linesearch/backtracking.py:39: SolverWarning:'comp.z' exceeds lower bounds\n",
      "  Val: [1.33333333 1.33333333 1.33333333]\n",
      "  Lower: [1.5 1.5 1.5]\n",
      "\n",
      "/home/runner/work/OpenMDAO/OpenMDAO/.pixi/envs/dev/lib/python3.13/site-packages/openmdao/solvers/linesearch/backtracking.py:39: SolverWarning:'comp.z' exceeds lower bounds\n",
      "  Val: [1.33333333 1.33333333 1.33333333]\n",
      "  Lower: [1.5 1.5 1.5]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from openmdao.test_suite.components.implicit_newton_linesearch import ImplCompTwoStatesArrays\n",
    "\n",
    "top = om.Problem()\n",
    "top.model.add_subsystem('comp', ImplCompTwoStatesArrays(), promotes_inputs=['x'])\n",
    "\n",
    "newt = top.model.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)\n",
    "top.model.nonlinear_solver.options['maxiter'] = 2\n",
    "top.model.linear_solver = om.ScipyKrylov()\n",
    "\n",
    "ls = newt.linesearch = om.BoundsEnforceLS(bound_enforcement='vector')\n",
    "ls.options['print_bound_enforce'] = True\n",
    "\n",
    "top.set_solver_print(level=2)\n",
    "\n",
    "\n",
    "top.setup()\n",
    "top.set_val('x', np.array([2., 2, 2]).reshape(3, 1))\n",
    "\n",
    "# Test lower bounds: should go to the lower bound and stall\n",
    "top.set_val('comp.y', 0.)\n",
    "top.set_val('comp.z', 1.6)\n",
    "top.run_model()\n",
    "\n",
    "for ind in range(3):\n",
    "    print(top.get_val('comp.z', indices=ind))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "cafe1686",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-10-02T14:42:16.593888Z",
     "iopub.status.busy": "2026-10-02T14:42:16.593747Z",
     "iopub.status.idle": "2026-10-02T14:42:16.596839Z",
     "shell.execute_reply": "2026-10-02T14:42:16.596039Z"
    },
    "papermill": {
     "duration": 0.006279,
     "end_time": "2026-10-02T14:42:16.597428+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.591149+00:00",
     "status": "completed"
    },
    "tags": [
     "remove-input",
     "remove-output"
    ]
   },
   "outputs": [],
   "source": [
    "for ind in range(3):\n",
    "    assert_near_equal(top.get_val('comp.z', indices=ind), [1.5], 1e-8)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d6f9ef9",
   "metadata": {
    "papermill": {
     "duration": 0.002499,
     "end_time": "2026-10-02T14:42:16.602423+00:00",
     "exception": false,
     "start_time": "2026-10-02T14:42:16.599924+00:00",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "- retry_on_analysis_error\n",
    "\n",
    "  By default, the ArmijoGoldsteinLS linesearch will backtrack if the model raises an AnalysisError, which can happen if the component explicitly raises it, or a subsolver hits its iteration limit with the 'err_on_non_converge' option set to True. If you would rather terminate on an AnalysisError, you can set this option to False.\n"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.14"
  },
  "orphan": true,
  "papermill": {
   "default_parameters": {},
   "duration": 5.440013,
   "end_time": "2026-10-02T14:42:17.323046+00:00",
   "environment_variables": {},
   "exception": null,
   "input_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/openmdao_book/features/building_blocks/solvers/armijo_goldstein.ipynb",
   "output_path": "/home/runner/work/OpenMDAO/OpenMDAO/openmdao/docs/_executed_book/features/building_blocks/solvers/armijo_goldstein.ipynb",
   "parameters": {},
   "start_time": "2026-10-02T14:42:11.883033+00:00",
   "version": "2.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}