Repository: optimagic-dev/optimagic (language: python)

Issue:
Return better results object for `estimate_ml` and `estimate_msm`
### Current situation

- `estimate_ml` and `estimate_msm` return a dictionary with information
- The keys are either confusing or not 

### Describe the solution you'd like

- `estimate_ml` and `estimate_msm` should return a custom object (`EstimationResult`).
- It could be designed as follows:

**`estimate_ml`:**

- Attributes
1. params
2. jacobian
3. hessian

- Methods
1. summary
2. cov
3. se

- Properties
1. _summary (calls summary at default)
2. _cov (calls cov at default)
3. _se (...)

And similar for `estimate_msm`.

### Backwards compatibility
We could make the results object fully backwards compatible by implementing __getitem__ to make it behave like a dict. However, I think the userbase is currently small enough that we could simply make a breaking change.


Discussion / hints:

Fix patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 60e4efe7f..dfa219317 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -10,7 +10,8 @@ releases are available on `Anaconda.org
 0.3.0
 -----
 
-Fist release with pytree support in optimization, estimation and differentiation.
+Fist release with pytree support in optimization, estimation and differentiation
+and much better result objects in optimization and estimation.
 
 Breaking changes
 
@@ -27,6 +28,15 @@ Breaking changes
 - Convenience functions to create namedtuples are removed from ``estimagic.utilities``.
 
 
+- :gh:`345` Moves estimation_table to new latex functionality of pandas
+  (:ghuser:`mpetrosian`)
+- :gh:`344` Adds pytree support to slice_plot (:ghuser:`janosg`)
+- :gh:`343` Improves the result object of estimation functions and makes msm estimation
+  pytree compatible (:ghuser:`janosg`)
+- :gh:`342` Improves default options of the fides optimizer, allows single constraints
+  and polishes the documentation (:ghuser:`janosg`)
+- :gh:`340` Enables history collection for optimizers that evaluate the criterion
+  function in parallel (:ghuser:`janosg`)
 - :gh:`339` Incorporates user feedback and polishes the documentation.
 - :gh:`338` Improves log reading functions (:ghuser:`janosg`)
 - :gh:`336` Adds pytree support to the dashboard (:ghuser:`roecla`).
diff --git a/codecov.yml b/codecov.yml
index 236b93d51..8ce60595b 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -9,7 +9,7 @@ coverage:
   status:
     patch:
       default:
-        target: 85%
+        target: 80%
     project:
       default:
         target: 90%
diff --git a/docs/source/getting_started/estimation/first_likelihood_estimation_with_estimagic.ipynb b/docs/source/getting_started/estimation/first_likelihood_estimation_with_estimagic.ipynb
index fc1efd17f..1f2fdf60f 100644
--- a/docs/source/getting_started/estimation/first_likelihood_estimation_with_estimagic.ipynb
+++ b/docs/source/getting_started/estimation/first_likelihood_estimation_with_estimagic.ipynb
@@ -278,7 +278,7 @@
     }
    ],
    "source": [
-    "res[\"summary_jacobian\"].round(3)"
+    "res.summary().round(3)"
    ]
   },
   {
@@ -287,39 +287,217 @@
    "source": [
     "## What's in the results?\n",
     "\n",
-    "The result of `estimate_ml` is a dictionary with the following entries:"
+    "`LikelihoodResult` objects provide attributes and methods to calculate standard errors, confidence intervals and p_values with multiple methods. You can even calculate cluster robust standard errors. \n",
+    "\n",
+    "A few examples are:"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 13,
    "metadata": {},
    "outputs": [
     {
      "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    .dataframe tbody tr th:only-of-type {\n",
+       "        vertical-align: middle;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe tbody tr th {\n",
+       "        vertical-align: top;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe thead th {\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "</style>\n",
+       "<table border=\"1\" class=\"dataframe\">\n",
+       "  <thead>\n",
+       "    <tr style=\"text-align: right;\">\n",
+       "      <th></th>\n",
+       "      <th>value</th>\n",
+       "      <th>lower_bound</th>\n",
+       "    </tr>\n",
+       "  </thead>\n",
+       "  <tbody>\n",
+       "    <tr>\n",
+       "      <th>intercept</th>\n",
+       "      <td>2.075153</td>\n",
+       "      <td>-inf</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>slope</th>\n",
+       "      <td>-0.885302</td>\n",
+       "      <td>-inf</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>sd</th>\n",
+       "      <td>1.028189</td>\n",
+       "      <td>1.000000e-10</td>\n",
+       "    </tr>\n",
+       "  </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
       "text/plain": [
-       "dict_keys(['summary_jacobian', 'cov_jacobian', 'jacobian', 'hessian', 'optimize_res', 'jacobian_numdiff_info'])"
+       "              value   lower_bound\n",
+       "intercept  2.075153          -inf\n",
+       "slope     -0.885302          -inf\n",
+       "sd         1.028189  1.000000e-10"
       ]
      },
-     "execution_count": 8,
+     "execution_count": 13,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "res.keys()"
+    "res.params"
    ]
   },
   {
-   "cell_type": "markdown",
+   "cell_type": "code",
+   "execution_count": 14,
    "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    .dataframe tbody tr th:only-of-type {\n",
+       "        vertical-align: middle;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe tbody tr th {\n",
+       "        vertical-align: top;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe thead th {\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "</style>\n",
+       "<table border=\"1\" class=\"dataframe\">\n",
+       "  <thead>\n",
+       "    <tr style=\"text-align: right;\">\n",
+       "      <th></th>\n",
+       "      <th>intercept</th>\n",
+       "      <th>slope</th>\n",
+       "      <th>sd</th>\n",
+       "    </tr>\n",
+       "  </thead>\n",
+       "  <tbody>\n",
+       "    <tr>\n",
+       "      <th>intercept</th>\n",
+       "      <td>0.010575</td>\n",
+       "      <td>-0.000296</td>\n",
+       "      <td>0.001165</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>slope</th>\n",
+       "      <td>-0.000296</td>\n",
+       "      <td>0.009050</td>\n",
+       "      <td>-0.000952</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>sd</th>\n",
+       "      <td>0.001165</td>\n",
+       "      <td>-0.000952</td>\n",
+       "      <td>0.003336</td>\n",
+       "    </tr>\n",
+       "  </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "           intercept     slope        sd\n",
+       "intercept   0.010575 -0.000296  0.001165\n",
+       "slope      -0.000296  0.009050 -0.000952\n",
+       "sd          0.001165 -0.000952  0.003336"
+      ]
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
-    "Importantly, we might have several summaries and several cov entries. This is because we always all possible types of standard errors, so you can compare them easily (for example using our estimation table functions). \n",
-    "\n",
-    "In the current example we only have jacobian based standard errors because we did not provide a closed form hessian function and numerical hessians are not yet implemented. With a closed form hessian we would also get hessian based and robust standard errors. Even cluster and strata robust standard errors are possible if you provide the relevant information. \n",
-    "\n",
-    "If numerical optimizations or derivative calculations were performed, the full output of those steps is also part of the results dictionary. "
+    "res.cov(method=\"robust\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    .dataframe tbody tr th:only-of-type {\n",
+       "        vertical-align: middle;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe tbody tr th {\n",
+       "        vertical-align: top;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe thead th {\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "</style>\n",
+       "<table border=\"1\" class=\"dataframe\">\n",
+       "  <thead>\n",
+       "    <tr style=\"text-align: right;\">\n",
+       "      <th></th>\n",
+       "      <th>value</th>\n",
+       "      <th>lower_bound</th>\n",
+       "    </tr>\n",
+       "  </thead>\n",
+       "  <tbody>\n",
+       "    <tr>\n",
+       "      <th>intercept</th>\n",
+       "      <td>0.105445</td>\n",
+       "      <td>-inf</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>slope</th>\n",
+       "      <td>0.111271</td>\n",
+       "      <td>-inf</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>sd</th>\n",
+       "      <td>0.094721</td>\n",
+       "      <td>1.000000e-10</td>\n",
+       "    </tr>\n",
+       "  </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "              value   lower_bound\n",
+       "intercept  0.105445          -inf\n",
+       "slope      0.111271          -inf\n",
+       "sd         0.094721  1.000000e-10"
+      ]
+     },
+     "execution_count": 15,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "res.se()"
    ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": []
   }
  ],
  "metadata": {
diff --git a/docs/source/getting_started/estimation/first_msm_estimation_with_estimagic.ipynb b/docs/source/getting_started/estimation/first_msm_estimation_with_estimagic.ipynb
index 509986bb7..9d02d714c 100644
--- a/docs/source/getting_started/estimation/first_msm_estimation_with_estimagic.ipynb
+++ b/docs/source/getting_started/estimation/first_msm_estimation_with_estimagic.ipynb
@@ -201,43 +201,43 @@
        "  <tbody>\n",
        "    <tr>\n",
        "      <th>y_mean</th>\n",
-       "      <td>0.020512</td>\n",
-       "      <td>-0.009331</td>\n",
-       "      <td>-0.013714</td>\n",
-       "      <td>0.079071</td>\n",
-       "      <td>-0.003119</td>\n",
+       "      <td>0.019384</td>\n",
+       "      <td>-0.009285</td>\n",
+       "      <td>-0.014657</td>\n",
+       "      <td>0.076048</td>\n",
+       "      <td>-0.002489</td>\n",
        "    </tr>\n",
        "    <tr>\n",
        "      <th>x_mean</th>\n",
-       "      <td>-0.009331</td>\n",
-       "      <td>0.009908</td>\n",
-       "      <td>0.017449</td>\n",
-       "      <td>-0.034002</td>\n",
-       "      <td>0.001736</td>\n",
+       "      <td>-0.009285</td>\n",
+       "      <td>0.010238</td>\n",
+       "      <td>0.018576</td>\n",
+       "      <td>-0.035035</td>\n",
+       "      <td>0.001544</td>\n",
        "    </tr>\n",
        "    <tr>\n",
        "      <th>yx_mean</th>\n",
-       "      <td>-0.013714</td>\n",
-       "      <td>0.017449</td>\n",
-       "      <td>0.053657</td>\n",
-       "      <td>-0.078643</td>\n",
-       "      <td>-0.012049</td>\n",
+       "      <td>-0.014657</td>\n",
+       "      <td>0.018576</td>\n",
+       "      <td>0.054319</td>\n",
+       "      <td>-0.081187</td>\n",
+       "      <td>-0.010329</td>\n",
        "    </tr>\n",
        "    <tr>\n",
        "      <th>y_sqrd_mean</th>\n",
-       "      <td>0.079071</td>\n",
-       "      <td>-0.034002</td>\n",
-       "      <td>-0.078643</td>\n",
-       "      <td>0.365561</td>\n",
-       "      <td>0.000102</td>\n",
+       "      <td>0.076048</td>\n",
+       "      <td>-0.035035</td>\n",
+       "      <td>-0.081187</td>\n",
+       "      <td>0.353938</td>\n",
+       "      <td>0.000089</td>\n",
        "    </tr>\n",
        "    <tr>\n",
        "      <th>x_sqrd_mean</th>\n",
-       "      <td>-0.003119</td>\n",
-       "      <td>0.001736</td>\n",
-       "      <td>-0.012049</td>\n",
-       "      <td>0.000102</td>\n",
-       "      <td>0.017509</td>\n",
+       "      <td>-0.002489</td>\n",
+       "      <td>0.001544</td>\n",
+       "      <td>-0.010329</td>\n",
+       "      <td>0.000089</td>\n",
+       "      <td>0.015506</td>\n",
        "    </tr>\n",
        "  </tbody>\n",
        "</table>\n",
@@ -245,11 +245,11 @@
       ],
       "text/plain": [
        "               y_mean    x_mean   yx_mean  y_sqrd_mean  x_sqrd_mean\n",
-       "y_mean       0.020512 -0.009331 -0.013714     0.079071    -0.003119\n",
-       "x_mean      -0.009331  0.009908  0.017449    -0.034002     0.001736\n",
-       "yx_mean     -0.013714  0.017449  0.053657    -0.078643    -0.012049\n",
-       "y_sqrd_mean  0.079071 -0.034002 -0.078643     0.365561     0.000102\n",
-       "x_sqrd_mean -0.003119  0.001736 -0.012049     0.000102     0.017509"
+       "y_mean       0.019384 -0.009285 -0.014657     0.076048    -0.002489\n",
+       "x_mean      -0.009285  0.010238  0.018576    -0.035035     0.001544\n",
+       "yx_mean     -0.014657  0.018576  0.054319    -0.081187    -0.010329\n",
+       "y_sqrd_mean  0.076048 -0.035035 -0.081187     0.353938     0.000089\n",
+       "x_sqrd_mean -0.002489  0.001544 -0.010329     0.000089     0.015506"
       ]
      },
      "execution_count": 7,
@@ -357,16 +357,7 @@
    "execution_count": 11,
    "id": "finite-david",
    "metadata": {},
-   "outputs": [
-    {
-     "name": "stderr",
-     "output_type": "stream",
-     "text": [
-      "/home/tim/sciebo/phd/projects/janos/estimagic/src/estimagic/utilities.py:194: UserWarning: Standard matrix inversion failed due to LinAlgError described below. A pseudo inverse was calculated instead. Taking inverse failed during the calculation of sensitvity measures. Interpret them with caution.\n",
-      "  warnings.warn(header + msg)\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "start_params = true_params.assign(value=[100, 100, 100])\n",
     "\n",
@@ -375,7 +366,7 @@
     "    empirical_moments,\n",
     "    moments_cov,\n",
     "    start_params,\n",
-    "    optimize_options={\"algorithm\": \"scipy_lbfgsb\"},\n",
+    "    optimize_options=\"scipy_lbfgsb\",\n",
     ")"
    ]
   },
@@ -417,29 +408,29 @@
        "  <tbody>\n",
        "    <tr>\n",
        "      <th>intercept</th>\n",
-       "      <td>1.995793</td>\n",
-       "      <td>0.142305</td>\n",
-       "      <td>1.078528e-44</td>\n",
-       "      <td>1.716880</td>\n",
-       "      <td>2.274707</td>\n",
+       "      <td>1.995794</td>\n",
+       "      <td>0.138153</td>\n",
+       "      <td>2.645631e-47</td>\n",
+       "      <td>1.725019</td>\n",
+       "      <td>2.266568</td>\n",
        "      <td>***</td>\n",
        "    </tr>\n",
        "    <tr>\n",
        "      <th>slope</th>\n",
        "      <td>-0.750961</td>\n",
-       "      <td>0.237271</td>\n",
-       "      <td>1.519872e-03</td>\n",
-       "      <td>-1.216004</td>\n",
-       "      <td>-0.285918</td>\n",
+       "      <td>0.238691</td>\n",
+       "      <td>1.654246e-03</td>\n",
+       "      <td>-1.218786</td>\n",
+       "      <td>-0.283136</td>\n",
        "      <td>***</td>\n",
        "    </tr>\n",
        "    <tr>\n",
        "      <th>sd</th>\n",
        "      <td>1.143843</td>\n",
-       "      <td>0.149403</td>\n",
-       "      <td>1.878186e-14</td>\n",
-       "      <td>0.851019</td>\n",
-       "      <td>1.436667</td>\n",
+       "      <td>0.149262</td>\n",
+       "      <td>1.811586e-14</td>\n",
+       "      <td>0.851296</td>\n",
+       "      <td>1.436391</td>\n",
        "      <td>***</td>\n",
        "    </tr>\n",
        "  </tbody>\n",
@@ -448,9 +439,9 @@
       ],
       "text/plain": [
        "              value  standard_error       p_value  ci_lower  ci_upper stars\n",
-       "intercept  1.995793        0.142305  1.078528e-44  1.716880  2.274707   ***\n",
-       "slope     -0.750961        0.237271  1.519872e-03 -1.216004 -0.285918   ***\n",
-       "sd         1.143843        0.149403  1.878186e-14  0.851019  1.436667   ***"
+       "intercept  1.995794        0.138153  2.645631e-47  1.725019  2.266568   ***\n",
+       "slope     -0.750961        0.238691  1.654246e-03 -1.218786 -0.283136   ***\n",
+       "sd         1.143843        0.149262  1.811586e-14  0.851296  1.436391   ***"
       ]
      },
      "execution_count": 12,
@@ -459,7 +450,7 @@
     }
    ],
    "source": [
-    "res[\"summary\"]"
+    "res.summary()"
    ]
   },
   {
@@ -469,7 +460,9 @@
    "source": [
     "## What's in the result?\n",
     "\n",
-    "The result is a dictionary with the following entries:"
+    "`MomentsResult` objects provide attributes and methods to calculate standard errors, confidence intervals and p_values with multiple methods. You can even calculate cluster robust standard errors.\n",
+    "\n",
+    "A few examples are:"
    ]
   },
   {
@@ -480,8 +473,54 @@
    "outputs": [
     {
      "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    .dataframe tbody tr th:only-of-type {\n",
+       "        vertical-align: middle;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe tbody tr th {\n",
+       "        vertical-align: top;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe thead th {\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "</style>\n",
+       "<table border=\"1\" class=\"dataframe\">\n",
+       "  <thead>\n",
+       "    <tr style=\"text-align: right;\">\n",
+       "      <th></th>\n",
+       "      <th>value</th>\n",
+       "      <th>lower_bound</th>\n",
+       "    </tr>\n",
+       "  </thead>\n",
+       "  <tbody>\n",
+       "    <tr>\n",
+       "      <th>intercept</th>\n",
+       "      <td>1.995794</td>\n",
+       "      <td>-inf</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>slope</th>\n",
+       "      <td>-0.750961</td>\n",
+       "      <td>-inf</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>sd</th>\n",
+       "      <td>1.143843</td>\n",
+       "      <td>1.000000e-10</td>\n",
+       "    </tr>\n",
+       "  </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
       "text/plain": [
-       "dict_keys(['summary', 'cov', 'sensitivity', 'jacobian', 'optimize_res', 'jacobian_numdiff_info'])"
+       "              value   lower_bound\n",
+       "intercept  1.995794          -inf\n",
+       "slope     -0.750961          -inf\n",
+       "sd         1.143843  1.000000e-10"
       ]
      },
      "execution_count": 13,
@@ -490,20 +529,145 @@
     }
    ],
    "source": [
-    "res.keys()"
+    "res.params"
    ]
   },
   {
-   "cell_type": "markdown",
-   "id": "approximate-constitution",
+   "cell_type": "code",
+   "execution_count": 14,
+   "id": "9fc88986",
    "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    .dataframe tbody tr th:only-of-type {\n",
+       "        vertical-align: middle;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe tbody tr th {\n",
+       "        vertical-align: top;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe thead th {\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "</style>\n",
+       "<table border=\"1\" class=\"dataframe\">\n",
+       "  <thead>\n",
+       "    <tr style=\"text-align: right;\">\n",
+       "      <th></th>\n",
+       "      <th>intercept</th>\n",
+       "      <th>slope</th>\n",
+       "      <th>sd</th>\n",
+       "    </tr>\n",
+       "  </thead>\n",
+       "  <tbody>\n",
+       "    <tr>\n",
+       "      <th>intercept</th>\n",
+       "      <td>0.019086</td>\n",
+       "      <td>-0.013996</td>\n",
+       "      <td>-0.010416</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>slope</th>\n",
+       "      <td>-0.013996</td>\n",
+       "      <td>0.056973</td>\n",
+       "      <td>0.027351</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>sd</th>\n",
+       "      <td>-0.010416</td>\n",
+       "      <td>0.027351</td>\n",
+       "      <td>0.022279</td>\n",
+       "    </tr>\n",
+       "  </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "           intercept     slope        sd\n",
+       "intercept   0.019086 -0.013996 -0.010416\n",
+       "slope      -0.013996  0.056973  0.027351\n",
+       "sd         -0.010416  0.027351  0.022279"
+      ]
+     },
+     "execution_count": 14,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "res.cov(method=\"robust\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "id": "d7dbe79c",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div>\n",
+       "<style scoped>\n",
+       "    .dataframe tbody tr th:only-of-type {\n",
+       "        vertical-align: middle;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe tbody tr th {\n",
+       "        vertical-align: top;\n",
+       "    }\n",
+       "\n",
+       "    .dataframe thead th {\n",
+       "        text-align: right;\n",
+       "    }\n",
+       "</style>\n",
+       "<table border=\"1\" class=\"dataframe\">\n",
+       "  <thead>\n",
+       "    <tr style=\"text-align: right;\">\n",
+       "      <th></th>\n",
+       "      <th>value</th>\n",
+       "      <th>lower_bound</th>\n",
+       "    </tr>\n",
+       "  </thead>\n",
+       "  <tbody>\n",
+       "    <tr>\n",
+       "      <th>intercept</th>\n",
+       "      <td>0.138153</td>\n",
+       "      <td>-inf</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>slope</th>\n",
+       "      <td>0.238691</td>\n",
+       "      <td>-inf</td>\n",
+       "    </tr>\n",
+       "    <tr>\n",
+       "      <th>sd</th>\n",
+       "      <td>0.149262</td>\n",
+       "      <td>1.000000e-10</td>\n",
+       "    </tr>\n",
+       "  </tbody>\n",
+       "</table>\n",
+       "</div>"
+      ],
+      "text/plain": [
+       "              value   lower_bound\n",
+       "intercept  0.138153          -inf\n",
+       "slope      0.238691          -inf\n",
+       "sd         0.149262  1.000000e-10"
+      ]
+     },
+     "execution_count": 15,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
-    "- summary: A DataFrame with estimated parameters, standard errors, p_values and confidence intervals. This is ideal for use with our `estimation_table` function. \n",
-    "- cov: A DataFrame with the full covariance matrix of the estimated parameters. You can use this for hypothesis tests. \n",
-    "- optimize_res: A dictionary with the complete output of the numerical optimization (if one was performed)\n",
-    "- numdiff_info: A dictionary with the complete output of the numerical differentiation (if one was performed)\n",
-    "- jacobian: A DataFrame with the jacobian of `simulate_moments` with respect to the free parameters. \n",
-    "- sensitivity: A dictionary of DataFrames with the six sensitivity measures from Honore, Jorgensen and DePaula (2020)"
+    "res.se()"
    ]
   },
   {
@@ -520,13 +684,13 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 16,
    "id": "fleet-qatar",
    "metadata": {},
    "outputs": [
     {
      "data": {
-      "image/png": "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"
+      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA4QAAAH0CAYAAABl8+PTAAAgAElEQVR4XuydB5RV1d2+fwqIgAqKXTC2iBURsGBBY++9l4hYsBsVe2/Y/fBTsSvqH0Wxdw2WWMAWBQ1GRMFCVJqgkSYg//Xu5PINwwxMY3PvO89eKytrmHvPPr/nvfe4n733ObPQzJkzZwYNAhCAAAQgAAEIQAACEIAABOodgYUQwnqXOQVDAAIQgAAEIAABCEAAAhBIBBBCPggQgAAEIAABCEAAAhCAAATqKQGEsJ4GT9kQgAAEIAABCEAAAhCAAAQQQj4DEIAABCAAAQhAAAIQgAAE6ikBhLCeBk/ZEIAABCAAAQhAAAIQgAAEEEI+AxCAAAQgAAEIQAACEIAABOopAYSwngZP2RCAAAQgAAEIQAACEIAABBBCPgMQgAAEIAABCEAAAhCAAATqKQGEsJ4GT9kQgAAEIAABCEAAAhCAAAQQQj4DEIAABCAAAQhAAAIQgAAE6ikBhLCeBk/ZlRO46qqr4t///nf06NEDTBCAAASKisBWW20VRx99dBx++OFFdV6cDAQgUL8I/Pjjj7HlllvG008/Heuss079Kt6wWoTQMFRKqh2BRx55JCZPnhxdunSp1oG+/fbbOOuss6Jv377Vel+xvLh79+6x9957x+abb14sp8R5QAAC5QgghHwkIACBYiCAEBZDCnV3Dghh3bHkSPWcwN133x1//etfQ0JZam3q1Klppu9//ud/EMJSC4/zrVcEEMJ6FTfFQqBoCSCERRtNjU4MIawRNt7kTECrfJMmTYpbbrkllamfl1tuuVhsscXS6t+YMWOidevWceKJJ8Zuu+2WXnPJJZdEnz59ZsPy//7f/4tNNtkkfv3117j66qvj5ZdfTiuP+reLL744Vl555fT6kSNHxrbbbhuDBg2KK664Ip577rn0mjvvvDP9/o033kjn8s9//jOaNGkS6667btx7773RoEGD9Pu77ror9T169OhYY4014uyzz55N6jSAPPfcc5Osvv766/Hbb7/FxhtvnM7hD3/4Q3z55Zdx6KGHxk8//TTr/PX78vU4Z05tECgWAroOXH/99TFkyJCYOXNmrLLKKnHUUUfF7rvvnk6xIiG877774qGHHop//etf0bJly9hzzz3j1FNPjUaNGqX3PP744+l/2mZ60003hXYzLLPMMvHnP/85HbtsGz58eFx55ZXx/vvvR+PGjWOXXXaJ8847LxZddNFiQcR5QAACdUxgXtcdjRt0XdL2UI1p2rdvHyeddFIcdthhbBmt4ywW1OEQwgVFnn6LlkBFQvjiiy/GjjvuGGeccUYstdRS8cQTTyQJfPbZZ2PNNdeMKVOmxI033hgff/xx9O7dO9WmAdTCCy+cBl2aSbvooouiRYsWcfPNN8eIESNCx2zYsGESwj/96U+x9dZbR/PmzdNgTn1I/N566600YDv44INjp512imnTpsX3338fBx10UOpDx7rnnnviggsuiPXWWy+ef/759LOOLdkrDCB//vnnJIW77rpruj9SMvjVV18lSV1ooYXil19+SZJ4xx13JBmVbDIALNqPKCdmSkCDrk033TR9v/fZZ5/Qyr0Gapro0feyIiHs2bNn3H///WniaoMNNggJne6D1nFuuOGGWUKo60/btm3j8ssvj1atWqXJIb1H14L99tsvvU6TQhJAHeeEE05IAz/9vmPHjmlSiwYBCPgRqMp1R89U0KSSxj1t2rRJY53bbrstTUJxD6HHZwIh9MiRKuqQQEVCqMGT5KysJGlVT7J3xBFHpN6vu+66+PDDD2fbMvruu++mWfmyF0zJl+7T0yz8HnvsMUsId9hhh7j11ltnq+SAAw6IpZdeOnr16jVHhRMnToxOnTrFaaedFkceeeSs3++///5JUnX8wgBSN3zr4l1oEyZMSFtEtSIpAdXAU0IpmeUewjr8MHEoCFSDgFb59f3TxI6+wxW1siuEEjaJ3/nnn58mjQrtvffeSzP3heNoIHfOOefEM888E2uvvfas1+ma9dJLL8Wrr76a/k2rh9oFoetd4Vqn654eYqOdCiussEI1quGlEIBAKRCY13VHY5bNNtssTWprTFJoDzzwQJpgQghLIeV5nyNCOG9GvKKeEahICDULVn4L5YEHHhgbbbRR6GEslQnh//7v/0a/fv2STJZt2v61xRZbpO2dhRVCbf3UKmGhadZOM/qamd9rr73mSKEw6NNgrrD9VC+S5H300UdpFVNNA0hJorZ3lG36N2370MohQljPPuSUW7QEunXrFp999lkcd9xxabJGW9XLtrJCOGDAgDQhpevL8ssvP9vrNtxwwzj99NPThJSEUNKo42rXQqHpfV27dk2rkM2aNUtbxyV92hpWaBoMdujQIW1N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PHlyrLvuuqFj77rrrpVuGR00aFDcdtttscwyy8Q333wTY8eOjXPPPTdeeumlGD58eEycODEdT8dXe+ONN+K6666LKVOmpH+75JJLUk3jx4+PM888M71n2rRpcdhhh0W3bt3Se7p27RrbbLNNvPbaazFp0qRo2rRp3HjjjdGiRYu5fghrsmV00vTf4tHhH8V3v46Ppg0bRZsWy8U2K7aJpg3n5G71DaAYSwL6fjVv3jxOO+20VN+f//zn2HfffWPPPfessN73338/rrzyyvj1119joYUWigsvvDC22mqr+Omnn+Lss8+OL774Ilq2bBl77LFHfP311+n7e8cdd8Riiy0Wb731VroG6Zqz8sorx1VXXRX9+/dP39O99947HnnkkbluGdX3fMstt4x33nknfvjhh1h77bVj9913T8fX9WKVVVZJ16iFF144XVd0zfv444+jSZMm6fq48cYbp5oee+yxuPvuu9N7ll566dCWz9atW0fhWrXCCiukc9e1Sn3us88+c82+pltGB44aHgNGDY9J06fF0os2i21WahNtmi9n+TmjKG8CjElqPyap6ZbRcVMnxrPffMqYxPsrRnVFRKCohFBcHnjggRg8eHAaVO21117Ro0ePaNeuXYXIXn311SSPN998c/r9d999lwZAkqvDDz88DdCWX375uOeee+Lqq69OgzYJ4YYbbhidO3dOA0AN6CRi2223Xfp5iy22iE8//TT222+/6Nmz51yF8IADDohnn3022rRpkwZ8p5xySvTp0ycN0D788MNUg85Bgzy9VgNDDcrOOuusWGONNZL4/f7770lWO3bsmAZqO+ywQxpM6jw1aGvUqFES2wYNGiQWiy++eJx88sl1LoTXf9I/hv08erbj7rby+rH7H9Yvoo8rpwKBqhGQOEn+NEH0j3/8I55//vm46667Kn2zXqsJmzXXXDN+/vnnJIVLLLFEnH766dGqVav0/+PGjUvfY8lbQQh79+4d11xzTbqeqD388MOpr3vvvTcJ3F/+8pfQKuHc7iHU91zXoZtuuildD3Tdk3xK7ho2bBhHHHFEuhZIUCWDeq0mkb788svo0qVLvPzyy9GsWbP4/PPP0/VFInzttdemSSSdp4Rw//33j379+qVrqerQpNiAAQMqnGgrQKqJEA79eVTc+Mmrs3Fu0qBR9Nh4TyaXqvbR5VVFRoAxSe3GJDUVQsYkRfZF4HTsCRSdEGpFT6uEGvSsuuqqcd5551UagmbtjzvuuLjiiitis802m/U6DfxGjRqVVujUdEFab7314t13302ipRVADdo0866m1cHzzz8/yV2hHXTQQWkgVtlDZTTI0rm98MIL6S3ffvttHHjggTFw4MD0s1YaNUjUKud9990X33//fepDTWIq2dTgsXzTgFODPp2jBoEayBXOQef8+uuvp9WCQnvuuefmOIZWRYYNG1atD2+3tx6a4/V/bL5sdG+7XbWOw4shUCwE3n777fQ90yq8Jmo0OVRZ03dGK3qabNE1otDatm0bOo7kUE0r9L/88sssIRw6dGj6t0I7+uij03Vg++23T/8k6br88svnKYT63ushVmravdChQ4c4+OCD088SzhVXXDFNcrVv3z5dAyR9aoceemh6aE2nTp1mK03n/OCDD6ZVRl2rtHuhrJRKCHWd1Iqmmuoof834+9//nlYaTzzxxCpHqhn95779dI7Xn952W1YJq0yRFxYTAcYkVR+TaEKrMCYqm6F2WQwZMqRasTImqRYuXgyBWhMoOiFURRIfzaxrm+VKK6001yI1aNFWUAngOeeck2bvtTKnGfZjjz121ns32mijNJNeEEKtGmgVQE1bMjVg1EpioWmQNa8to5qFf+ih/4iUtpZI4F555ZX089SpU2PTTTdNW7u0Ovnkk0/OGsTNmDEjDT61eiiR1NbTH3/8MZ2PVke16rD++uun46kGHUdNAzptSdVKQqFpwFu+iUddCGGrZi3iwva71PpDxgEgsKAISLK0Kqbv4NyaVtP0/dcqmrZpawVOTdu7da0oNEmWVvwKK4Tanql7ewpNq3uXXnppbLDBBumfNGml389rhbDs91w7CDSZtNtuu6VjaOVSYibR1HE1UVZoWgnV9lbVqR0IusapTZgwIV0DJX0SwrLXKv1ek0y33HJLrL766un1Eldtmy3bRo8ena6/dSGEx6/TOdq1bLWgPgb0C4FaEWBMUrUxicY2hR1bBeAa19x5550IYa0+gbwZAvOfQNEJoURK27c04637d8rKz9xwaNB21FFHpQHRo48+mrZfFlYXdZHSipsGPQUhLDtbpRVC3Yuj7aeFpnv5NPs+txVCDdQkkmpzE0KtEI4ZMyZtFS3fdI+Rtn0V7m3SgFIrCgUh1LbSwn2IFQlhRUxqcg/hue8/HT9NnTjb4Tott2p0WXP2lYf5/5GkBwjUDQHJnbZf6745XUfWWmuteR5Yuwkke1oR1ASTvoda9deOBTUNdrTlsiCEul5pq3ihaYVQOxwklWqSLK34z0sIy37PKxPCI488Mq0QavVP9xOXbVo1VI0SVm0r1ySXdiAUhLDstUrvKy+EFYGpyZZR3Tt4/xfvznE4bRlt2bjZPPnzAggUGwHGJLUbk9R0yyhjkmL7JnA+7gSKTgi1PUpNgyIJmQZBhe1X5cPQvXmLLrpoLLnkkulhC1rRe+KJJ5IMSg71kIXlllsuDZL0AJnCPYSSw7JCqAuW7iHUVkzd//fZZ5+lewhvuOGGOhFCbRfV9i/dEyRZ039gNPuu+x21EqBBpmb+tb1Ucti3b9/sQvjdxPHRa8ibs6RQ20VPWKcz9/24XwFM69OOAa2oaXJI99pJiHQ90L24FTV95/VQKrX7778/PShKk0TaQqr7CvX/2nqq77FW7CsTQk0Q6d5m3buoewi10qh7++pKCCWXjRs3TsfV/cXaYaCtsM8880zaPSAB1PXljDPOSFvlcwuh+D3y1d/jte+HJpa6f/CA1TvEZsutZvpJoyx3AoxJajcmqakQMiZx/2ZRX7ERKCoh1MNcNJDR4EaiN2LEiLRtUit3hXtmygLUw1g0i68ngmpwpNdqEKim2XFtU9Cedm290r52bdGsaIVQr9e2Km29klhqACjJlKzVxQqhjq8nCOo/LBJBPV1UA0zdH6j7FiWieiiEZv918dS9QrlXCIvtg8n5QKA2BHRv8dZbbx26F1hN1wlttSw8wbf8sTUBpZVAyZbuq9N3VU8Q1vdV979oC7Z+1mq9tolWJoR6QJUe/qSVSa3U6busCamK7qspnIOuW1VdIdT1SdtftZ1e1wrVpAfY6D4nbXPXNVPnqfuf9XTmBSGEtcmN90KgmAgwJqn9mKSmQlhMnwPOBQL1gUBRCeH8BK5ZfQ3Kyj4wYn72tyCPXZMtowvyfOkbAqVCQPcM675ACaF7q8mWUXcm1AeBuiJQX8YkCGFdfWI4DgTmL4GSEEJt4dJ2r7JNK3h6HHRVW00vvnrin57AV7Zp5bDw0Imq9p/zdQhhTtr0VSoENDDR3yIs30444YRKdwKUf21NhVC7GbTds3zTA6X0Zy2KsSGExZgK51QMBBiTVD0FhLDqrHglBBYkgZIQwroAVFMhrIu+cx8DIcxNnP7qC4GaCmEp8kEISzE1zrlUCNSXMQlCWCqfSM6zvhOoN0JYn4JGCOtT2tQKgflDACGcP1w5KgTqEwGEsD6lTa2lTAAhLOX0Kjl3hNAwVEqCQGYCCGFm4HQHAUMCCKFhqJRkSQAhNIwVITQMlZIgkJkAQpgZON1BwJAAQmgYKiVZEkAIDWNFCA1DpSQIZCaAEGYGTncQMCSAEBqGSkmWBBBCw1gRQsNQKQkCmQkghJmB0x0EDAkghIahUpIlAYTQMFaE0DBUSoJAZgIIYWbgdAcBQwIIoWGolGRJACE0jBUhNAyVkiCQmQBCmBk43UHAkABCaBgqJVkSQAgNY0UIDUOlJAhkJoAQZgZOdxAwJIAQGoZKSZYEEELDWBFCw1ApCQKZCSCEmYHTHQQMCSCEhqFSkiUBhNAwVoTQMFRKgkBmAghhZuB0BwFDAgihYaiUZEkAITSMFSE0DJWSIJCZAEKYGTjdQcCQAEJoGColWRJACA1jRQgNQ6UkCGQmgBBmBk53EDAkgBAahkpJlgQQQsNYEULDUCkJApkJIISZgdMdBAwJIISGoVKSJQGE0DBWhNAwVEqCQGYCCGFm4HQHAUMCCKFhqJRkSQAhNIwVITQMlZIgkJkAQpgZON1BwJAAQmgYKiVZEkAIDWNFCA1DpSQIZCaAEGYGTncQMCSAEBqGSkmWBBBCw1gRQsNQKQkCmQkghJmB0x0EDAkghIahUpIlAYTQMFaE0DBUSoJAZgIIYWbgdAcBQwIIoWGolGRJACE0jBUhNAyVkiCQmQBCmBk43UHAkABCaBgqJVkSQAgNY0UIDUOlJAhkJoAQZgZOdxAwJIAQGoZKSZYEEELDWBFCw1ApCQKZCSCEmYHTHQQMCSCEhqFSkiUBhNAwVoTQMFRKgkBmAghhZuB0BwFDAgihYaiUZEkAITSMFSE0DJWSIJCZAEKYGTjdQcCQAEJoGColWRJACA1jRQgNQ6UkCGQmgBBmBk53EDAkgBAahkpJlgQQQsNYEULDUCkJApkJIISZgdMdBAwJIISGoVKSJQGE0DBWhNAwVEqCQGYCCGFm4HQHAUMCCKFhqJRkSQAhNIwVITQMlZIgkJkAQpgZON1BwJAAQmgYKiVZEkAIDWNFCA1DpSQIZCaAEGYGTncQMCSAEBqGSkmWBBBCw1gRQsNQKQkCmQkghJmB0x0EDAkghIahUpIlAYTQMFaE0DBUSoJAZgIIYWbgdAcBQwIIoWGolGRJACE0jBUhNAyVkiCQmQBCmBk43UHAkABCaBgqJVkSQAgNY0UIDUOlJAhkJoAQZgZOdxAwJIAQGoZKSZYEEELDWBFCw1ApCQKZCSCEmYHTHQQMCSCEhqFSkkEKmPEAACAASURBVCUBhNAwVoTQMFRKgkBmAghhZuB0BwFDAgihYaiUZEkAITSMFSE0DJWSIJCZAEKYGTjdQcCQAEJoGColWRJACA1jRQgNQ6UkCGQmgBBmBk53EDAkgBAahkpJlgQQQsNYEULDUCkJApkJIISZgdMdBAwJIISGoVKSJQGE0DBWhNAwVEqCQGYCCGFm4HQHAUMCCKFhqJRkSQAhNIwVITQMlZIgkJkAQpgZON1BwJAAQmgYKiVZEkAIDWNFCA1DpSQIZCaAEGYGTncQMCSAEBqGSkmWBBBCw1gRQsNQKQkCmQkghJmB0x0EDAkghIahUpIlAYTQMFaE0DBUSoJAZgIIYWbgdAcBQwIIoWGolGRJACE0jBUhNAyVkiCQmQBCmBk43UHAkABCaBgqJVkSQAgNY0UIDUOlJAhkJoAQZgZOdxAwJIAQGoZKSZYEEELDWBFCw1ApCQKZCSCEmYHTHQQMCSCEhqFSkiUBhNAwVoTQMFRKgkBmAghhZuB0BwFDAgihYaiUZEkAITSMFSE0DJWSIJCZAEKYGTjdQcCQAEJoGColWRJACA1jRQgNQ6UkCGQmgBBmBk53EDAkgBAahkpJlgQQQsNYEULDUCkJApkJIISZgdMdBAwJIISGoVKSJQGE0DBWhNAwVEqCQGYCCGFm4HQHAUMCCKFhqJRkSQAhNIwVITQMlZIgkJkAQpgZON1BwJAAQmgYKiVZEkAIDWNFCA1DpSQIZCaAEGYGTncQMCSAEBqGSkmWBBBCw1gRQsNQKQkCmQkghJmB0x0EDAkghIahUpIlAYTQMFaE0DBUSoJAZgIIYWbgdAcBQwIIoWGolGRJACE0jBUhNAyVkiCQmQBCmBk43UHAkABCaBgqJVkSQAgNY0UIDUOlJAhkJoAQZgZOdxAwJIAQGoZKSZYEEELDWBFCw1ApCQKZCSCEmYHTHQQMCSCEhqFSkiUBhNAwVoTQMFRKgkBmAghhZuB0BwFDAgihYaiUZEkAITSMFSE0DJWSIJCZAEKYGTjdQcCQAEJoGColWRJACA1jRQgNQ6UkCGQmgBBmBk53EDAkgBAahkpJlgQQQsNYEULDUCkJApkJIISZgdMdBAwJIISGoVKSJQGE0DBWhNAwVEqCQGYCCGFm4HQHAUMCCKFhqJRkSQAhNIwVITQMlZIgkJkAQpgZON1BwJAAQmgYKiVZEkAIDWNFCA1DpSQIZCaAEGYGTncQMCSAEBqGSkmWBBBCw1gRQsNQKQkCmQkghJmB0x0EDAkghIahUpIlAYTQMFaE0DBUSoJAZgIIYWbgdAcBQwIIoWGolGRJACE0jBUhNAyVkiCQmQBCmBk43UHAkABCaBgqJVkSQAgNY0UIDUOlJAhkJoAQZgZOdxAwJIAQGoZKSZYEEELDWBFCw1ApCQKZCSCEmYHTHQQMCSCEhqFSkiUBhNAwVoTQMFRKgkBmAghhZuB0BwFDAgihYaiUZEkAIawk1lNPPTV22mmn2HnnnUsueISw5CLjhE0JfPXVV3HSSSfFiy++WHIVIoQlFxknbEygVMckCKHxh5LSrAgghAih1QeaYiBQTAQQwmJKg3OBQOkSQAhLNzvOHAKlQAAhRAhnEZg0/bcYOGpEfPHzqGi5aLPYoGWraNN8uVL4HHOOEChKAvVVCAeOGh5Dfx6dMmnTfNnotNxqRZkPJwWBUiGAEJZKUv93ngNGDY8vuA6WXnD19IyLSghfffXV6N27dzz44IOz4tB2qx122CH22GOPOSKaPn16XHzxxfHee++FtiWss846cfvtt6fXPf7449GrV6+YOXNm2vb50Ucfxa233hpLLbVU7LjjjtG9e/e47LLLYpNNNonrr78+Pvnkk7jgggti8uTJse6664aOveuuu1a6ZXTQoEFx2223xTLLLBPffPNNjB07Ns4999x46aWXYvjw4TFx4sR0PB1f7Y033ojrrrsupkyZkv7tkksuiUUWWSTGjx8fZ555ZnrPtGnT4rDDDotu3bql93Tt2jW22WabeO2112LSpEnRtGnTuPHGG6NFixZz/bjWdMvo9Z/0j2H/vXgVOjh+nc7RrmWrevr1oOxSJbDnnnum799GG22UShg2bFgcf/zx0b9//wpLev/99+PKK6+MX3/9NRZaaKG48MILY6uttoqffvopzj777Pjiiy+iZcuW6Tr09ddfp+/vHXfcEYsttli89dZb6Rqka87KK68cV111VepH39O99947HnnkkbluGdX3fMstt4x33nknfvjhh1h77bVj9913T8fX9WKVVVZJ16iFF144XVd0zfv444+jSZMmcdFFF8XGG2+canrsscfi7rvvTu9ZeumlQ1s+W7duHYVr1QorrJDOXdcq9bnPPvvMNd6abhl99ptP47lvP53t2Nus2CYOXL1DqX6cOO96SoAxSe3HJPV1y2hF18HdVl4/dv/D+vX020TZxU6gqIRQEta5c+d44oknYvnll08StPXWWyeZkgyVb7pYP/XUU3HzzTenX3333XdpACS5Ovzww9MATce555574uqrr06DNgnhhhtumPrRAFADOonYdtttl37eYost4tNPP4399tsvevbsOVchPOCAA+LZZ5+NNm3apAHfKaecEn369EkDtA8//DANDHUOGuTptRoYalB21llnxRprrJHE7/fff0+y2rFjxzRQk/xqMKnz1KCtUaNGSWwbNGgQPXr0iMUXXzxOPvnkWSg0UC3fJLIaAFenaXXwtIGPzfGWPzZfNrq33a46h+K1EFjgBB544IH0Hbj88svTuei7LNHTLHtFTQKpCZs111wzfv755/TaJZZYIk4//fRo1apV+v9x48al77HkrSCEmsC65ppr0vVE7eGHH47nn38+7r333iRwf/nLX0KrhHO7h1Dfc12HbrrppnQ92GuvvZJ8Su4aNmwYRxxxRLoWSFAlg3qtJpG+/PLL6NKlS7z88svRrFmz+Pzzz9P1pXnz5nHttdem66fOU0K4//77R79+/aJdu3apDk2KDRgwIE1Kqenf9L+yTddhXW9OPPHEauV5+UcvxsiJ42d7T5MGjaLnZvtX6zi8GAILmgBjkuqNSTQBX37sMWPGjDSeGjJkSI3i/Pe0KfHM15/EuKkTa/T+BfWmzyf8GDNmzpyt+5aNm0WPjfdcUKdEvxCYK4GiEkKdqaRn2WWXjaOPPjrJlqRPg7mKmmTouOOOiyuuuCI222yzWS+56667YtSoUWmFQE0zVOutt168++67SbS0AqhBm2be1bQ6eP7556f+Cu2ggw5KA7HKHiqjQdZ5550XL7zwQnrLt99+GwceeGAMHDgw/ayVRg0SP/jgg7jvvvvi+++/T32oSUxVkwaP5ZsGnBr06Rw1CNRArnAOOufXX389rRYU2gknnDDHMf76179WWwi/mzg+rvho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+SaE137y1/jq5zGzHV//Meu52f62XwIKg0B1CUyfPj1dK5544olYfvnl04TN1ltvnSZ+JF2nnXZaPPPMM2niZ/XVV4+jjz660i70PV9sscXipptuSteDvfbaK1q2bJnkrmHDhnHEEUeka8FWW22VZFCv1STSl19+GV26dImXX345mjVrFp9//nm6vjRv3jyuvfbadE7qX0K4//77R79+/aJdu3Yxbty42HHHHWPAgAFpUqqyVlsh/PKXMfHVL7NfS6rLmddDoNQIjJnya7z1w5dznHZlE6vuY5LaCuHEab/F38d9G5On/1ZqH4X5fr4vffdZTCrHpVWzJePC9jvP977pwI9AvRNCrcjtsssu8be//S0NhiRgt99+e6y22mpJyA488MA0GJOsaba/sqZB1nnnnRcvvPBCesm3336b3jtw4MD08+TJk9OA8YMPPkgrBlptPP/889Pv3nvvvSSiDz/88ByHlzhq0LfuuuumQaAGcjvv/J8v9/PPPx+vv/56Wi0otO23336OY2hAKumtSTvn/adj/NSJc7z1ji0PqcnheA8EbAlogmbZZZdNsqeJIa0a6nutdsMNNyRB++mnn+LRRx9NEzqVNX3P9b3faaed0ku6d+8eHTp0iIMPPjj9fM0118SKK64Yhx9+eLRv3z5dAyR9aoceemiayOrUqdNsh3/77bfT6qVWGXWt0u4FTVoVmoTwrrvuipVXXjn9k1Y7NZlVtq255pqxzjrrxIknnlijDD8Y/U3cPfSdGr2XN0HAjUBlQug0JtEuJ42vyjZNamsX1ZAhQ2oU6b+nTYmen76ett/SqkaA8VrVOPGq2QnUOyFU+SeccELaLtWqVau0tUsrgYWmLVgaTGlwp5XDypoGWZqF1xZTtZEjRyaBe+WVV9LPU6dOjU033TRt7br66qvjySefnDWImzFjRtr2qdVDiaS2nv7444+pv8GDB6fB2frrr5+Od+yxx6bjqGlApy2pWkmYW6vNllFWCLlEQKBqBCR8Wu3XSqCuKfvuu++sSaTRo0fHFltskWRu7733nusBy3/PdUxNJu22227pfdpqri2gmnDaYIMNYtVVV511PG0hvfDCC5NMageCVgvVtFVVE1uSvvLXKv1ek0zaFq/Vy8paXawQDv9lbNVg8ioImBDQCuGbP8w5ITu3Wy+cxyR1sUL4UVohnGbyCam7Ml78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gdMdBAwJIISGoVKSJQGE8L+x9ujRI5ZYYok46aST0r/MmDEjttxyy3jiiSdi+eWXnyP8QYMGxW233RbLLLNMfPPNNzF27Ng499xz46WXXorhw4fHxIkT44ILLohNNtkkvfeNN96I6667LqZMmZL+7ZJLLolFFlkkxo8fH2eeeWZ6z7Rp0+Kwww6Lbt26pfd07do1ttlmm3jttddi0qRJ0bRp07jxxhujRYsWc/0wIoSW31WKms8EJk3/LW777M344ufRqaeWjZvF8et2jtbNlqxyz/o+77DDDvHmm29GkyZN0vsefPDB+Pzzz+PKK6+s8Dj6nuta884778QPP/wQa6+9duy+++5xxx13pOvFKqusEtdff30svPDC6bpy8cUXx8cff5yOf9FFF8XGG2+cjvvYY4/F3Xffnd6z9NJLh4SudevWUbhWrbDCCvH111+na5X63GeffeZaV22EsPcX78bAUcPT8Zs0aBRd2nSKdi1bVZkjL4RAfSfgMiZBCOv7J5n6a0qgLsYk1ekbIfwvraFDh8bJJ58cr7zySvqXgQMHxs033xwPPfRQhTw1yDrggAPi2WefjTZt2sSLL74Yp5xySvTp0ycN0D788MO46qqr4vHHH0+DPL32kUceCQ3KzjrrrFhjjTWS+P3+++/x0UcfRceOHdNATYPJ/v37x1JLLZUGbY0aNYpevXpFgwYNQv+BWHzxxdN5zq3VVgjHTPk1ZsbM6nyOeC0ESp7AEyM+jo/HjpytDklhj433rFZtJ554Yuy8886x2267pfcdfPDBceqpp8amm25aqRAutthicdNNN6XrwV577RUtW7ZMctewYcM44ogj0rVgq622SjKo12oS6csvv4wuXbrEyy+/HM2aNUvSqetL8+bN49prr02TSJp40rVq//33j379+kW7du1i3LhxseOOO8aAAQPSpFRlraZCOGDU8Lj/i3dnO6yk8MIOuyTJpkEAAvMm4DImqa0QTvt9Rkz4bTJjknl/ZHiFGYG6GpNUFQtCWIbUnnvuGVdccUWsv/76aXVv3XXXTYO5ipoGWeedd1688MIL6dfffvttHHjggUkk1SZPnhydO3eODz74IO677774/vvv4/zzz0+/e++996Jnz57x8MMPz3FoiaMGfepbg0AN5DS4VHv++efj9ddfT6sFhaYVw/JNK5fDhg2r6mdgttdNnP5b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"
      },
      "metadata": {},
      "output_type": "display_data"
@@ -535,13 +699,21 @@
    "source": [
     "from estimagic.visualization.lollipop_plot import lollipop_plot\n",
     "\n",
-    "sensitivity_data = res[\"sensitivity\"][\"sensitivity_to_bias\"].abs().T\n",
+    "sensitivity_data = res.sensitivity(kind=\"bias\").abs().T\n",
     "\n",
     "fig = lollipop_plot(sensitivity_data)\n",
     "\n",
     "fig = fig.update_layout(height=500, width=900)\n",
     "fig.show(renderer=\"png\")"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "3da1b18f",
+   "metadata": {},
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {
diff --git a/docs/source/refs.bib b/docs/source/refs.bib
index 170c177e7..e8181b13b 100644
--- a/docs/source/refs.bib
+++ b/docs/source/refs.bib
@@ -517,7 +517,6 @@ @Article{Broyden1965
   number    = {92},
   pages     = {577--577},
   volume    = {19},
-  doi       = {10.1090/s0025-5718-1965-0198670-6},
   publisher = {American Mathematical Society ({AMS})},
 }
 
diff --git a/src/estimagic/estimation/estimate_ml.py b/src/estimagic/estimation/estimate_ml.py
index 553774746..b0a6cff79 100644
--- a/src/estimagic/estimation/estimate_ml.py
+++ b/src/estimagic/estimation/estimate_ml.py
@@ -1,18 +1,30 @@
+from dataclasses import dataclass
+from typing import Any
+from typing import Union
+
+import numpy as np
+import pandas as pd
 from estimagic.differentiation.derivatives import first_derivative
 from estimagic.differentiation.derivatives import second_derivative
 from estimagic.exceptions import InvalidFunctionError
+from estimagic.exceptions import NotAvailableError
 from estimagic.inference.ml_covs import cov_cluster_robust
 from estimagic.inference.ml_covs import cov_hessian
 from estimagic.inference.ml_covs import cov_jacobian
 from estimagic.inference.ml_covs import cov_robust
 from estimagic.inference.ml_covs import cov_strata_robust
+from estimagic.inference.shared import calculate_ci
 from estimagic.inference.shared import calculate_inference_quantities
+from estimagic.inference.shared import calculate_p_values
 from estimagic.inference.shared import check_is_optimized_and_derivative_case
 from estimagic.inference.shared import get_derivative_case
 from estimagic.inference.shared import transform_covariance
 from estimagic.optimization.optimize import maximize
+from estimagic.optimization.optimize_result import OptimizeResult
+from estimagic.parameters.block_trees import block_tree_to_matrix
+from estimagic.parameters.block_trees import matrix_to_block_tree
+from estimagic.parameters.conversion import Converter
 from estimagic.parameters.conversion import get_converter
-from estimagic.parameters.parameter_bounds import get_bounds
 from estimagic.shared.check_option_dicts import check_numdiff_options
 from estimagic.shared.check_option_dicts import check_optimization_options
 
@@ -31,11 +43,8 @@ def estimate_ml(
     numdiff_options=None,
     jacobian=None,
     jacobian_kwargs=None,
-    hessian=False,
+    hessian=None,
     hessian_kwargs=None,
-    ci_level=0.95,
-    n_samples=10_000,
-    bounds_handling="raise",
     design_info=None,
 ):
     """Do a maximum likelihood (ml) estimation.
@@ -46,17 +55,14 @@ def estimate_ml(
 
     While we have good defaults, you can still configure each aspect of each step
     via the optional arguments of this function. If you find it easier to do the
-    "difficult" steps (mainly maximization and calculating numerical derivatives
-    of a potentially noisy function) separately, you can do so and just provide those
-    results as ``params``, ``jacobian`` and ``hessian``.
-
-    The docstring is aspirational and not all options are supported yet.
+    maximization separately, you can do so and just provide the optimal parameters as
+    ``params`` and set ``optimize_options=False``.
 
     Args:
         loglike (callable): Likelihood function that takes a params (and potentially
             other keyword arguments) and returns a dictionary that has at least the
             entries "value" (a scalar float) and "contributions" (a 1d numpy array or
-            pandas Series) with the log likelihood contribution per individual.
+            pytree) with the log likelihood contribution per individual.
         params (pytree): A pytree containing the estimated or start parameters of the
             likelihood model. If the supplied parameters are estimated parameters, set
             optimize_options to False. Pytrees can be a numpy array, a pandas Series, a
@@ -64,10 +70,11 @@ def estimate_ml(
             or list containing these elements. See :ref:`params` for examples.
         optimize_options (dict, str or False): Keyword arguments that govern the
             numerical optimization. Valid entries are all arguments of
-            :func:`~estimagic.optimization.optimize.minimize` except for criterion. If
-            you pass False as optimize_options you signal that ``params`` are already
-            the optimal parameters and no numerical optimization is needed. If you pass
-            a str as optimize_options it is used as the ``algorithm`` option.
+            :func:`~estimagic.optimization.optimize.minimize` except for those that are
+            passed explicilty to ``estimate_ml``. If you pass False as optimize_options
+            you signal that ``params`` are already the optimal parameters and no
+            numerical optimization is needed. If you pass a str as optimize_options it
+            is used as the ``algorithm`` option.
         lower_bounds (pytree): A pytree with the same structure as params with lower
             bounds for the parameters. Can be ``-np.inf`` for parameters with no lower
             bound.
@@ -97,10 +104,8 @@ def estimate_ml(
         jacobian (callable or None): A function that takes ``params`` and potentially
             other keyword arguments and returns the jacobian of loglike["contributions"]
             with respect to the params. Note that you only need to pass a Jacobian
-            function if you have a closed form Jacobian but decided not to return it as
-            part of ``derivative`` (e.g.  because you use a scalar optimizer and can
-            calculate a gradient in a way that is faster than calculating and summing
-            the Jacobian). If you pass None, a numerical Jacobian will be calculated.
+            function if you have a closed form Jacobian. If you pass None, a numerical
+            Jacobian will be calculated.
         jacobian_kwargs (dict): Additional keyword arguments for the Jacobian function.
         hessian (callable or None or False): A function that takes ``params`` and
             potentially other keyword arguments and returns the Hessian of
@@ -109,26 +114,13 @@ def estimate_ml(
             Hessian should be calculated. Thus, no result that requires the Hessian will
             be calculated.
         hessian_kwargs (dict): Additional keyword arguments for the Hessian function.
-        ci_level (float): Confidence level for the calculation of confidence intervals.
-            The default is 0.95.
-        n_samples (int): Number of samples used to transform the covariance matrix of
-            the internal parameter vector into the covariance matrix of the external
-            parameters. For background information about internal and external params
-            see :ref:`implementation_of_constraints`. This is only used if you have
-            specified constraints.
-        bounds_handling (str): One of "clip", "raise", "ignore". Determines how bounds
-            are handled. If "clip", confidence intervals are clipped at the bounds.
-            Standard errors are only adjusted if a sampling step is necessary due to
-            additional constraints. If "raise" and any lower or upper bound is binding,
-            we raise an Error. If "ignore", boundary problems are simply ignored.
         design_info (pandas.DataFrame): DataFrame with one row per observation that
             contains some or all of the variables "psu" (primary sampling unit),
-            "stratum" and "fpc" (finite population corrector). See
+            "strata" and "fpc" (finite population corrector). See
             :ref:`robust_likelihood_inference` for details.
 
     Returns:
-        dict: The estimated parameters, standard errors and covariance matrix of the
-            parameters.
+        LikelihoodResult: A LikelihoodResult object.
 
     """
     # ==================================================================================
@@ -153,8 +145,6 @@ def estimate_ml(
     check_is_optimized_and_derivative_case(is_optimized, jac_case)
     check_is_optimized_and_derivative_case(is_optimized, hess_case)
 
-    cov_cases = _get_cov_cases(jac_case, hess_case, design_info)
-
     check_numdiff_options(numdiff_options, "estimate_ml")
     numdiff_options = {} if numdiff_options in (None, False) else numdiff_options
     loglike_kwargs = {} if loglike_kwargs is None else loglike_kwargs
@@ -168,6 +158,7 @@ def estimate_ml(
 
     if is_optimized:
         estimates = params
+        opt_res = None
     else:
         opt_res = maximize(
             criterion=loglike,
@@ -200,21 +191,26 @@ def estimate_ml(
         except (KeyboardInterrupt, SystemExit):
             raise
         except Exception as e:
-            msg = "Error while evaluating derivative at estimated params."
+            msg = "Error while evaluating closed form jacobian at estimated params."
             raise InvalidFunctionError(msg) from e
     else:
         jacobian_eval = None
 
+    if callable(hessian):
+        try:
+            hessian_eval = hessian(estimates, **hessian_kwargs)
+        except (KeyboardInterrupt, SystemExit):
+            raise
+        except Exception as e:
+            msg = "Error while evaluating closed form hessian at estimated params."
+            raise InvalidFunctionError(msg) from e
+    else:
+        hessian_eval = None
+
     # ==================================================================================
     # Get the converter for params and function outputs
     # ==================================================================================
 
-    lower_bounds, upper_bounds = get_bounds(
-        params,
-        lower_bounds=lower_bounds,
-        upper_bounds=upper_bounds,
-    )
-
     converter, flat_estimates = get_converter(
         func=loglike,
         params=estimates,
@@ -235,7 +231,6 @@ def estimate_ml(
     if jac_case == "closed-form":
         x = converter.params_to_internal(estimates)
         int_jac = converter.derivative_to_internal(jacobian_eval, x)
-    # switch to "numerical" even if jac_case == "skip" because jac is required for ml.
     elif jac_case == "numerical":
 
         def func(x):
@@ -253,10 +248,26 @@ def func(x):
         )
 
         int_jac = jac_res["derivative"]
-        jac_numdiff_info = {k: v for k, v in jac_res.items() if k != "derivative"}
     else:
         int_jac = None
 
+    if constraints in [None, []] and jacobian_eval is None and int_jac is not None:
+        loglike_contribs = loglike_eval
+        if isinstance(loglike_contribs, dict) and "contributions" in loglike_contribs:
+            loglike_contribs = loglike_contribs["contributions"]
+
+        jacobian_eval = matrix_to_block_tree(
+            int_jac,
+            outer_tree=loglike_contribs,
+            inner_tree=estimates,
+        )
+
+    if jacobian_eval is None:
+        _no_jac_reason = (
+            "no closed form jacobian was provided and there are constraints"
+        )
+    else:
+        _no_jac_reason = None
     # ==================================================================================
     # Calculate internal Hessian
     # ==================================================================================
@@ -279,105 +290,450 @@ def func(x):
             **numdiff_options,
         )
         int_hess = hess_res["derivative"]
-        hess_numdiff_info = {k: v for k, v in hess_res.items() if k != "derivative"}
     elif hess_case == "closed-form" and constraints:
         raise NotImplementedError(
             "Closed-form Hessians are not yet compatible with constraints."
         )
+    elif hess_case == "closed-form":
+        int_hess = block_tree_to_matrix(
+            hessian_eval,
+            outer_tree=params,
+            inner_tree=params,
+        )
     else:
-        int_hess = hessian(estimates, **hessian_kwargs)
-
-    # ==================================================================================
-    # Calculate all available internal cov types
-    # ==================================================================================
+        raise ValueError()
 
-    int_covs = {}
-    if "jacobian" in cov_cases:
-        int_covs["cov_jacobian"] = cov_jacobian(int_jac)
-    if "hessian" in cov_cases:
-        int_covs["cov_hessian"] = cov_hessian(int_hess)
-    if "robust" in cov_cases:
-        int_covs["cov_robust"] = cov_robust(jac=int_jac, hess=int_hess)
-    if "cluster_robust" in cov_cases:
-        int_covs["cov_cluster_robust"] = cov_cluster_robust(
-            jac=int_jac, hess=int_hess, design_info=design_info
-        )
-    if "strata_robust" in cov_cases:
-        int_covs["cov_strata_robust"] = cov_strata_robust(
-            jac=int_jac, hess=int_hess, design_info=design_info
+    if constraints in [None, []] and hessian_eval is None and int_hess is not None:
+        hessian_eval = matrix_to_block_tree(
+            int_hess,
+            outer_tree=params,
+            inner_tree=params,
         )
 
+    if hessian_eval is None:
+        if hess_case == "skip":
+            _no_hess_reason = "the hessian calculation was explicitly skipped."
+        else:
+            _no_hess_reason = (
+                "no closed form hessian was provided and there are constraints"
+            )
+    else:
+        _no_hess_reason = None
+
     # ==================================================================================
-    # Calculate all available external covs and summaries
+    # create a LikelihoodResult object
     # ==================================================================================
 
-    covs = {}
-    summaries = {}
-    for case in cov_cases:
-        cov = transform_covariance(
-            flat_params=flat_estimates,
-            internal_cov=int_covs[f"cov_{case}"],
+    res = LikelihoodResult(
+        params=estimates,
+        _converter=converter,
+        optimize_result=opt_res,
+        _jacobian=jacobian_eval,
+        _no_jacobian_reason=_no_jac_reason,
+        _hessian=hessian_eval,
+        _no_hessian_reason=_no_hess_reason,
+        _internal_jacobian=int_jac,
+        _internal_hessian=int_hess,
+        _design_info=design_info,
+        _flat_params=flat_estimates,
+        _has_constraints=constraints not in [None, []],
+    )
+
+    return res
+
+
+@dataclass
+class LikelihoodResult:
+    params: Any
+    _flat_params: Any
+    _converter: Converter
+    _has_constraints: bool
+    optimize_result: Union[OptimizeResult, None] = None
+    _jacobian: Any = None
+    _no_jacobian_reason: Union[str, None] = None
+    _hessian: Any = None
+    _no_hessian_reason: Union[str, None] = None
+    _internal_jacobian: Union[np.ndarray, None] = None
+    _internal_hessian: Union[np.ndarray, None] = None
+    _design_info: Union[pd.DataFrame, None] = None
+
+    def __post_init__(self):
+        if self._internal_jacobian is None and self._internal_hessian is None:
+            raise ValueError(
+                "At least one of _internal_jacobian or _internal_hessian must be "
+                "not None."
+            )
+
+        elif self._internal_jacobian is None:
+            valid_methods = ["hessian"]
+        elif self._internal_hessian is None:
+            valid_methods = ["jacobian"]
+        else:
+            valid_methods = ["jacobian", "hessian", "robust"]
+            if self._design_info is not None:
+                if "psu" in self._design_info:
+                    valid_methods.append("cluster_robust")
+                if {"strata", "psu", "fpc"}.issubset(self._design_info):
+                    valid_methods.append("strata_robust")
+
+        self._valid_methods = set(valid_methods)
+
+    def _get_free_cov(
+        self,
+        method,
+        n_samples,
+        bounds_handling,
+        seed,
+    ):
+        if method not in self._valid_methods:
+            raise ValueError()
+
+        internal_jac = self._internal_jacobian
+        internal_hess = self._internal_hessian
+        design_info = self._design_info
+        converter = self._converter
+        flat_params = self._flat_params
+
+        if method == "jacobian":
+            int_cov = cov_jacobian(internal_jac)
+        elif method == "hessian":
+            int_cov = cov_hessian(internal_hess)
+        elif method == "robust":
+            int_cov = cov_robust(jac=internal_jac, hess=internal_hess)
+        elif method == "cluster_robust":
+            int_cov = cov_cluster_robust(
+                jac=internal_jac, hess=internal_hess, design_info=design_info
+            )
+        elif method == "strata_robust":
+            int_cov = cov_strata_robust(
+                jac=internal_jac, hess=internal_hess, design_info=design_info
+            )
+        else:
+            raise ValueError(f"Invalid method: {method}")
+
+        np.random.seed(seed)
+
+        free_cov = transform_covariance(
+            flat_params=flat_params,
+            internal_cov=int_cov,
             converter=converter,
             n_samples=n_samples,
             bounds_handling=bounds_handling,
         )
-        summary = calculate_inference_quantities(
-            estimates=estimates,
-            flat_estimates=flat_estimates,
-            free_cov=cov,
-            ci_level=ci_level,
-        )
-
-        covs[f"cov_{case}"] = cov
-        summaries[f"summary_{case}"] = summary
-
-    # ==================================================================================
-    # Calculate external jac and hess (if no transforming constraints)
-    # ==================================================================================
-
-    if not converter.has_transforming_constraints:
-        ext_jac = int_jac
-        ext_hess = int_hess
-    else:
-        ext_jac = "No external Jacobian defined due to constraints."
-        ext_hess = "No external Hessian defined due to constraints."
 
-    # ==================================================================================
-    # Construct output
-    # ==================================================================================
+        return free_cov
+
+    @property
+    def jacobian(self):
+        if self._jacobian is None:
+            raise NotAvailableError(
+                f"No jacobian is available because {self._no_jacobian_reason}."
+            )
+
+        return self._jacobian
+
+    @property
+    def hessian(self):
+        if self._hessian is None:
+            raise NotAvailableError(
+                f"No hessian is available because {self._no_hessian_reason}."
+            )
+
+        return self._hessian
+
+    @property
+    def _se(self):
+        return self.se()
+
+    @property
+    def _cov(self):
+        return self.cov()
+
+    @property
+    def _summary(self):
+        return self.summary()
+
+    @property
+    def _ci(self):
+        return self.ci()
+
+    @property
+    def _p_values(self):
+        return self.p_values()
+
+    def se(
+        self,
+        method="jacobian",
+        n_samples=10_000,
+        bounds_handling="clip",
+        seed=None,
+    ):
+        """Calculate standard errors.
+
+        Args:
+            method (str): One of "jacobian", "hessian", "robust", "cluster_robust",
+                "strata_robust". Default "jacobian". "cluster_robust" is only available
+                if design_info containts a columns called "psu" that identifies the
+                primary sampling unit. "strata_robust" is only available if the columns
+                "strata", "fpc" and "psu" are in design_info.
+            n_samples (int): Number of samples used to transform the covariance matrix
+                of the internal parameter vector into the covariance matrix of the
+                external parameters. For background information about internal and
+                external params see :ref:`implementation_of_constraints`. This is only
+                used if you are using constraints.
+            bounds_handling (str): One of "clip", "raise", "ignore". Determines how
+                bounds are handled. If "clip", confidence intervals are clipped at the
+                bounds. Standard errors are only adjusted if a sampling step is
+                necessary due to additional constraints. If "raise" and any lower or
+                upper bound is binding, we raise an Error. If "ignore", boundary
+                problems are simply ignored.
+            seed (int): Seed for the random number generator. Only used if there are
+                transforming constraints.
+
+        Returns:
+            Any: A pytree with the same structure as params containing standard errors
+            for the parameter estimates.
+
+        """
+        free_cov = self._get_free_cov(
+            method=method,
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+            seed=seed,
+        )
 
-    out = {
-        **summaries,
-        **covs,
-        "jacobian": ext_jac,
-        "hessian": ext_hess,
-    }
+        helper = np.full(len(self._flat_params.values), np.nan)
+        helper[self._flat_params.free_mask] = np.sqrt(np.diagonal(free_cov))
+
+        out = self._converter.params_from_internal(helper)
+
+        return out
+
+    def cov(
+        self,
+        method="jacobian",
+        n_samples=10_000,
+        bounds_handling="clip",
+        return_type="pytree",
+        seed=None,
+    ):
+        """Calculate the variance-covariance matrix of the estimated parameters.
+
+        Args:
+            method (str): One of "jacobian", "hessian", "robust", "cluster_robust",
+                "strata_robust". Default "jacobian". "cluster_robust" is only available
+                if design_info containts a columns called "psu" that identifies the
+                primary sampling unit. "strata_robust" is only available if the columns
+                "strata", "fpc" and "psu" are in design_info.
+            n_samples (int): Number of samples used to transform the covariance matrix
+                of the internal parameter vector into the covariance matrix of the
+                external parameters. For background information about internal and
+                external params see :ref:`implementation_of_constraints`. This is only
+                used if you are using constraints.
+            bounds_handling (str): One of "clip", "raise", "ignore". Determines how
+                bounds are handled. If "clip", confidence intervals are clipped at the
+                bounds. Standard errors are only adjusted if a sampling step is
+                necessary due to additional constraints. If "raise" and any lower or
+                upper bound is binding, we raise an Error. If "ignore", boundary
+                problems are simply ignored.
+            return_type (str): One of "pytree", "array" or "dataframe". Default pytree.
+                If "array", a 2d numpy array with the covariance is returned. If
+                "dataframe", a pandas DataFrame with parameter names in the
+                index and columns are returned.
+            seed (int): Seed for the random number generator. Only used if there are
+                transforming constraints.
+
+        Returns:
+            Any: The covariance matrix of the estimated parameters as block-pytree or
+                numpy array.
+
+        """
+        free_cov = self._get_free_cov(
+            method=method,
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+            seed=seed,
+        )
+        if return_type == "array":
+            out = free_cov
+        elif return_type == "dataframe":
+            free_index = np.array(self._flat_params.names)[self._flat_params.free_mask]
+            out = pd.DataFrame(data=free_cov, columns=free_index, index=free_index)
+        elif return_type == "pytree":
+            if len(free_cov) != len(self._flat_params.values):
+                raise NotAvailableError(
+                    "Covariance matrices in block-pytree format are only available if "
+                    "there are no constraints that reduce the number of free "
+                    "parameters."
+                )
+            out = matrix_to_block_tree(free_cov, self.params, self.params)
+        return out
+
+    def summary(
+        self,
+        method="jacobian",
+        n_samples=10_000,
+        ci_level=0.95,
+        bounds_handling="clip",
+        seed=None,
+    ):
+        """Create a summary of estimation results.
+
+        Args:
+            method (str): One of "jacobian", "hessian", "robust", "cluster_robust",
+                "strata_robust". Default "jacobian". "cluster_robust" is only available
+                if design_info containts a columns called "psu" that identifies the
+                primary sampling unit. "strata_robust" is only available if the columns
+                "strata", "fpc" and "psu" are in design_info.
+            ci_level (float): Confidence level for the calculation of confidence
+                intervals. The default is 0.95.
+            n_samples (int): Number of samples used to transform the covariance matrix
+                of the internal parameter vector into the covariance matrix of the
+                external parameters. For background information about internal and
+                external params see :ref:`implementation_of_constraints`. This is only
+                used if you are using constraints.
+            bounds_handling (str): One of "clip", "raise", "ignore". Determines how
+                bounds are handled. If "clip", confidence intervals are clipped at the
+                bounds. Standard errors are only adjusted if a sampling step is
+                necessary due to additional constraints. If "raise" and any lower or
+                upper bound is binding, we raise an Error. If "ignore", boundary
+                problems are simply ignored.
+            seed (int): Seed for the random number generator. Only used if there are
+                transforming constraints.
+
+
+        Returns:
+            Any: The estimation summary as pytree of DataFrames.
+
+        """
+        free_cov = self._get_free_cov(
+            method=method,
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+            seed=seed,
+        )
 
-    if not is_optimized:
-        out["optimize_res"] = opt_res
+        summary = calculate_inference_quantities(
+            estimates=self.params,
+            flat_estimates=self._flat_params,
+            free_cov=free_cov,
+            ci_level=ci_level,
+        )
+        return summary
+
+    def ci(
+        self,
+        method="jacobian",
+        n_samples=10_000,
+        ci_level=0.95,
+        bounds_handling="clip",
+        seed=None,
+    ):
+        """Calculate confidence intervals.
+
+        Args:
+            method (str): One of "jacobian", "hessian", "robust", "cluster_robust",
+                "strata_robust". Default "jacobian". "cluster_robust" is only available
+                if design_info containts a columns called "psu" that identifies the
+                primary sampling unit. "strata_robust" is only available if the columns
+                "strata", "fpc" and "psu" are in design_info.
+            ci_level (float): Confidence level for the calculation of confidence
+                intervals. The default is 0.95.
+            n_samples (int): Number of samples used to transform the covariance matrix
+                of the internal parameter vector into the covariance matrix of the
+                external parameters. For background information about internal and
+                external params see :ref:`implementation_of_constraints`. This is only
+                used if you are using constraints.
+            bounds_handling (str): One of "clip", "raise", "ignore". Determines how
+                bounds are handled. If "clip", confidence intervals are clipped at the
+                bounds. Standard errors are only adjusted if a sampling step is
+                necessary due to additional constraints. If "raise" and any lower or
+                upper bound is binding, we raise an Error. If "ignore", boundary
+                problems are simply ignored.
+            seed (int): Seed for the random number generator. Only used if there are
+                transforming constraints.
+
+        Returns:
+            Any: Pytree with the same structure as params containing lower bounds of
+                confidence intervals.
+            Any: Pytree with the same structure as params containing upper bounds of
+                confidence intervals.
+
+        """
+        free_cov = self._get_free_cov(
+            method=method,
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+            seed=seed,
+        )
 
-    if jac_case == "numerical":
-        out["jacobian_numdiff_info"] = jac_numdiff_info
+        free_values = self._flat_params.values[self._flat_params.free_mask]
+        free_se = np.sqrt(np.diagonal(free_cov))
+
+        free_lower, free_upper = calculate_ci(free_values, free_se, ci_level)
+
+        helper = np.full(len(self._flat_params.values), np.nan)
+        helper[self._flat_params.free_mask] = free_lower
+        lower = self._converter.params_from_internal(helper)
+
+        helper = np.full(len(self._flat_params.values), np.nan)
+        helper[self._flat_params.free_mask] = free_upper
+        upper = self._converter.params_from_internal(helper)
+
+        return lower, upper
+
+    def p_values(
+        self,
+        method="jacobian",
+        n_samples=10_000,
+        bounds_handling="clip",
+        seed=None,
+    ):
+        """Calculate p_values.
+
+        Args:
+            method (str): One of "jacobian", "hessian", "robust", "cluster_robust",
+                "strata_robust". Default "jacobian". "cluster_robust" is only available
+                if design_info containts a columns called "psu" that identifies the
+                primary sampling unit. "strata_robust" is only available if the columns
+                "strata", "fpc" and "psu" are in design_info.
+            ci_level (float): Confidence level for the calculation of confidence
+                intervals. The default is 0.95.
+            n_samples (int): Number of samples used to transform the covariance matrix
+                of the internal parameter vector into the covariance matrix of the
+                external parameters. For background information about internal and
+                external params see :ref:`implementation_of_constraints`. This is only
+                used if you are using constraints.
+            bounds_handling (str): One of "clip", "raise", "ignore". Determines how
+                bounds are handled. If "clip", confidence intervals are clipped at the
+                bounds. Standard errors are only adjusted if a sampling step is
+                necessary due to additional constraints. If "raise" and any lower or
+                upper bound is binding, we raise an Error. If "ignore", boundary
+                problems are simply ignored.
+            seed (int): Seed for the random number generator. Only used if there are
+                transforming constraints.
+
+        Returns:
+            Any: Pytree with the same structure as params containing lower bounds of
+                confidence intervals.
+            Any: Pytree with the same structure as params containing upper bounds of
+                confidence intervals.
+
+        """
+        free_cov = self._get_free_cov(
+            method=method,
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+            seed=seed,
+        )
 
-    if hess_case == "numerical":
-        out["hessian_numdiff_info"] = hess_numdiff_info
+        free_values = self._flat_params.values[self._flat_params.free_mask]
+        free_se = np.sqrt(np.diagonal(free_cov))
 
-    return out
+        free_p_values = calculate_p_values(free_values, free_se)
 
+        helper = np.full(len(self._flat_params.values), np.nan)
+        helper[self._flat_params.free_mask] = free_p_values
+        out = self._converter.params_from_internal(helper)
 
-def _get_cov_cases(jac_case, hess_case, design_info):
-    if jac_case == "skip" and hess_case == "skip":
-        raise ValueError("Jacobian and Hessian cannot both be False.")
-    elif jac_case == "skip" and hess_case != "skip":
-        cases = ["hessian"]
-    elif hess_case == "skip" and jac_case != "skip":
-        cases = ["jacobian"]
-    else:
-        cases = ["jacobian", "hessian", "robust"]
-        if design_info is not None:
-            if "psu" in design_info:
-                cases.append("cluster_robust")
-            if {"strata", "psu", "fpc"}.issubset(design_info):
-                cases.append("strata_robust")
-
-    return cases
+        return out
diff --git a/src/estimagic/estimation/estimate_msm.py b/src/estimagic/estimation/estimate_msm.py
index c7fb33c41..79199a396 100644
--- a/src/estimagic/estimation/estimate_msm.py
+++ b/src/estimagic/estimation/estimate_msm.py
@@ -1,24 +1,46 @@
 """Do a method of simlated moments estimation."""
 import functools
 from collections.abc import Callable
+from dataclasses import dataclass
+from typing import Any
+from typing import Union
 
 import numpy as np
 import pandas as pd
 from estimagic.differentiation.derivatives import first_derivative
 from estimagic.estimation.msm_weighting import get_weighting_matrix
 from estimagic.exceptions import InvalidFunctionError
+from estimagic.exceptions import NotAvailableError
 from estimagic.inference.msm_covs import cov_optimal
 from estimagic.inference.msm_covs import cov_robust
+from estimagic.inference.shared import calculate_ci
 from estimagic.inference.shared import calculate_inference_quantities
+from estimagic.inference.shared import calculate_p_values
 from estimagic.inference.shared import check_is_optimized_and_derivative_case
 from estimagic.inference.shared import get_derivative_case
 from estimagic.inference.shared import transform_covariance
 from estimagic.optimization.optimize import minimize
+from estimagic.parameters.block_trees import block_tree_to_matrix
+from estimagic.parameters.block_trees import matrix_to_block_tree
+from estimagic.parameters.conversion import Converter
 from estimagic.parameters.conversion import get_converter
-from estimagic.parameters.parameter_bounds import get_bounds
-from estimagic.sensitivity.msm_sensitivity import calculate_sensitivity_measures
+from estimagic.parameters.tree_registry import get_registry
+from estimagic.sensitivity.msm_sensitivity import calculate_actual_sensitivity_to_noise
+from estimagic.sensitivity.msm_sensitivity import (
+    calculate_actual_sensitivity_to_removal,
+)
+from estimagic.sensitivity.msm_sensitivity import (
+    calculate_fundamental_sensitivity_to_noise,
+)
+from estimagic.sensitivity.msm_sensitivity import (
+    calculate_fundamental_sensitivity_to_removal,
+)
+from estimagic.sensitivity.msm_sensitivity import calculate_sensitivity_to_bias
+from estimagic.sensitivity.msm_sensitivity import calculate_sensitivity_to_weighting
 from estimagic.shared.check_option_dicts import check_numdiff_options
 from estimagic.shared.check_option_dicts import check_optimization_options
+from pybaum import leaf_names
+from pybaum import tree_just_flatten
 
 
 def estimate_msm(
@@ -38,9 +60,6 @@ def estimate_msm(
     numdiff_options=None,
     jacobian=None,
     jacobian_kwargs=None,
-    ci_level=0.95,
-    n_samples=10_000,
-    bounds_handling="raise",
 ):
     """Do a method of simulated moments or indirect inference estimation.
 
@@ -50,32 +69,31 @@ def estimate_msm(
 
     While we have good defaults, you can still configure each aspect of each steps
     vial the optional arguments of this functions. If you find it easier to do the
-    "difficult" steps (mainly minimization and calculating numerical derivatives
-    of a potentially noisy function) separately, you can do so and just provide those
-    results as ``params`` and ``jacobian``.
-
-    The docstring is aspirational and not all options are supported yet.
+    minimization separately, you can do so and just provide the optimal parameters as
+    ``params`` and set ``optimize_options=False``.
 
     Args:
         simulate_moments (callable): Function that takes params and potentially other
-            keyword arguments and returns simulated moments as a pandas Series.
-            Alternatively, the function can return a dict with any number of entries as
-            long as one of those entries is "simulated_moments".
-        empirical_moments (pandas.Series): A pandas series with the empirical
-            equivalents of the simulated moments.
-        moments_cov (pandas.DataFrame): A quadratic pandas DataFrame with the covariance
+            keyword arguments and returns a pytree with simulated moments. If the
+            function returns a dict containing the key ``"simulated_moments"`` we only
+            use the value corresponding to that key. Other entries are stored in the
+            log database if you use logging.
+
+        empirical_moments (pandas.Series): A pytree with the same structure as the
+            result of ``simulate_moments``.
+        moments_cov (pandas.DataFrame): A block-pytree containing the covariance
             matrix of the empirical moments. This is typically calculated with
-            our ``get_moments_cov`` function. The index and columns need to be the same
-            as the index of ``empirical_moments``.
+            our ``get_moments_cov`` function.
         params (pytree): A pytree containing the estimated or start parameters of the
-            likelihood model. If the supplied parameters are estimated parameters, set
+            model. If the supplied parameters are estimated parameters, set
             optimize_options to False. Pytrees can be a numpy array, a pandas Series, a
             DataFrame with "value" column, a float and any kind of (nested) dictionary
             or list containing these elements. See :ref:`params` for examples.
         optimize_options (dict, str or False): Keyword arguments that govern the
             numerical optimization. Valid entries are all arguments of
-            :func:`~estimagic.optimization.optimize.minimize` except for criterion.  If
-            you pass False as optimize_options you signal that ``params`` are already
+            :func:`~estimagic.optimization.optimize.minimize` except for those that can
+            be passed explicitly to ``estimate_msm``.  If you pass False as
+            ``optimize_options`` you signal that ``params`` are already
             the optimal parameters and no numerical optimization is needed. If you pass
             a str as optimize_options it is used as the ``algorithm`` option.
         lower_bounds (pytree): A pytree with the same structure as params with lower
@@ -85,12 +103,9 @@ def estimate_msm(
             no upper bound.
         simulate_moments_kwargs (dict): Additional keyword arguments for
             ``simulate_moments``.
-        weights (str or pandas.DataFrame): Either a DataFrame with a positive
-            semi-definite weighting matrix or a string that specifies one of the
-            pre-implemented weighting matrices: "diagonal" (default), "identity" or
-            "optimal". Note that "optimal" refers to the asymptotically optimal
-            weighting matrix and is often not a good choice due to large finite sample
-            bias.
+        weights (str): One of "diagonal" (default), "identity" or "optimal".
+            Note that "optimal" refers to the asymptotically optimal weighting matrix
+            and is often not a good choice due to large finite sample bias.
         constraints (list, dict): List with constraint dictionaries or single dict.
             See .. _link: ../../docs/source/how_to_guides/how_to_use_constraints.ipynb
         logging (pathlib.Path, str or False): Path to sqlite3 file (which typically has
@@ -113,24 +128,10 @@ def estimate_msm(
             :ref:`first_derivative` for details. Note that by default we increase the
             step_size by a factor of 2 compared to the rule of thumb for optimal
             step sizes. This is because many msm criterion functions are slightly noisy.
-        jacobian (callable or pandas.DataFrame): A function that take ``params`` and
-            potentially other keyword arguments and returns the Jacobian of
-            simulate_moments with respect to the params. Alternatively, you can pass
-            a pandas.DataFrame with the Jacobian at the optimal parameters. This is
-            only possible if you pass ``optimize_options=False``.
-        jacobian_kwargs (dict): Additional keyword arguments for the Jacobian function.
-        ci_level (float): Confidence level for the calculation of confidence intervals.
-            The default is 0.95
-        n_samples (int): Number of samples used to transform the covariance matrix of
-            the internal parameter vector into the covariance matrix of the external
-            parameters. For background information about internal and external params
-            see :ref:`implementation_of_constraints`. This is only used if you have
-            constraints in the ``optimize_options``
-        bounds_handling (str): One of "clip", "raise", "ignore". Determines how bounds
-            are handled. If "clip", confidence intervals are clipped at the bounds.
-            Standard errors are only adjusted if a sampling step is necessary due to
-            additional constraints. If "raise" and any lower or upper bound is binding,
-            we raise an error. If "ignore", boundary problems are simply ignored.
+        jacobian (callable): A function that take ``params`` and
+            potentially other keyword arguments and returns the jacobian of
+            simulate_moments with respect to the params.
+        jacobian_kwargs (dict): Additional keyword arguments for the jacobian function.
 
         Returns:
             dict: The estimated parameters, standard errors and sensitivity measures
@@ -141,6 +142,9 @@ def estimate_msm(
     # Check and process inputs
     # ==================================================================================
 
+    if weights not in ["diagonal", "optimal"]:
+        raise NotImplementedError("Custom weighting matrices are not yet implemented.")
+
     is_optimized = optimize_options is False
 
     if not is_optimized:
@@ -155,8 +159,6 @@ def estimate_msm(
 
     jac_case = get_derivative_case(jacobian)
 
-    cov_case = _get_cov_case(weights)
-
     check_is_optimized_and_derivative_case(is_optimized, jac_case)
 
     check_numdiff_options(numdiff_options, "estimate_msm")
@@ -165,12 +167,24 @@ def estimate_msm(
     if "scaling_factor" not in numdiff_options:
         numdiff_options["scaling_factor"] = 2
 
-    if not isinstance(weights, (np.ndarray, pd.DataFrame)):
-        weights = get_weighting_matrix(moments_cov, weights)
+    weights, internal_weights = get_weighting_matrix(
+        moments_cov=moments_cov,
+        method=weights,
+        empirical_moments=empirical_moments,
+        return_type="pytree_and_array",
+    )
+
+    internal_moments_cov = block_tree_to_matrix(
+        moments_cov,
+        outer_tree=empirical_moments,
+        inner_tree=empirical_moments,
+    )
 
     constraints = [] if constraints is None else constraints
     jacobian_kwargs = {} if jacobian_kwargs is None else jacobian_kwargs
-    simulate_moments_kwargs = {} if simulate_moments_kwargs is None else {}
+    simulate_moments_kwargs = (
+        {} if simulate_moments_kwargs is None else simulate_moments_kwargs
+    )
 
     # ==================================================================================
     # Calculate estimates via minimization (if necessary)
@@ -178,13 +192,16 @@ def estimate_msm(
 
     if is_optimized:
         estimates = params
+        opt_res = None
     else:
         funcs = get_msm_optimization_functions(
             simulate_moments=simulate_moments,
             empirical_moments=empirical_moments,
             weights=weights,
             simulate_moments_kwargs=simulate_moments_kwargs,
-            jacobian=jacobian,
+            # Always pass None because we do not support closed form jacobians during
+            # optimization yet. Otherwise we would get a NotImplementedError
+            jacobian=None,
             jacobian_kwargs=jacobian_kwargs,
         )
 
@@ -229,12 +246,6 @@ def estimate_msm(
     # get converter for params and function outputs
     # ==================================================================================
 
-    lower_bounds, upper_bounds = get_bounds(
-        params,
-        lower_bounds=lower_bounds,
-        upper_bounds=upper_bounds,
-    )
-
     def helper(params):
         raw = simulate_moments(params, **simulate_moments_kwargs)
         if isinstance(raw, dict) and "simulated_moments" in raw:
@@ -267,8 +278,7 @@ def helper(params):
 
     if jac_case == "closed-form":
         x = converter.params_to_internal(estimates)
-        int_jac = converter.derivative_to_internal(jacobian, x)
-    # switch to "numerical" even if jac_case == "skip" because jac is required for msm.
+        int_jac = converter.derivative_to_internal(jacobian_eval, x)
     else:
 
         def func(x):
@@ -277,88 +287,50 @@ def func(x):
             out = converter.func_to_internal(sim_mom_eval)
             return out
 
-        jac_res = first_derivative(
+        int_jac = first_derivative(
             func=func,
             params=flat_estimates.values,
             lower_bounds=flat_estimates.lower_bounds,
             upper_bounds=flat_estimates.upper_bounds,
             **numdiff_options,
-        )
-
-        int_jac = jac_res["derivative"]
-        numdiff_info = {k: v for k, v in jac_res.items() if k != "derivative"}
-
-    # ==================================================================================
-    # Calculate internal cov
-    # ==================================================================================
-
-    if cov_case == "optimal":
-        cov = cov_optimal(int_jac, weights)
-    else:
-        cov = cov_robust(int_jac, weights, moments_cov)
-
-    # ==================================================================================
-    # Calculate external cov and summary
-    # ==================================================================================
+        )["derivative"]
 
-    cov = transform_covariance(
-        flat_params=flat_estimates,
-        internal_cov=cov,
-        converter=converter,
-        n_samples=n_samples,
-        bounds_handling=bounds_handling,
-    )
-
-    summary = calculate_inference_quantities(
-        estimates=estimates,
-        flat_estimates=flat_estimates,
-        free_cov=cov,
-        ci_level=ci_level,
-    )
     # ==================================================================================
-    # Calculate external jac (if no transforming constraints)
+    # Calculate external jac (if no constraints and not closed form )
     # ==================================================================================
 
-    if not converter.has_transforming_constraints:
-        if isinstance(moments_cov, pd.DataFrame):
-            moments_names = moments_cov.index
-        else:
-            moments_names = None
-        ext_jac = pd.DataFrame(int_jac, columns=cov.index, index=moments_names)
-    else:
-        ext_jac = "No external jacobian defined due to constraints."
-
-    # ==================================================================================
-    # Calculate sensitivity measures (if no transforming constraints)
-    # ==================================================================================
+    if constraints in [None, []] and jacobian_eval is None and int_jac is not None:
+        jacobian_eval = matrix_to_block_tree(
+            int_jac,
+            outer_tree=empirical_moments,
+            inner_tree=estimates,
+        )
 
-    if not converter.has_transforming_constraints:
-        sensitivities = calculate_sensitivity_measures(
-            jac=int_jac,
-            weights=weights,
-            moments_cov=moments_cov,
-            params_cov=cov,
+    if jacobian_eval is None:
+        _no_jac_reason = (
+            "no closed form jacobian was provided and there are constraints"
         )
     else:
-        sensitivities = "No sensitivity measures can be calculated due to constraints."
+        _no_jac_reason = None
 
     # ==================================================================================
-    # Construct output
+    # Create MomentsResult
     # ==================================================================================
-    out = {
-        "summary": summary,
-        "cov": cov,
-        "sensitivity": sensitivities,
-        "jacobian": ext_jac,
-    }
 
-    if not is_optimized:
-        out["optimize_res"] = opt_res
-
-    if jac_case == "numerical":
-        out["jacobian_numdiff_info"] = numdiff_info
-
-    return out
+    res = MomentsResult(
+        params=estimates,
+        weights=weights,
+        _flat_params=flat_estimates,
+        _converter=converter,
+        _internal_weights=internal_weights,
+        _internal_moments_cov=internal_moments_cov,
+        _internal_jacobian=int_jac,
+        _jacobian=jacobian_eval,
+        _no_jacobian_reason=_no_jac_reason,
+        _empirical_moments=empirical_moments,
+        _has_constraints=constraints not in [None, []],
+    )
+    return res
 
 
 def get_msm_optimization_functions(
@@ -379,8 +351,7 @@ def get_msm_optimization_functions(
             as long as one of those entries is "simulated_moments".
         empirical_moments (pandas.Series): A pandas series with the empirical
             equivalents of the simulated moments.
-        weights (pandas.DataFrame): DataFrame with a positive
-            semi-definite weighting matrix.
+        weights (pytree): The weighting matrix as block pytree.
         simulate_moments_kwargs (dict): Additional keyword arguments for
             ``simulate_moments``.
         jacobian (callable or pandas.DataFrame): A function that take ``params`` and
@@ -397,14 +368,26 @@ def get_msm_optimization_functions(
             as only argument.
 
     """
+    flat_weights = block_tree_to_matrix(
+        weights,
+        outer_tree=empirical_moments,
+        inner_tree=empirical_moments,
+    )
+
+    chol_weights = np.linalg.cholesky(flat_weights)
+
+    registry = get_registry(extended=True)
+    flat_emp_mom = tree_just_flatten(empirical_moments, registry=registry)
+
     _simulate_moments = _partial_kwargs(simulate_moments, simulate_moments_kwargs)
     _jacobian = _partial_kwargs(jacobian, jacobian_kwargs)
 
     criterion = functools.partial(
         _msm_criterion,
         simulate_moments=_simulate_moments,
-        empirical_moments=empirical_moments,
-        weights=weights,
+        flat_empirical_moments=flat_emp_mom,
+        chol_weights=chol_weights,
+        registry=registry,
     )
 
     out = {"criterion": criterion}
@@ -417,13 +400,26 @@ def get_msm_optimization_functions(
     return out
 
 
-def _msm_criterion(params, simulate_moments, empirical_moments, weights):
+def _msm_criterion(
+    params, simulate_moments, flat_empirical_moments, chol_weights, registry
+):
     """Calculate msm criterion given parameters and building blocks."""
     simulated = simulate_moments(params)
-    if isinstance(simulated, dict):
+    if isinstance(simulated, dict) and "simulated_moments" in simulated:
         simulated = simulated["simulated_moments"]
-    deviations = simulated - empirical_moments
-    out = deviations @ weights @ deviations
+    if isinstance(simulated, np.ndarray) and simulated.ndim == 1:
+        simulated_flat = simulated
+    else:
+        simulated_flat = np.array(tree_just_flatten(simulated, registry=registry))
+
+    deviations = simulated_flat - flat_empirical_moments
+    root_contribs = deviations @ chol_weights
+
+    value = root_contribs @ root_contribs
+    out = {
+        "value": value,
+        "root_contributions": root_contribs,
+    }
     return out
 
 
@@ -445,5 +441,492 @@ def _partial_kwargs(func, kwargs):
     return out
 
 
-def _get_cov_case(weights):
-    return weights == "optimal"
+@dataclass
+class MomentsResult:
+    params: Any
+    weights: Any
+    _flat_params: Any
+    _converter: Converter
+    _internal_moments_cov: np.ndarray
+    _internal_weights: np.ndarray
+    _internal_jacobian: np.ndarray
+    _empirical_moments: Any
+    _has_constraints: bool
+    _jacobian: Any = None
+    _no_jacobian_reason: Union[str, None] = None
+
+    @property
+    def jacobian(self):
+        return self._jacobian
+
+    @property
+    def _se(self):
+        return self.se()
+
+    @property
+    def _cov(self):
+        return self.cov()
+
+    @property
+    def _summary(self):
+        return self.summary()
+
+    @property
+    def _ci(self):
+        return self.ci()
+
+    def _get_free_cov(self, method, n_samples, bounds_handling, seed):
+
+        int_jac = self._internal_jacobian
+        weights = self._internal_weights
+        converter = self._converter
+        flat_params = self._flat_params
+        moments_cov = self._internal_moments_cov
+
+        if method == "optimal":
+            int_cov = cov_optimal(int_jac, weights)
+        else:
+            int_cov = cov_robust(int_jac, weights, moments_cov)
+
+        np.random.seed(seed)
+
+        free_cov = transform_covariance(
+            flat_params=flat_params,
+            internal_cov=int_cov,
+            converter=converter,
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+        )
+
+        return free_cov
+
+    @property
+    def _p_values(self):
+        return self.p_values()
+
+    def se(
+        self,
+        method="robust",
+        n_samples=10_000,
+        bounds_handling="clip",
+        seed=None,
+    ):
+        """Calculate standard errors.
+
+        Args:
+            method (str): One of "robust", "optimal". Despite the name, "optimal" is
+                not recommended in finite samples and "optimal" standard errors are
+                only valid if the asymptotically optimal weighting matrix has been
+                used. It is only supported because it is needed to calculate
+                sensitivity measures.
+            n_samples (int): Number of samples used to transform the covariance matrix
+                of the internal parameter vector into the covariance matrix of the
+                external parameters. For background information about internal and
+                external params see :ref:`implementation_of_constraints`. This is only
+                used if you are using constraints.
+            bounds_handling (str): One of "clip", "raise", "ignore". Determines how
+                bounds are handled. If "clip", confidence intervals are clipped at the
+                bounds. Standard errors are only adjusted if a sampling step is
+                necessary due to additional constraints. If "raise" and any lower or
+                upper bound is binding, we raise an Error. If "ignore", boundary
+                problems are simply ignored.
+            seed (int): Seed for the random number generator. Only used if there are
+                transforming constraints.
+
+
+        Returns:
+            Any: A pytree with the same structure as params containing standard errors
+            for the parameter estimates.
+
+        """
+        free_cov = self._get_free_cov(
+            method=method,
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+            seed=seed,
+        )
+
+        helper = np.full(len(self._flat_params.values), np.nan)
+        helper[self._flat_params.free_mask] = np.sqrt(np.diagonal(free_cov))
+
+        out = self._converter.params_from_internal(helper)
+
+        return out
+
+    def cov(
+        self,
+        method="robust",
+        n_samples=10_000,
+        bounds_handling="clip",
+        return_type="pytree",
+        seed=None,
+    ):
+        """Calculate the variance-covariance matrix of the estimated parameters.
+
+        Args:
+            method (str): One of "robust", "optimal". Despite the name, "optimal" is
+                not recommended in finite samples and "optimal" standard errors are
+                only valid if the asymptotically optimal weighting matrix has been
+                used. It is only supported because it is needed to calculate
+                sensitivity measures.
+            n_samples (int): Number of samples used to transform the covariance matrix
+                of the internal parameter vector into the covariance matrix of the
+                external parameters. For background information about internal and
+                external params see :ref:`implementation_of_constraints`. This is only
+                used if you are using constraints.
+            bounds_handling (str): One of "clip", "raise", "ignore". Determines how
+                bounds are handled. If "clip", confidence intervals are clipped at the
+                bounds. Standard errors are only adjusted if a sampling step is
+                necessary due to additional constraints. If "raise" and any lower or
+                upper bound is binding, we raise an Error. If "ignore", boundary
+                problems are simply ignored.
+            return_type (str): One of "pytree", "array" or "dataframe". Default pytree.
+                If "array", a 2d numpy array with the covariance is returned. If
+                "dataframe", a pandas DataFrame with parameter names in the
+                index and columns are returned.
+            seed (int): Seed for the random number generator. Only used if there are
+                transforming constraints.
+
+
+        Returns:
+            Any: The covariance matrix of the estimated parameters as block-pytree or
+                numpy array.
+
+        """
+        free_cov = self._get_free_cov(
+            method=method,
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+            seed=seed,
+        )
+        if return_type == "array":
+            out = free_cov
+        elif return_type == "dataframe":
+            free_index = np.array(self._flat_params.names)[self._flat_params.free_mask]
+            out = pd.DataFrame(data=free_cov, columns=free_index, index=free_index)
+        elif return_type == "pytree":
+            if len(free_cov) != len(self._flat_params.values):
+                raise NotAvailableError(
+                    "Covariance matrices in block-pytree format are only available if "
+                    "there are no constraints that reduce the number of free "
+                    "parameters."
+                )
+            out = matrix_to_block_tree(free_cov, self.params, self.params)
+        return out
+
+    def summary(
+        self,
+        method="robust",
+        n_samples=10_000,
+        ci_level=0.95,
+        bounds_handling="clip",
+        seed=None,
+    ):
+        """Create a summary of estimation results.
+
+        Args:
+            method (str): One of "robust", "optimal". Despite the name, "optimal" is
+                not recommended in finite samples and "optimal" standard errors are
+                only valid if the asymptotically optimal weighting matrix has been
+                used. It is only supported because it is needed to calculate
+                sensitivity measures.
+            ci_level (float): Confidence level for the calculation of confidence
+                intervals. The default is 0.95.
+            n_samples (int): Number of samples used to transform the covariance matrix
+                of the internal parameter vector into the covariance matrix of the
+                external parameters. For background information about internal and
+                external params see :ref:`implementation_of_constraints`. This is only
+                used if you are using constraints.
+            bounds_handling (str): One of "clip", "raise", "ignore". Determines how
+                bounds are handled. If "clip", confidence intervals are clipped at the
+                bounds. Standard errors are only adjusted if a sampling step is
+                necessary due to additional constraints. If "raise" and any lower or
+                upper bound is binding, we raise an Error. If "ignore", boundary
+                problems are simply ignored.
+            seed (int): Seed for the random number generator. Only used if there are
+                transforming constraints.
+
+        Returns:
+            Any: The estimation summary as pytree of DataFrames.
+
+        """
+        free_cov = self._get_free_cov(
+            method=method,
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+            seed=seed,
+        )
+
+        summary = calculate_inference_quantities(
+            estimates=self.params,
+            flat_estimates=self._flat_params,
+            free_cov=free_cov,
+            ci_level=ci_level,
+        )
+        return summary
+
+    def ci(
+        self,
+        method="robust",
+        n_samples=10_000,
+        ci_level=0.95,
+        bounds_handling="clip",
+        seed=None,
+    ):
+        """Calculate confidence intervals.
+
+        Args:
+            method (str): One of "robust", "optimal". Despite the name, "optimal" is
+                not recommended in finite samples and "optimal" standard errors are
+                only valid if the asymptotically optimal weighting matrix has been
+                used. It is only supported because it is needed to calculate
+                sensitivity measures.
+            ci_level (float): Confidence level for the calculation of confidence
+                intervals. The default is 0.95.
+            n_samples (int): Number of samples used to transform the covariance matrix
+                of the internal parameter vector into the covariance matrix of the
+                external parameters. For background information about internal and
+                external params see :ref:`implementation_of_constraints`. This is only
+                used if you are using constraints.
+            bounds_handling (str): One of "clip", "raise", "ignore". Determines how
+                bounds are handled. If "clip", confidence intervals are clipped at the
+                bounds. Standard errors are only adjusted if a sampling step is
+                necessary due to additional constraints. If "raise" and any lower or
+                upper bound is binding, we raise an Error. If "ignore", boundary
+                problems are simply ignored.
+            seed (int): Seed for the random number generator. Only used if there are
+                transforming constraints.
+
+
+        Returns:
+            Any: Pytree with the same structure as params containing lower bounds of
+                confidence intervals.
+            Any: Pytree with the same structure as params containing upper bounds of
+                confidence intervals.
+
+        """
+        free_cov = self._get_free_cov(
+            method=method,
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+            seed=seed,
+        )
+
+        free_values = self._flat_params.values[self._flat_params.free_mask]
+        free_se = np.sqrt(np.diagonal(free_cov))
+
+        free_lower, free_upper = calculate_ci(free_values, free_se, ci_level)
+
+        helper = np.full(len(self._flat_params.values), np.nan)
+        helper[self._flat_params.free_mask] = free_lower
+        lower = self._converter.params_from_internal(helper)
+
+        helper = np.full(len(self._flat_params.values), np.nan)
+        helper[self._flat_params.free_mask] = free_upper
+        upper = self._converter.params_from_internal(helper)
+
+        return lower, upper
+
+    def p_values(
+        self,
+        method="robust",
+        n_samples=10_000,
+        bounds_handling="clip",
+        seed=None,
+    ):
+        """Calculate confidence intervals.
+
+        Args:
+            method (str): One of "robust", "optimal". Despite the name, "optimal" is
+                not recommended in finite samples and "optimal" standard errors are
+                only valid if the asymptotically optimal weighting matrix has been
+                used. It is only supported because it is needed to calculate
+                sensitivity measures.
+            n_samples (int): Number of samples used to transform the covariance matrix
+                of the internal parameter vector into the covariance matrix of the
+                external parameters. For background information about internal and
+                external params see :ref:`implementation_of_constraints`. This is only
+                used if you are using constraints.
+            bounds_handling (str): One of "clip", "raise", "ignore". Determines how
+                bounds are handled. If "clip", confidence intervals are clipped at the
+                bounds. Standard errors are only adjusted if a sampling step is
+                necessary due to additional constraints. If "raise" and any lower or
+                upper bound is binding, we raise an Error. If "ignore", boundary
+                problems are simply ignored.
+            seed (int): Seed for the random number generator. Only used if there are
+                transforming constraints.
+
+        Returns:
+            Any: Pytree with the same structure as params containing lower bounds of
+                confidence intervals.
+            Any: Pytree with the same structure as params containing upper bounds of
+                confidence intervals.
+
+        """
+        free_cov = self._get_free_cov(
+            method=method,
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+            seed=seed,
+        )
+
+        free_values = self._flat_params.values[self._flat_params.free_mask]
+        free_se = np.sqrt(np.diagonal(free_cov))
+
+        free_p_values = calculate_p_values(free_values, free_se)
+
+        helper = np.full(len(self._flat_params.values), np.nan)
+        helper[self._flat_params.free_mask] = free_p_values
+        out = self._converter.params_from_internal(helper)
+
+        return out
+
+    def sensitivity(
+        self,
+        kind="bias",
+        n_samples=10_000,
+        bounds_handling="clip",
+        seed=None,
+        return_type="pytree",
+    ):
+        """Calculate sensitivity measures for moments estimates.
+
+        The sensitivity measures are based on the following papers:
+
+        Andrews, Gentzkow & Shapiro
+        (https://academic.oup.com/qje/article/132/4/1553/3861634)
+
+        Honore, Jorgensen & de Paula (https://papers.srn.com/abstract=3518640)
+
+        In the papers the different kinds of sensitivity measures are just called
+        m1, e2, e3, e4, e5 and e6. We try to give them more informative names, but
+        list the original names for references.
+
+        Args:
+            kind (str): The following kinds are supported:
+                - "bias": Origally m1. How strongly would the parameter estimates be
+                   biased if the kth moment was misspecified, i.e not zero in
+                   expectation?
+                - "noise_fundamental": Originally e2. How much precision would be lost
+                   if the kth moment was subject to a little additional noise if the
+                   optimal weighting matrix was used?
+                - "noise": Originally e3. How much precision would be lost if the kth
+                  moment was subjet to a little additional noise?
+                - "removal": Originally e4. How much precision would be lost if the kth
+                  moment was excluded from the estimation?
+                - "removal_fundamental": Originally e5. How much precision would be lost
+                  if the kth moment was excluded from the estimation if the
+                  asymptotically optimal weighting matrix was used.
+                - "weighting": Originally e6. How would the precision change if the
+                  weight of the kth moment is increased a little?
+            n_samples (int): Number of samples used to transform the covariance matrix
+                of the internal parameter vector into the covariance matrix of the
+                external parameters. For background information about internal and
+                external params see :ref:`implementation_of_constraints`. This is only
+                used if you are using constraints.
+            bounds_handling (str): One of "clip", "raise", "ignore". Determines how
+                bounds are handled. If "clip", confidence intervals are clipped at the
+                bounds. Standard errors are only adjusted if a sampling step is
+                necessary due to additional constraints. If "raise" and any lower or
+                upper bound is binding, we raise an Error. If "ignore", boundary
+                problems are simply ignored.
+            seed (int): Seed for the random number generator. Only used if there are
+                transforming constraints.
+            return_type (str): One of "array", "dataframe" or "pytree". Default pytree.
+                If your params or moments have a very nested format, return_type
+                "dataframe" might be the better choice.
+
+        Returns:
+            Any: The sensitivity measure as a pytree, numpy array or DataFrame.
+                In 2d formats, the sensitivity measures have one row per estimated
+                parameter and one column per moment.
+
+        """
+        if self._has_constraints:
+            raise NotImplementedError(
+                "Sensitivity measures with constraints are not yet implemented."
+            )
+        jac = self._internal_jacobian
+        weights = self._internal_weights
+        moments_cov = self._internal_moments_cov
+        params_cov = self._get_free_cov(
+            method="robust",
+            n_samples=n_samples,
+            bounds_handling=bounds_handling,
+            seed=seed,
+        )
+
+        weights_opt = get_weighting_matrix(
+            moments_cov=moments_cov,
+            method="optimal",
+            empirical_moments=self._empirical_moments,
+        )
+        params_cov_opt = cov_optimal(jac, weights_opt)
+
+        if kind == "bias":
+            raw = calculate_sensitivity_to_bias(jac=jac, weights=weights)
+        elif kind == "noise_fundamental":
+            raw = calculate_fundamental_sensitivity_to_noise(
+                jac=jac,
+                weights=weights_opt,
+                moments_cov=moments_cov,
+                params_cov_opt=params_cov_opt,
+            )
+        elif kind == "noise":
+            m1 = calculate_sensitivity_to_bias(jac=jac, weights=weights)
+            raw = calculate_actual_sensitivity_to_noise(
+                sensitivity_to_bias=m1,
+                weights=weights,
+                moments_cov=moments_cov,
+                params_cov=params_cov,
+            )
+        elif kind == "removal":
+            raw = calculate_actual_sensitivity_to_removal(
+                jac=jac,
+                weights=weights,
+                moments_cov=moments_cov,
+                params_cov=params_cov,
+            )
+        elif kind == "removal_fundamental":
+
+            raw = calculate_fundamental_sensitivity_to_removal(
+                jac=jac,
+                moments_cov=moments_cov,
+                params_cov_opt=params_cov_opt,
+            )
+
+        elif kind == "weighting":
+
+            raw = calculate_sensitivity_to_weighting(
+                jac=jac,
+                weights=weights,
+                moments_cov=moments_cov,
+                params_cov=params_cov,
+            )
+        else:
+            raise ValueError(f"Invalid kind: {kind}")
+
+        if return_type == "array":
+            out = raw
+        elif return_type == "pytree":
+            out = matrix_to_block_tree(
+                raw,
+                outer_tree=self.params,
+                inner_tree=self._empirical_moments,
+            )
+        elif return_type == "dataframe":
+            registry = get_registry(extended=True)
+            row_names = self._flat_params.names
+            col_names = leaf_names(self._empirical_moments, registry=registry)
+            out = pd.DataFrame(
+                data=raw,
+                index=row_names,
+                columns=col_names,
+            )
+        else:
+            msg = (
+                f"Invalid return type: {return_type}. Valid are 'pytree', 'array' "
+                "and 'dataframe'"
+            )
+            raise ValueError(msg)
+        return out
diff --git a/src/estimagic/estimation/msm_weighting.py b/src/estimagic/estimation/msm_weighting.py
index da31392e7..515088c36 100644
--- a/src/estimagic/estimation/msm_weighting.py
+++ b/src/estimagic/estimation/msm_weighting.py
@@ -1,7 +1,13 @@
+import functools
+
 import numpy as np
 import pandas as pd
 from estimagic.inference.bootstrap import bootstrap
+from estimagic.parameters.block_trees import block_tree_to_matrix
+from estimagic.parameters.block_trees import matrix_to_block_tree
+from estimagic.parameters.tree_registry import get_registry
 from estimagic.utilities import robust_inverse
+from pybaum import tree_just_flatten
 from scipy.linalg import block_diag
 
 
@@ -40,47 +46,86 @@ def get_moments_cov(
     if problematic:
         raise ValueError(f"Invalid bootstrap_kwargs: {problematic}")
 
-    cov = bootstrap(data=data, outcome=calculate_moments, outcome_kwargs=moment_kwargs)[
-        "cov"
-    ]
+    first_eval = calculate_moments(data, **moment_kwargs)
+
+    registry = get_registry(extended=True)
+
+    @functools.wraps(calculate_moments)
+    def func(data, **kwargs):
+        raw = calculate_moments(data, **kwargs)
+        out = pd.Series(
+            tree_just_flatten(raw, registry=registry)
+        )  # xxxx won't be necessary soon!
+        return out
+
+    cov_arr = bootstrap(data=data, outcome=func, outcome_kwargs=moment_kwargs)["cov"]
+
+    if isinstance(cov_arr, pd.DataFrame):
+        cov_arr = cov_arr.to_numpy()  # xxxx won't be necessary soon
+
+    cov = matrix_to_block_tree(cov_arr, first_eval, first_eval)
 
     return cov
 
 
-def get_weighting_matrix(moments_cov, method, clip_value=1e-6):
+def get_weighting_matrix(
+    moments_cov, method, empirical_moments, clip_value=1e-6, return_type="pytree"
+):
     """Calculate a weighting matrix from moments_cov.
 
     Args:
         moments_cov (pandas.DataFrame or numpy.ndarray): Square DataFrame or Array
             with the covariance matrix of the moment conditions for msm estimation.
         method (str): One of "optimal", "diagonal".
+        empirical_moments (pytree): Pytree containing empirical moments. Used to get
+            the tree structure
         clip_value (float): Bound at which diagonal elements of the moments_cov are
             clipped to avoid dividing by zero.
+        return_type (str): One of "pytree", "array" or "pytree_and_array"
 
     Returns:
         pandas.DataFrame or numpy.ndarray: Weighting matrix with the same shape as
             moments_cov.
 
     """
+    fast_path = isinstance(moments_cov, np.ndarray) and moments_cov.ndim == 2
+
+    if fast_path:
+        _internal_cov = moments_cov
+    else:
+        _internal_cov = block_tree_to_matrix(
+            moments_cov,
+            outer_tree=empirical_moments,
+            inner_tree=empirical_moments,
+        )
+
     if method == "optimal":
-        values = robust_inverse(moments_cov)
+        array_weights = robust_inverse(_internal_cov)
     elif method == "diagonal":
-        diagonal_values = 1 / np.clip(np.diagonal(moments_cov), clip_value, np.inf)
-        values = np.diag(diagonal_values)
+        diagonal_values = 1 / np.clip(np.diagonal(_internal_cov), clip_value, np.inf)
+        array_weights = np.diag(diagonal_values)
     else:
         raise ValueError(f"Invalid method: {method}")
 
-    if isinstance(moments_cov, np.ndarray):
-        weights = values
+    if return_type == "array" or (fast_path and "_and_" not in return_type):
+        out = array_weights
+    elif fast_path:
+        out = (array_weights, array_weights)
     else:
-        weights = pd.DataFrame(
-            values, columns=moments_cov.index, index=moments_cov.index
+        tree_weights = matrix_to_block_tree(
+            array_weights,
+            outer_tree=empirical_moments,
+            inner_tree=empirical_moments,
         )
+        if return_type == "pytree":
+            out = tree_weights
+        else:
+            out = (tree_weights, array_weights)
 
-    return weights
+    return out
 
 
-def assemble_block_diagonal_matrix(matrices):
+def _assemble_block_diagonal_matrix(matrices):
     """Build a block diagonal matrix out of matrices.
 
     Args:
diff --git a/src/estimagic/examples/logit.py b/src/estimagic/examples/logit.py
index 65c039d4a..f6c49eeb1 100644
--- a/src/estimagic/examples/logit.py
+++ b/src/estimagic/examples/logit.py
@@ -1,5 +1,6 @@
 """Likelihood functions and derivatives of a logit model."""
 import numpy as np
+import pandas as pd
 
 
 def logit_loglike_and_derivative(params, y, x):
@@ -19,8 +20,12 @@ def logit_loglike(params, y, x):
         loglike (np.array): 1d numpy array with likelihood contribution  per individual
 
     """
+    if isinstance(params, pd.DataFrame):
+        p = params["value"].to_numpy()
+    else:
+        p = params
     q = 2 * y - 1
-    contribs = np.log(1 / (1 + np.exp(-(q * np.dot(x, params["value"])))))
+    contribs = np.log(1 / (1 + np.exp(-(q * np.dot(x, p)))))
 
     out = {"value": contribs.sum(), "contributions": contribs}
 
@@ -41,7 +46,10 @@ def logit_derivative(params, y, x):
             The derivative of the loglikelihood for each observation evaluated
             at `params`.
     """
-    p = params["value"].to_numpy()
+    if isinstance(params, pd.DataFrame):
+        p = params["value"].to_numpy()
+    else:
+        p = params
     y = y.to_numpy()
     c = 1 / (1 + np.exp(-(np.dot(x, p))))
     jac = (y - c)[:, None] * x
@@ -64,5 +72,9 @@ def logit_hessian(params, y, x):
             logl-ikelihood function evaluated at `params`
 
     """
-    c = 1 / (1 + np.exp(-(np.dot(x, params["value"]))))
+    if isinstance(params, pd.DataFrame):
+        p = params["value"].to_numpy()
+    else:
+        p = params
+    c = 1 / (1 + np.exp(-(np.dot(x, p))))
     return -np.dot(c * (1 - c) * x.T, x)
diff --git a/src/estimagic/exceptions.py b/src/estimagic/exceptions.py
index e546b3bb8..a08a100f1 100644
--- a/src/estimagic/exceptions.py
+++ b/src/estimagic/exceptions.py
@@ -39,6 +39,10 @@ class NotInstalledError(EstimagicError):
     """Exception when optional dependencies are needed but not installed."""
 
 
+class NotAvailableError(EstimagicError):
+    """Exception when something is not available, e.g. because a calculation failed."""
+
+
 class StopOptimizationError(EstimagicError):
     def __init__(self, message, current_status):
         super().__init__(message)
diff --git a/src/estimagic/inference/bootstrap_outcomes.py b/src/estimagic/inference/bootstrap_outcomes.py
index 9c0efcc8a..04e4bd912 100644
--- a/src/estimagic/inference/bootstrap_outcomes.py
+++ b/src/estimagic/inference/bootstrap_outcomes.py
@@ -44,7 +44,7 @@ def get_bootstrap_outcomes(
     check_inputs(data=data, cluster_by=cluster_by)
 
     if outcome_kwargs is not None:
-        outcome = partial(outcome, *outcome_kwargs)
+        outcome = partial(outcome, **outcome_kwargs)
 
     indices = get_bootstrap_indices(
         data=data,
diff --git a/src/estimagic/inference/ml_covs.py b/src/estimagic/inference/ml_covs.py
index 3d1d3c18a..508af7cac 100644
--- a/src/estimagic/inference/ml_covs.py
+++ b/src/estimagic/inference/ml_covs.py
@@ -226,7 +226,7 @@ def _clustering(jac, design_info):
 
 
 def _stratification(jac, design_info):
-    """Variance estimatio for each strata stratum.
+    """Variance estimation for each stratum.
 
     The function takes the sum of the jacobian observations for each cluster
     within strata. The result is the meat of the sandwich estimator.
diff --git a/src/estimagic/inference/shared.py b/src/estimagic/inference/shared.py
index 4ead8f80a..3ecf6f55f 100644
--- a/src/estimagic/inference/shared.py
+++ b/src/estimagic/inference/shared.py
@@ -75,9 +75,7 @@ def transform_covariance(
     else:
         free_cov = internal_cov
 
-    free_index = np.array(flat_params.names)[flat_params.free_mask]
-    res = pd.DataFrame(data=free_cov, columns=free_index, index=free_index)
-    return res
+    return free_cov
 
 
 def calculate_inference_quantities(estimates, flat_estimates, free_cov, ci_level):
@@ -102,6 +100,9 @@ def calculate_inference_quantities(estimates, flat_estimates, free_cov, ci_level
             reproduced for convenience.
 
     """
+    if not isinstance(free_cov, pd.DataFrame):
+        free_index = np.array(flat_estimates.names)[flat_estimates.free_mask]
+        free_cov = pd.DataFrame(data=free_cov, columns=free_index, index=free_index)
     ####################################################################################
     # Construct summary data frame for flat estimates
     ####################################################################################
@@ -109,13 +110,19 @@ def calculate_inference_quantities(estimates, flat_estimates, free_cov, ci_level
     df = pd.DataFrame(index=flat_estimates.names)
     df["value"] = flat_estimates.values
     df.loc[free_cov.index, "standard_error"] = np.sqrt(np.diag(free_cov))
-    tvalues = df["value"] / df["standard_error"]
-    df["p_value"] = 2 * scipy.stats.norm.sf(np.abs(tvalues))
 
-    alpha = 1 - ci_level
-    scale = scipy.stats.norm.ppf(1 - alpha / 2)
-    df["ci_lower"] = df["value"] - scale * df["standard_error"]
-    df["ci_upper"] = df["value"] + scale * df["standard_error"]
+    df["p_value"] = calculate_p_values(
+        df["value"].to_numpy(),
+        df["standard_error"].to_numpy(),
+    )
+
+    lower, upper = calculate_ci(
+        df["value"].to_numpy(),
+        df["standard_error"].to_numpy(),
+        ci_level=ci_level,
+    )
+    df["ci_lower"] = lower
+    df["ci_upper"] = upper
 
     df.loc[free_cov.index, "stars"] = pd.cut(
         df.loc[free_cov.index, "p_value"],
@@ -271,3 +278,18 @@ def check_is_optimized_and_derivative_case(is_minimized, derivative_case):
             "optimization was done outside of the estimate_function, i.e. if "
             "optimize_options=False."
         )
+
+
+def calculate_ci(flat_values, flat_standard_errors, ci_level):
+
+    alpha = 1 - ci_level
+    scale = scipy.stats.norm.ppf(1 - alpha / 2)
+    lower = flat_values - scale * flat_standard_errors
+    upper = flat_values + scale * flat_standard_errors
+    return lower, upper
+
+
+def calculate_p_values(flat_values, flat_standard_error):
+    tvalues = flat_values / np.clip(flat_standard_error, 1e-300, np.inf)
+    pvalues = 2 * scipy.stats.norm.sf(np.abs(tvalues))
+    return pvalues
diff --git a/src/estimagic/sensitivity/msm_sensitivity.py b/src/estimagic/sensitivity/msm_sensitivity.py
index 8837e84c8..d57e6685e 100644
--- a/src/estimagic/sensitivity/msm_sensitivity.py
+++ b/src/estimagic/sensitivity/msm_sensitivity.py
@@ -10,80 +10,12 @@
 """
 import numpy as np
 import pandas as pd
-from estimagic.estimation.msm_weighting import get_weighting_matrix
 from estimagic.exceptions import INVALID_SENSITIVITY_MSG
-from estimagic.inference.msm_covs import cov_optimal
 from estimagic.inference.msm_covs import cov_robust
 from estimagic.inference.shared import process_pandas_arguments
 from estimagic.utilities import robust_inverse
 
 
-def calculate_sensitivity_measures(jac, weights, moments_cov, params_cov):
-    """Calculate sensitivity measures for MSM estimates.
-
-    Args:
-        jac (np.ndarray or pandas.DataFrame): The jacobian of simulate_moments with
-            respect to params, evaluated at the  point estimates.
-        weights (np.ndarray or pandas.DataFrame): The weighting matrix used for
-            msm estimation.
-        moments_cov (numpy.ndarray or pandas.DataFrame): The covariance matrix of the
-            empirical moments.
-        params_cov (numpy.ndarray or pandas.DataFrame): The covariance matrix of the
-            parameter estimates.
-
-    Returns:
-        dict: Dictionary with six sensitivity measures.
-
-
-    """
-    weights_opt = get_weighting_matrix(moments_cov, "optimal")
-    params_cov_opt = cov_optimal(jac, weights_opt)
-
-    m1 = calculate_sensitivity_to_bias(jac=jac, weights=weights)
-    e2 = calculate_fundamental_sensitivity_to_noise(
-        jac=jac,
-        weights=weights_opt,
-        moments_cov=moments_cov,
-        params_cov_opt=params_cov_opt,
-    )
-    e3 = calculate_actual_sensitivity_to_noise(
-        sensitivity_to_bias=m1,
-        weights=weights,
-        moments_cov=moments_cov,
-        params_cov=params_cov,
-    )
-    e4 = calculate_actual_sensitivity_to_removal(
-        jac=jac,
-        weights=weights,
-        moments_cov=moments_cov,
-        params_cov=params_cov,
-    )
-
-    e5 = calculate_fundamental_sensitivity_to_removal(
-        jac=jac,
-        moments_cov=moments_cov,
-        params_cov_opt=params_cov_opt,
-    )
-
-    e6 = calculate_sensitivity_to_weighting(
-        jac=jac,
-        weights=weights,
-        moments_cov=moments_cov,
-        params_cov=params_cov,
-    )
-
-    measures = {
-        "sensitivity_to_bias": m1,
-        "fundamental_sensitivity_to_noise": e2,
-        "actual_sensitivity_to_noise": e3,
-        "actual_sensitivity_to_removal": e4,
-        "fundamental_sensitivity_to_removal": e5,
-        "sensitivity_to_weighting": e6,
-    }
-
-    return measures
-
-
 def calculate_sensitivity_to_bias(jac, weights):
     """calculate the sensitivity to bias.
 
diff --git a/tox.ini b/tox.ini
index f7a0182fa..86cadcf52 100644
--- a/tox.ini
+++ b/tox.ini
@@ -114,6 +114,7 @@ ignore =
     RST201  ;  gave false positives
     W605  ; ignores regex relevant escape sequences
     E731  ; assigned lambda expressions
+    C417  ; unnecessary use of map
 per-file-ignores =
     docs/source/credits.rst:D001
     docs/source/conf.py:E501


Test patch:
diff --git a/tests/estimation/test_estimate_ml.py b/tests/estimation/test_estimate_ml.py
index 6ddc0e793..08af438ab 100644
--- a/tests/estimation/test_estimate_ml.py
+++ b/tests/estimation/test_estimate_ml.py
@@ -4,6 +4,7 @@
 import pandas as pd
 import pytest
 import scipy as sp
+import statsmodels.api as sm
 from estimagic.estimation.estimate_ml import estimate_ml
 from estimagic.examples.logit import logit_derivative
 from estimagic.examples.logit import logit_hessian
@@ -23,6 +24,19 @@ def aaae(obj1, obj2, decimal=3):
 # ======================================================================================
 
 
+@pytest.fixture
+def logit_np_inputs():
+    spector_data = sm.datasets.spector.load_pandas()
+    spector_data.exog = sm.add_constant(spector_data.exog)
+    x_df = sm.add_constant(spector_data.exog)
+    out = {
+        "y": spector_data.endog,
+        "x": x_df.to_numpy(),
+        "params": np.array([-10, 2, 0.2, 2]),
+    }
+    return out
+
+
 @pytest.fixture
 def fitted_logit_model(logit_object):
     """We need to use a generic model class to access all standard errors etc."""
@@ -44,24 +58,26 @@ def logit_loglike_and_derivative(params, y, x):
     return loglike, loglike_derivative["value"]
 
 
-test_cases = itertools.product(
-    [
-        {"algorithm": "scipy_lbfgsb"},
-        "scipy_lbfgsb",
-        {
-            "algorithm": "scipy_lbfgsb",
-            "criterion_and_derivative": logit_loglike_and_derivative,
-        },
-    ],  # optimize_options
-    [None, logit_jacobian, False],  # jacobian
-    [None, logit_hessian, False],  # hessian
+test_cases = list(
+    itertools.product(
+        [
+            {"algorithm": "scipy_lbfgsb"},
+            "scipy_lbfgsb",
+            {
+                "algorithm": "scipy_lbfgsb",
+                "criterion_and_derivative": logit_loglike_and_derivative,
+            },
+        ],  # optimize_options
+        [None, logit_jacobian, False],  # jacobian
+        [None, logit_hessian, False],  # hessian
+    )
 )
 
 
 @pytest.mark.parametrize("optimize_options, jacobian, hessian", test_cases)
 def test_estimate_ml_with_logit_no_constraints(
     fitted_logit_model,
-    logit_inputs,
+    logit_np_inputs,
     optimize_options,
     jacobian,
     hessian,
@@ -78,14 +94,14 @@ def test_estimate_ml_with_logit_no_constraints(
     # estimate
     # ==================================================================================
 
-    kwargs = {"y": logit_inputs["y"], "x": logit_inputs["x"]}
+    kwargs = {"y": logit_np_inputs["y"], "x": logit_np_inputs["x"]}
 
     if "criterion_and_derivative" in optimize_options:
         optimize_options["criterion_and_derivative_kwargs"] = kwargs
 
     got = estimate_ml(
         loglike=logit_loglike,
-        params=logit_inputs["params"],
+        params=logit_np_inputs["params"],
         loglike_kwargs=kwargs,
         optimize_options=optimize_options,
         jacobian=jacobian,
@@ -101,11 +117,11 @@ def test_estimate_ml_with_logit_no_constraints(
     exp = fitted_logit_model
 
     if jacobian is not False and hessian is not False:
-        cases = ["jacobian", "hessian", "robust"]
+        methods = ["jacobian", "hessian", "robust"]
     elif jacobian is not False:
-        cases = ["jacobian"]
+        methods = ["jacobian"]
     elif hessian is not False:
-        cases = ["hessian"]
+        methods = ["hessian"]
 
     statsmodels_suffix_map = {
         "jacobian": "jac",
@@ -113,28 +129,45 @@ def test_estimate_ml_with_logit_no_constraints(
         "robust": "jhj",
     }
 
-    for case in cases:
-
-        summary = got[f"summary_{case}"]
+    # compare estimated parameters
+    aaae(got.params, exp.params, decimal=4)
 
-        # compare estimated parameters
-        aaae(summary["value"], exp.params, decimal=4)
+    for method in methods:
 
         # compare estimated standard errors
-        exp_se = getattr(exp, f"bse{statsmodels_suffix_map[case]}")
-        aaae(summary["standard_error"], exp_se, decimal=3)
+        exp_se = getattr(exp, f"bse{statsmodels_suffix_map[method]}")
+        aaae(got.se(method=method), exp_se, decimal=3)
 
         # compare estimated confidence interval
-        if case == "hessian":
-            aaae(summary[["ci_lower", "ci_upper"]], exp.conf_int(), decimal=3)
+        if method == "hessian":
+            lower, upper = got.ci(method=method)
+            exp_lower = exp.conf_int().T[0]
+            exp_upper = exp.conf_int().T[1]
+            aaae(lower, exp_lower, decimal=3)
+            aaae(upper, exp_upper, decimal=3)
+
+        # compare covariance
+        if method == "hessian":
+            aaae(got.cov(method=method), exp.cov_params(), decimal=3)
+        elif method == "robust":
+            aaae(got.cov(method=method), exp.covjhj, decimal=2)
+        elif method == "jacobian":
+            aaae(got.cov(method=method), exp.covjac, decimal=4)
+
+        summary = got.summary(method=method)
 
-        # compare covariance (if not robust case)
-        if case == "hessian":
-            aaae(got[f"cov_{case}"], exp.cov_params(), decimal=3)
-        elif case == "robust":
-            aaae(got[f"cov_{case}"], exp.covjhj, decimal=2)
-        elif case == "jacobian":
-            aaae(got[f"cov_{case}"], exp.covjac, decimal=4)
+        aaae(summary["value"], exp.params, decimal=4)
+        aaae(summary["standard_error"], got.se(method=method))
+        lower, upper = got.ci(method=method)
+        aaae(summary["ci_lower"], lower)
+        aaae(summary["ci_upper"], upper)
+        aaae(summary["p_value"], got.p_values(method=method))
+
+    if "jacobian" in methods:
+        aaae(got._se, got.se())
+        aaae(got._ci[0], got.ci()[0])
+        aaae(got._ci[1], got.ci()[1])
+        aaae(got._p_values, got.p_values())
 
 
 def test_estimate_ml_optimize_options_false(fitted_logit_model, logit_inputs):
@@ -151,7 +184,7 @@ def test_estimate_ml_optimize_options_false(fitted_logit_model, logit_inputs):
         optimize_options=False,
     )
 
-    summary = got["summary_jacobian"]
+    summary = got.summary()
 
     # compare estimated parameters
     aaae(summary["value"], fitted_logit_model.params, decimal=4)
@@ -160,7 +193,7 @@ def test_estimate_ml_optimize_options_false(fitted_logit_model, logit_inputs):
     aaae(summary["standard_error"], fitted_logit_model.bsejac, decimal=3)
 
     # compare covariance (if not robust case)
-    aaae(got["cov_jacobian"], fitted_logit_model.covjac, decimal=4)
+    aaae(got.cov(method="jacobian"), fitted_logit_model.covjac, decimal=4)
 
 
 # ======================================================================================
@@ -203,10 +236,7 @@ def test_estimate_ml_general_pytree(normal_inputs):
         optimize_options="scipy_lbfgsb",
         lower_bounds={"sd": 0.0001},
         jacobian_kwargs=kwargs,
-        # ------------------------------------------------------------------------------
-        # constraints are not working properly at the moment. needs to be checked.
-        # constraints=[{"selector": lambda p: p["sd"], "type": "sdcorr"}],  # noqa: E800
-        # ------------------------------------------------------------------------------
+        constraints=[{"selector": lambda p: p["sd"], "type": "sdcorr"}],
     )
 
     # ==================================================================================
@@ -215,5 +245,7 @@ def test_estimate_ml_general_pytree(normal_inputs):
 
     true = normal_inputs["true"]
 
-    assert np.abs(true["mean"] - got["summary_jacobian"]["mean"]["value"][0]) < 1e-1
-    assert np.abs(true["sd"] - got["summary_jacobian"]["sd"]["value"][0]) < 1e-1
+    assert (
+        np.abs(true["mean"] - got.summary(method="jacobian")["mean"]["value"][0]) < 1e-1
+    )
+    assert np.abs(true["sd"] - got.summary(method="jacobian")["sd"]["value"][0]) < 1e-1
diff --git a/tests/estimation/test_estimate_msm.py b/tests/estimation/test_estimate_msm.py
index b1b2b0efd..95fc46133 100644
--- a/tests/estimation/test_estimate_msm.py
+++ b/tests/estimation/test_estimate_msm.py
@@ -1,6 +1,5 @@
 """Most test exploit the special case where simulate_moments just returns parameters."""
 import itertools
-import warnings
 
 import numpy as np
 import pandas as pd
@@ -12,63 +11,57 @@
 
 
 def _sim_pd(params):
-    return params["value"]
+    return pd.Series(params)
 
 
 def _sim_np(params):
-    return params["value"].to_numpy()
+    return params
 
 
 def _sim_dict_pd(params):
-    return {"simulated_moments": params["value"], "other": "bla"}
+    return {"simulated_moments": pd.Series(params), "other": "bla"}
 
 
 def _sim_dict_np(params):
-    return {"simulated_moments": params["value"].to_numpy(), "other": "bla"}
+    return {"simulated_moments": params, "other": "bla"}
 
 
 cov_np = np.diag([1, 2, 3.0])
 cov_pd = pd.DataFrame(cov_np)
 
-test_cases = itertools.product(
-    [_sim_pd, _sim_np, _sim_dict_pd, _sim_dict_np],  # simulate_moments
-    [cov_np, cov_pd],  # moments_cov
-    [{"algorithm": "scipy_lbfgsb"}, "scipy_lbfgsb"],  # optimize_options
+test_cases = list(
+    itertools.product(
+        [_sim_pd, _sim_np, _sim_dict_pd, _sim_dict_np],  # simulate_moments
+        [cov_np, cov_pd],  # moments_cov
+        [{"algorithm": "scipy_lbfgsb"}, "scipy_lbfgsb"],  # optimize_options
+    )
 )
 
 
 @pytest.mark.parametrize("simulate_moments, moments_cov, optimize_options", test_cases)
 def test_estimate_msm(simulate_moments, moments_cov, optimize_options):
-    start_params = pd.DataFrame()
-    start_params["value"] = [3, 2, 1]
+    start_params = np.array([3, 2, 1])
 
-    expected_params = pd.DataFrame()
-    expected_params["value"] = np.zeros(3)
+    expected_params = np.zeros(3)
 
     # abuse simulate_moments to get empirical moments in correct format
     empirical_moments = simulate_moments(expected_params)
     if isinstance(empirical_moments, dict):
         empirical_moments = empirical_moments["simulated_moments"]
 
-    # catching warnings is necessary because the very special case with diagonal
-    # weighting and diagonal jacobian leads to singular matrices while calculating
-    # sensitivity to removal of moments.
-    with warnings.catch_warnings():
-        warnings.filterwarnings("ignore", message="Standard matrix inversion failed")
-        calculated = estimate_msm(
-            simulate_moments=simulate_moments,
-            empirical_moments=empirical_moments,
-            moments_cov=moments_cov,
-            params=start_params,
-            optimize_options=optimize_options,
-        )
-
-    calculated_params = calculated["optimize_res"].params[["value"]]
+    calculated = estimate_msm(
+        simulate_moments=simulate_moments,
+        empirical_moments=empirical_moments,
+        moments_cov=moments_cov,
+        params=start_params,
+        optimize_options=optimize_options,
+    )
+
     # check that minimization works
-    aaae(calculated_params["value"].to_numpy(), expected_params["value"].to_numpy())
+    aaae(calculated.params, expected_params)
 
     # check that cov works
-    calculated_cov = calculated["cov"]
+    calculated_cov = calculated.cov()
     if isinstance(calculated_cov, pd.DataFrame):
         calculated_cov = calculated_cov.to_numpy()
 
@@ -76,6 +69,28 @@ def test_estimate_msm(simulate_moments, moments_cov, optimize_options):
     # jac = identity matrix
     expected_cov = np.diag([1, 2, 3])
     aaae(calculated_cov, expected_cov)
+    aaae(calculated.se(), np.sqrt([1, 2, 3]))
+
+    # works only because parameter point estimates are exactly zero
+    aaae(calculated.p_values(), np.ones(3))
+
+    #
+    expected_ci_upper = np.array([1.95996398, 2.77180765, 3.3947572])
+    expected_ci_lower = -expected_ci_upper
+
+    lower, upper = calculated.ci()
+    aaae(lower, expected_ci_lower)
+    aaae(upper, expected_ci_upper)
+
+    aaae(calculated.ci(), calculated._ci)
+    aaae(calculated.p_values(), calculated._p_values)
+    aaae(calculated.se(), calculated._se)
+    aaae(calculated.cov(), calculated._cov)
+
+    summary = calculated.summary()
+    aaae(summary["value"], np.zeros(3))
+    aaae(summary["p_value"], np.ones(3))
+    assert summary["stars"].tolist() == [""] * 3
 
 
 def test_check_and_process_numdiff_options_with_invalid_entries():
@@ -86,3 +101,59 @@ def test_check_and_process_numdiff_options_with_invalid_entries():
 def test_check_and_process_optimize_options_with_invalid_entries():
     with pytest.raises(ValueError):
         check_optimization_options({"criterion": lambda x: x}, "estimate_msm")
+
+
+ls_test_cases = list(
+    itertools.product(
+        [_sim_pd, _sim_np, _sim_dict_pd, _sim_dict_np],  # simulate_moments
+        [cov_np, cov_pd],  # moments_cov
+        [{"algorithm": "pounders"}, "pounders"],  # optimize_options
+    )
+)
+
+
+@pytest.mark.parametrize(
+    "simulate_moments, moments_cov, optimize_options", ls_test_cases
+)
+def test_estimate_msm_ls(simulate_moments, moments_cov, optimize_options):
+    start_params = np.array([3, 2, 1])
+
+    expected_params = np.zeros(3)
+
+    # abuse simulate_moments to get empirical moments in correct format
+    empirical_moments = simulate_moments(expected_params)
+    if isinstance(empirical_moments, dict):
+        empirical_moments = empirical_moments["simulated_moments"]
+
+    calculated = estimate_msm(
+        simulate_moments=simulate_moments,
+        empirical_moments=empirical_moments,
+        moments_cov=moments_cov,
+        params=start_params,
+        optimize_options=optimize_options,
+    )
+
+    aaae(calculated.params, expected_params)
+
+
+def test_estimate_msm_with_jacobian():
+    start_params = np.array([3, 2, 1])
+
+    expected_params = np.zeros(3)
+
+    # abuse simulate_moments to get empirical moments in correct format
+    empirical_moments = _sim_np(expected_params)
+    if isinstance(empirical_moments, dict):
+        empirical_moments = empirical_moments["simulated_moments"]
+
+    calculated = estimate_msm(
+        simulate_moments=_sim_np,
+        empirical_moments=empirical_moments,
+        moments_cov=cov_np,
+        params=start_params,
+        optimize_options="scipy_lbfgsb",
+        jacobian=lambda x: np.eye(len(x)),
+    )
+
+    aaae(calculated.params, expected_params)
+    aaae(calculated.cov(), cov_np)
diff --git a/tests/estimation/test_estimate_msm_dict_params_and_moments.py b/tests/estimation/test_estimate_msm_dict_params_and_moments.py
new file mode 100644
index 000000000..8ef3cd1e4
--- /dev/null
+++ b/tests/estimation/test_estimate_msm_dict_params_and_moments.py
@@ -0,0 +1,103 @@
+"""Most test exploit the special case where simulate_moments just returns parameters."""
+import numpy as np
+import pandas as pd
+from estimagic.estimation.estimate_msm import estimate_msm
+from estimagic.parameters.tree_registry import get_registry
+from numpy.testing import assert_array_almost_equal as aaae
+from pybaum import tree_just_flatten
+
+
+def test_estimate_msm_dict_params_and_moments():
+    def simulate_moments(params):
+        return {k * 2: v for k, v in params.items()}
+
+    start_params = {"a": 3, "b": 2, "c": 1}
+
+    expected_params = {"a": 0, "b": 0, "c": 0}
+
+    empirical_moments = {"aa": 0, "bb": 0, "cc": 0}
+
+    moments_cov = {
+        "aa": {"aa": 1, "bb": 0, "cc": 0},
+        "bb": {"aa": 0, "bb": 2, "cc": 0},
+        "cc": {"aa": 0, "bb": 0, "cc": 3},
+    }
+
+    calculated = estimate_msm(
+        simulate_moments=simulate_moments,
+        empirical_moments=empirical_moments,
+        moments_cov=moments_cov,
+        params=start_params,
+        optimize_options="scipy_lbfgsb",
+    )
+
+    # check that minimization works
+    assert_almost_equal(calculated.params, expected_params)
+
+    # this works only in the very special case with diagonal moments cov and
+    # jac = identity matrix
+    assert_almost_equal(calculated.cov(), moments_cov)
+
+    assert_almost_equal(calculated.se(), {"a": 1, "b": np.sqrt(2), "c": np.sqrt(3)})
+
+    # works only because parameter point estimates are exactly zero
+    assert_almost_equal(calculated.p_values(), {"a": 1, "b": 1, "c": 1})
+
+    expected_ci_upper = {"a": 1.95996398, "b": 2.77180765, "c": 3.3947572}
+    expected_ci_lower = {k: -v for k, v in expected_ci_upper.items()}
+
+    lower, upper = calculated.ci()
+    assert_almost_equal(lower, expected_ci_lower)
+    assert_almost_equal(upper, expected_ci_upper)
+
+    assert_almost_equal(calculated.ci(), calculated._ci)
+    assert_almost_equal(calculated.p_values(), calculated._p_values)
+    assert_almost_equal(calculated.se(), calculated._se)
+    assert_almost_equal(calculated.cov(), calculated._cov)
+
+    summary = calculated.summary()
+    summary_df = pd.concat(list(summary.values()))
+    aaae(summary_df["value"], np.zeros(3))
+    aaae(summary_df["p_value"], np.ones(3))
+    assert summary_df["stars"].tolist() == [""] * 3
+
+    expected_sensitivity_to_bias_dict = {
+        "a": {"aa": -1.0, "bb": 0.0, "cc": 0.0},
+        "b": {"aa": 0.0, "bb": -1.0, "cc": 0.0},
+        "c": {"aa": 0.0, "bb": 0.0, "cc": -1.0},
+    }
+
+    assert_almost_equal(
+        calculated.sensitivity("bias"), expected_sensitivity_to_bias_dict
+    )
+
+    expected_sensitivity_to_bias_arr = -np.eye(3)
+
+    aaae(
+        calculated.sensitivity("bias", return_type="array"),
+        expected_sensitivity_to_bias_arr,
+    )
+    aaae(
+        calculated.sensitivity("bias", return_type="dataframe").to_numpy(),
+        expected_sensitivity_to_bias_arr,
+    )
+
+    expected_jacobian = {
+        "a": {"aa": 1.0, "bb": 0.0, "cc": 0.0},
+        "b": {"aa": 0.0, "bb": 1.0, "cc": 0.0},
+        "c": {"aa": 0.0, "bb": 0.0, "cc": 1.0},
+    }
+
+    assert_almost_equal(calculated.jacobian, expected_jacobian)
+
+
+def assert_almost_equal(x, y, decimal=6):
+    if isinstance(x, np.ndarray):
+        x_flat = x
+        y_flat = y
+    else:
+        registry = get_registry(extended=True)
+        x_flat = np.array(tree_just_flatten(x, registry=registry))
+        y_flat = np.array(tree_just_flatten(x, registry=registry))
+
+    aaae(x_flat, y_flat, decimal=decimal)
diff --git a/tests/estimation/test_msm_weighting.py b/tests/estimation/test_msm_weighting.py
index 645fa5e48..b723991e4 100644
--- a/tests/estimation/test_msm_weighting.py
+++ b/tests/estimation/test_msm_weighting.py
@@ -3,8 +3,10 @@
 import numpy as np
 import pandas as pd
 import pytest
-from estimagic.estimation.msm_weighting import assemble_block_diagonal_matrix
+from estimagic.estimation.msm_weighting import _assemble_block_diagonal_matrix
+from estimagic.estimation.msm_weighting import get_moments_cov
 from estimagic.estimation.msm_weighting import get_weighting_matrix
+from estimagic.parameters.block_trees import block_tree_to_matrix
 from numpy.testing import assert_array_almost_equal as aaae
 
 
@@ -22,7 +24,11 @@ def expected_values():
 
 @pytest.mark.parametrize("moments_cov, method", test_cases)
 def test_get_weighting_matrix(moments_cov, method):
-    calculated = get_weighting_matrix(moments_cov, method)
+    if isinstance(moments_cov, np.ndarray):
+        fake_emp_moms = np.ones(len(moments_cov))
+    else:
+        fake_emp_moms = pd.Series(np.ones(len(moments_cov)), index=moments_cov.index)
+    calculated = get_weighting_matrix(moments_cov, method, fake_emp_moms)
 
     if isinstance(moments_cov, pd.DataFrame):
         assert calculated.index.equals(moments_cov.index)
@@ -38,7 +44,7 @@ def test_assemble_block_diagonal_matrix_pd(expected_values):
         pd.DataFrame([[1, 2], [3, 4]]),
         pd.DataFrame([[5, 6], [7, 8]], columns=[2, 3], index=[2, 3]),
     ]
-    calculated = assemble_block_diagonal_matrix(matrices)
+    calculated = _assemble_block_diagonal_matrix(matrices)
     assert isinstance(calculated, pd.DataFrame)
     assert calculated.index.equals(calculated.columns)
     assert calculated.index.tolist() == [0, 1, 2, 3]
@@ -47,6 +53,32 @@ def test_assemble_block_diagonal_matrix_pd(expected_values):
 
 def test_assemble_block_diagonal_matrix_mixed(expected_values):
     matrices = [pd.DataFrame([[1, 2], [3, 4]]), np.array([[5, 6], [7, 8]])]
-    calculated = assemble_block_diagonal_matrix(matrices)
+    calculated = _assemble_block_diagonal_matrix(matrices)
     assert isinstance(calculated, np.ndarray)
     aaae(calculated, expected_values)
+
+
+def test_get_moments_cov_runs_with_pytrees():
+    np.random.seed(1234)
+    data = np.random.normal(scale=[10, 5, 1], size=(100, 3))
+    data = pd.DataFrame(data=data)
+
+    def calc_moments(data, keys):
+        means = data.mean()
+        means.index = keys
+        return means.to_dict()
+
+    moment_kwargs = {"keys": ["a", "b", "c"]}
+
+    calculated = get_moments_cov(
+        data=data,
+        calculate_moments=calc_moments,
+        moment_kwargs=moment_kwargs,
+        bootstrap_kwargs={"n_draws": 100},
+    )
+
+    fake_tree = {"a": 1, "b": 2, "c": 3}
+    cov = block_tree_to_matrix(calculated, fake_tree, fake_tree)
+    assert cov.shape == (3, 3)
+
+    assert cov[0, 0] > cov[1, 1] > cov[2, 2]
diff --git a/tests/sensitivity/test_msm_sensitivity_via_estimate_msm.py b/tests/sensitivity/test_msm_sensitivity_via_estimate_msm.py
new file mode 100644
index 000000000..184d7d191
--- /dev/null
+++ b/tests/sensitivity/test_msm_sensitivity_via_estimate_msm.py
@@ -0,0 +1,158 @@
+import numpy as np
+import pandas as pd
+import pytest
+from estimagic.config import EXAMPLE_DIR
+from estimagic.estimation.estimate_msm import estimate_msm
+from numpy.testing import assert_array_almost_equal as aaae
+from scipy import stats
+
+
+def simulate_aggregated_moments(params, x, y):
+    """Calculate aggregated moments for example from Honore, DePaula, Jorgensen."""
+
+    mom_value = simulate_moment_contributions(params, x, y)
+    moments = mom_value.mean(axis=1)
+
+    return moments
+
+
+def simulate_moment_contributions(params, x, y):
+    """Calculate moment contributions for example from Honore, DePaula, Jorgensen."""
+
+    y_estimated = x.to_numpy() @ (params["value"].to_numpy())
+
+    x_np = x.T.to_numpy()
+
+    residual = y.T.to_numpy() - stats.norm.cdf(y_estimated)
+
+    mom_value = []
+
+    length = len(x_np)
+
+    for i in range(length):
+        for j in range(i, length):
+            moment = residual * x_np[i] * x_np[j]
+            mom_value.append(moment)
+
+    mom_value = np.stack(mom_value, axis=1)[0]
+    mom_value = pd.DataFrame(data=mom_value)
+
+    return mom_value
+
+
+@pytest.fixture
+def moments_cov(params, func_kwargs):
+    mom_value = simulate_moment_contributions(params, **func_kwargs)
+    mom_value = mom_value.to_numpy()
+    s = np.cov(mom_value, ddof=0)
+    return s
+
+
+@pytest.fixture
+def params():
+    params_index = [["beta"], ["intersection", "x1", "x2"]]
+    params_index = pd.MultiIndex.from_product(params_index, names=["type", "name"])
+    params = pd.DataFrame(
+        data=[[0.57735], [0.57735], [0.57735]], index=params_index, columns=["value"]
+    )
+    return params
+
+
+@pytest.fixture
+def func_kwargs():
+    data = pd.read_csv(EXAMPLE_DIR / "sensitivity_probit_example_data.csv")
+    y_data = data[["y"]]
+    x_data = data[["intercept", "x1", "x2"]]
+    func_kwargs = {"x": x_data, "y": y_data}
+    return func_kwargs
+
+
+@pytest.fixture()
+def msm_res(params, moments_cov, func_kwargs):
+    res = estimate_msm(
+        simulate_moments=simulate_aggregated_moments,
+        # only needed for shape since optimization is skipped
+        empirical_moments=np.zeros(6),
+        params=params,
+        optimize_options=False,
+        moments_cov=moments_cov,
+        simulate_moments_kwargs=func_kwargs,
+        weights="optimal",
+    )
+    return res
+
+
+def test_sensitivity_to_bias(msm_res):
+    calculated = msm_res.sensitivity(kind="bias")
+    expected = np.array(
+        [
+            [4.010481, 2.068143, 2.753155, 0.495683, 1.854492, 0.641020],
+            [0.605718, 6.468960, -2.235886, 1.324065, -1.916986, -0.116590],
+            [2.218011, -1.517303, 7.547212, -0.972578, 1.956985, 0.255691],
+        ]
+    )
+
+    aaae(calculated, expected)
+
+
+def test_fundamental_sensitivity_to_noise(msm_res):
+    calculated = msm_res.sensitivity(kind="noise_fundamental")
+    expected = np.array(
+        [
+            [1.108992, 0.191341, 0.323757, 0.020377, 0.085376, 0.029528],
+            [0.017262, 1.277374, 0.145700, 0.099208, 0.062248, 0.000667],
+            [0.211444, 0.064198, 1.516571, 0.048900, 0.059264, 0.002929],
+        ]
+    )
+
+    aaae(calculated, expected)
+
+
+def test_actual_sensitivity_to_noise(msm_res):
+    calculated = msm_res.sensitivity(kind="noise")
+    expected = np.array(
+        [
+            [1.108992, 0.191341, 0.323757, 0.020377, 0.085376, 0.029528],
+            [0.017262, 1.277374, 0.145700, 0.099208, 0.062248, 0.000667],
+            [0.211444, 0.064198, 1.516571, 0.048900, 0.059264, 0.002929],
+        ]
+    )
+
+    aaae(calculated, expected)
+
+
+def test_actual_sensitivity_to_removal(msm_res):
+    calculated = msm_res.sensitivity(kind="removal")
+
+    expected = np.array(
+        [
+            [1.020791, 0.343558, 0.634299, 0.014418, 0.058827, 0.017187],
+            [0.016262, 2.313441, 0.285552, 0.052574, 0.043585, 0.000306],
+            [0.189769, 0.114946, 2.984443, 0.022729, 0.042140, 0.005072],
+        ]
+    )
+
+    aaae(calculated, expected)
+
+
+def test_fundamental_sensitivity_to_removal(msm_res):
+
+    calculated = msm_res.sensitivity(kind="removal_fundamental")
+
+    expected = np.array(
+        [
+            [0.992910, 0.340663, 0.634157, 0.009277, 0.058815, 0.013542],
+            [0.015455, 2.274235, 0.285389, 0.045166, 0.042882, 0.000306],
+            [0.189311, 0.114299, 2.970578, 0.022262, 0.040827, 0.001343],
+        ]
+    )
+
+    aaae(calculated, expected)
+
+
+def test_sensitivity_to_weighting(msm_res):
+    calculated = msm_res.sensitivity(kind="weighting")
+
+    expected = np.zeros((3, 6))
+
+    aaae(calculated, expected)