diff --git a/estimagic/optimization/reparametrize.py b/estimagic/optimization/reparametrize.py
index db6eded..49b3360 100644
--- a/estimagic/optimization/reparametrize.py
+++ b/estimagic/optimization/reparametrize.py
@@ -8,6 +8,7 @@ from estimagic.optimization.utilities import cov_matrix_to_params
 from estimagic.optimization.utilities import cov_matrix_to_sdcorr_params
 from estimagic.optimization.utilities import cov_params_to_matrix
 from estimagic.optimization.utilities import number_of_triangular_elements_to_dimension
+from estimagic.optimization.utilities import robust_cholesky
 from estimagic.optimization.utilities import sdcorr_params_to_matrix
 
 
@@ -164,7 +165,7 @@ def _covariance_to_internal(params_subset, case, type_, bounds_distance):
         res["lower"] = np.maximum(res["lower"], np.zeros(len(res)))
         assert (res["upper"] >= res["lower"]).all(), "Invalid upper bound for variance."
     elif case == "free":
-        chol = np.linalg.cholesky(cov)
+        chol = robust_cholesky(cov, threshold=1e-8)
         chol_coeffs = chol[np.tril_indices(dim)]
         res["value"] = chol_coeffs
 
diff --git a/estimagic/optimization/utilities.py b/estimagic/optimization/utilities.py
index a55ba59..fde7f76 100644
--- a/estimagic/optimization/utilities.py
+++ b/estimagic/optimization/utilities.py
@@ -1,5 +1,17 @@
+import warnings
+from collections import namedtuple
+
 import numpy as np
 from fuzzywuzzy import process as fw_process
+from scipy.linalg import ldl
+from scipy.linalg import qr
+
+
+def chol_params_to_lower_triangular_matrix(params):
+    dim = number_of_triangular_elements_to_dimension(len(params))
+    mat = np.zeros((dim, dim))
+    mat[np.tril_indices(dim)] = params
+    return mat
 
 
 def cov_params_to_matrix(cov_params):
@@ -13,18 +25,34 @@ def cov_params_to_matrix(cov_params):
         cov (np.array): a covariance matrix
 
     """
-    dim = number_of_triangular_elements_to_dimension(len(cov_params))
-    lower = np.zeros((dim, dim))
-    lower[np.tril_indices(dim)] = cov_params
-    upper = lower.T.copy()
-    upper[np.diag_indices(dim)] = 0
-    cov = lower + upper
+    lower = chol_params_to_lower_triangular_matrix(cov_params)
+    cov = lower + np.tril(lower, k=-1).T
     return cov
 
 
 def cov_matrix_to_params(cov):
-    dim = len(cov)
-    return cov[np.tril_indices(dim)]
+    return cov[np.tril_indices(len(cov))]
+
+
+def sdcorr_params_to_sds_and_corr(sdcorr_params):
+    dim = number_of_triangular_elements_to_dimension(len(sdcorr_params))
+    sds = np.array(sdcorr_params[:dim])
+    corr = np.eye(dim)
+    corr[np.tril_indices(dim, k=-1)] = sdcorr_params[dim:]
+    corr += np.tril(corr, k=-1).T
+    return sds, corr
+
+
+def sds_and_corr_to_cov(sds, corr):
+    diag = np.diag(sds)
+    return diag @ corr @ diag
+
+
+def cov_to_sds_and_corr(cov):
+    sds = np.sqrt(np.diagonal(cov))
+    diag = np.diag(1 / sds)
+    corr = diag @ cov @ diag
+    return sds, corr
 
 
 def sdcorr_params_to_matrix(sdcorr_params):
@@ -40,20 +68,12 @@ def sdcorr_params_to_matrix(sdcorr_params):
         cov (np.array): a covariance matrix
 
     """
-    dim = number_of_triangular_elements_to_dimension(len(sdcorr_params))
-    diag = np.diag(sdcorr_params[:dim])
-    lower = np.zeros((dim, dim))
-    lower[np.tril_indices(dim, k=-1)] = sdcorr_params[dim:]
-    corr = np.eye(dim) + lower + lower.T
-    cov = diag.dot(corr).dot(diag)
-    return cov
+    return sds_and_corr_to_cov(*sdcorr_params_to_sds_and_corr(sdcorr_params))
 
 
 def cov_matrix_to_sdcorr_params(cov):
     dim = len(cov)
-    sds = np.sqrt(np.diagonal(cov))
-    scaling_matrix = np.diag(1 / sds)
-    corr = scaling_matrix.dot(cov).dot(scaling_matrix)
+    sds, corr = cov_to_sds_and_corr(cov)
     correlations = corr[np.tril_indices(dim, k=-1)]
     return np.hstack([sds, correlations])
 
@@ -120,3 +140,123 @@ def propose_algorithms(requested_algo, algos, number=3):
     proposals = [proposal[0] for proposal in proposals_w_probs]
 
     return proposals
+
+
+def robust_cholesky(matrix, threshold=None, warn=True, return_info=False):
+    """Lower triangular cholesky factor of *matrix*.
+
+    Args:
+        matrix (np.array): Square, symmetric and (almost) positive semi-definite matrix
+        threshold (float): Small negative number. Diagonal elements of D from the LDL
+            decomposition between threshold and zero are set to zero. Default is
+            minus machine accuracy.
+        warn (bool): If True, the user is warned about negative elements in D
+        return_info (bool): If True, also return a dictionary with 'method' and
+            'diagonals'. Method can take the values 'np.linalg.cholesky',
+            'LDL cholesky' and 'LDL cholesky with QR decomposition'.
+            'diagonals' are the diagonal entries of D. They can be used to construct
+            penalty terms for non positive definite matrices. Note that diagonals will
+            also be returned if the standard cholesky decomposition did not fail. This
+            allows for smooth penalty terms that start before actually reaching invalid
+            matrices.
+
+    Returns:
+        chol (np.array): Cholesky factor of matrix
+        info (float, optional): see return_info.
+
+    Raises:
+        np.linalg.LinalgError if the diagonal entries of D from the LDL decomposition
+        are smaller than threshold.
+
+    In contrast to a regular cholesky decomposition, this function will also
+    work for matrices that are only positive semi-definite or even indefinite.
+
+    For speed and precision reasons we first try a regular cholesky decomposition.
+    If it fails we switch to more robust methods. For this we first take an LDL
+    decomposition and set diagonal elements in D that are negative but above
+    threshold to 0. Then we use the modified D to construct a candidate cholesky
+    factor. If the candidate is not lower triangular, we use a QR decomposition to
+    make it lower triangular.
+
+
+    """
+    sum_stabilized = 0.0
+
+    try:
+        chol = np.linalg.cholesky(matrix)
+        method = "np.linalg.cholesky"
+        diags = np.diagonal(chol) ** 2
+    except np.linalg.LinAlgError:
+        method = "LDL cholesky"
+        threshold = threshold if threshold is not None else -np.finfo(float).eps
+
+        lu, d, _ = ldl(matrix)
+
+        diags = np.diagonal(d).copy()
+
+        for i in range(len(diags)):
+            if diags[i] >= 0:
+                diags[i] = np.sqrt(diags[i])
+            elif diags[i] > threshold:
+                diags[i] = 0
+                sum_stabilized += diags[i]
+            else:
+                raise np.linalg.LinAlgError(
+                    "Diagonal entry below threshold in D from LDL decomposition."
+                )
+
+        if sum_stabilized < 0 and warn:
+            warnings.warn(
+                "Negative diagonal entry has been set to 0 in robust_cholesky.",
+                category=RuntimeWarning,
+            )
+
+        candidate = lu * diags.reshape(1, len(diags))
+
+        is_triangular = (candidate[np.triu_indices(len(matrix), k=1)] == 0).all()
+
+        if is_triangular:
+            chol = candidate
+            method = "LDL cholesky"
+        else:
+            _, r = qr(candidate.T)
+            chol = r.T
+            method = "LDL cholesky with QR decomposition"
+
+    info = {"method": method, "diagonals": diags}
+
+    res = (chol, info) if return_info else chol
+    return res
+
+
+def namedtuple_from_dict(field_dict):
+    """Filled namedtuple generated from a dictionary.
+
+    Example:
+        >>> namedtuple_from_dict({'a': 1, 'b': 2})
+        NamedTuple(a=1, b=2)
+
+    """
+    return namedtuple("NamedTuple", field_dict)(**field_dict)
+
+
+def namedtuple_from_kwargs(**kwargs):
+    """Filled namedtuple generated from keyword arguments.
+
+    Example:
+        >>> namedtuple_from_kwargs(a=1, b=2)
+        NamedTuple(a=1, b=2)
+
+    """
+    return namedtuple("NamedTuple", kwargs)(**kwargs)
+
+
+def namedtuple_from_iterables(field_names, field_entries):
+    """Filled namedtuple generated from field_names and field_entries.
+
+    Example:
+        >>> namedtuple_from_iterables(field_names=['a', 'b'], field_entries=[1, 2])
+        NamedTuple(a=1, b=2)
+
+    """
+    return namedtuple("NamedTuple", field_names)(*field_entries)
diff --git a/setup.py b/setup.py
index f5d8147..06d9410 100644
--- a/setup.py
+++ b/setup.py
@@ -1,7 +1,7 @@
 from setuptools import find_packages
 from setuptools import setup
 
-version = "0.0.13"
+version = "0.0.14"
 
 setup(
     name="estimagic",

Add a robust cholesky decomposition to the utilities
## Background

The standard cholesky decompositions in `numpy.linalg` and `scipy.linalg` only work for positive-definite covariance matrices. However, there are two places where we might want to take a cholesky factor of a covariance matrix that is only positive semi-definite:

- During the reparametrization step (to_internal), if the user provided I covariance matrix that is only semi-definite in the start values
- In user code, when we need a cholesky factor of of a covariance matrix for random number generation and the optimizer tried a semi-definite covariance matrix. We could directly use it in skillmodels and respy and then probably don't need the bounds_distance anymore. 

## Proposed Solution

Add a cholesky function based on an [LDL](https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.ldl.html#scipy.linalg.ldl) decomposition. See also [here](https://stackoverflow.com/questions/46100441/cholesky-ldl-decomposition-for-semidefinite-matrices-in-python)

## How much work is it

If we only want to accept square matrices as inputs, we'll just need a few lines. If we want the functions to work with higher dimensional arrays (i.e. shape [..., k, k]) we should wait until [numba-scipy](https://github.com/numba/numba-scipy) supports `scipy.linalg.ldl`




diff --git a/estimagic/tests/optimization/test_utilities.py b/estimagic/tests/optimization/test_utilities.py
index e393cae..fce0d21 100644
--- a/estimagic/tests/optimization/test_utilities.py
+++ b/estimagic/tests/optimization/test_utilities.py
@@ -1,13 +1,26 @@
 import numpy as np
+import pandas as pd
+import pytest
 from numpy.testing import assert_array_almost_equal as aaae
 
+from estimagic.optimization.utilities import chol_params_to_lower_triangular_matrix
 from estimagic.optimization.utilities import cov_matrix_to_params
 from estimagic.optimization.utilities import cov_matrix_to_sdcorr_params
 from estimagic.optimization.utilities import cov_params_to_matrix
+from estimagic.optimization.utilities import cov_to_sds_and_corr
 from estimagic.optimization.utilities import dimension_to_number_of_triangular_elements
 from estimagic.optimization.utilities import index_element_to_string
 from estimagic.optimization.utilities import number_of_triangular_elements_to_dimension
+from estimagic.optimization.utilities import robust_cholesky
 from estimagic.optimization.utilities import sdcorr_params_to_matrix
+from estimagic.optimization.utilities import sdcorr_params_to_sds_and_corr
+from estimagic.optimization.utilities import sds_and_corr_to_cov
+
+
+def test_chol_params_to_lower_triangular_matrix():
+    calculated = chol_params_to_lower_triangular_matrix(pd.Series([1, 2, 3]))
+    expected = np.array([[1, 0], [2, 3]])
+    aaae(calculated, expected)
 
 
 def test_cov_params_to_matrix():
@@ -24,6 +37,15 @@ def test_cov_matrix_to_params():
     aaae(calculated, expected)
 
 
+def test_sdcorr_params_to_sds_and_corr():
+    sdcorr_params = pd.Series([1, 2, 3, 0.1, 0.2, 0.3])
+    exp_corr = np.array([[1, 0.1, 0.2], [0.1, 1, 0.3], [0.2, 0.3, 1]])
+    exp_sds = np.array([1, 2, 3])
+    calc_sds, calc_corr = sdcorr_params_to_sds_and_corr(sdcorr_params)
+    aaae(calc_sds, exp_sds)
+    aaae(calc_corr, exp_corr)
+
+
 def test_sdcorr_params_to_matrix():
     sds = np.sqrt([1, 2, 3])
     corrs = [0.07071068, 0.11547005, 0.08981462]
@@ -42,6 +64,25 @@ def test_cov_matrix_to_sdcorr_params():
     aaae(calculated, expected)
 
 
+def test_sds_and_corr_to_cov():
+    sds = [1, 2, 3]
+    corr = np.ones((3, 3)) * 0.2
+    corr[np.diag_indices(3)] = 1
+    calculated = sds_and_corr_to_cov(sds, corr)
+    expected = np.array([[1.0, 0.4, 0.6], [0.4, 4.0, 1.2], [0.6, 1.2, 9.0]])
+    aaae(calculated, expected)
+
+
+def test_cov_to_sds_and_corr():
+    cov = np.array([[1.0, 0.4, 0.6], [0.4, 4.0, 1.2], [0.6, 1.2, 9.0]])
+    calc_sds, calc_corr = cov_to_sds_and_corr(cov)
+    exp_sds = [1, 2, 3]
+    exp_corr = np.ones((3, 3)) * 0.2
+    exp_corr[np.diag_indices(3)] = 1
+    aaae(calc_sds, exp_sds)
+    aaae(calc_corr, exp_corr)
+
+
 def test_number_of_triangular_elements_to_dimension():
     inputs = [6, 10, 15, 21]
     expected = [3, 4, 5, 6]
@@ -61,3 +102,33 @@ def test_index_element_to_string():
     expected = ["a_b_1", "bla~5~6", "bla"]
     for inp, exp in zip(inputs, expected):
         assert index_element_to_string(*inp) == exp
+
+
+def random_cov(dim, seed):
+    num_elements = int(dim * (dim + 1) / 2)
+    chol = np.zeros((dim, dim))
+    chol[np.tril_indices(dim)] = np.random.uniform(size=num_elements)
+    cov = chol @ chol.T
+    zero_positions = np.random.choice(range(dim), size=int(dim / 5), replace=False)
+    for pos in zero_positions:
+        cov[:, pos] = 0
+        cov[pos] = 0
+    return cov
+
+
+seeds = [58822, 3181, 98855, 44002, 47631, 97741, 10655, 4600, 1151, 58189]
+dims = [8] * 6 + [10, 12, 15, 20]
+
+
+@pytest.mark.parametrize("dim, seed", zip(dims, seeds))
+def test_robust_cholesky_with_zero_variance(dim, seed):
+    cov = random_cov(dim, seed)
+    chol = robust_cholesky(cov)
+    aaae(chol.dot(chol.T), cov)
+    assert (chol[np.triu_indices(len(cov), k=1)] == 0).all()
+
+
+def test_robust_cholesky_with_extreme_cases():
+    for cov in [np.ones((5, 5)), np.zeros((5, 5))]:
+        chol = robust_cholesky(cov)
+        aaae(chol.dot(chol.T), cov)

environment.yml
pip install -e .[dev]
parse_log_pytest
environment.yml
pytest pytest-mock pytest-xdist
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
alabaster==0.7.12
algopy==0.6.1
anaconda-client==1.11.0
anyio==3.5.0
argon2-cffi==21.3.0
argon2-cffi-bindings==21.2.0
attrs==22.1.0
Babel==2.11.0
backcall==0.2.0
backports.functools-lru-cache==1.6.4
backports.tempfile==1.0
backports.weakref==1.0.post1
beautifulsoup4==4.11.1
black==23.3.0
bleach==4.1.0
bokeh==1.1.0
brotlipy==0.7.0
certifi==2022.12.7
cffi==1.15.1
cfgv==3.3.1
chardet==4.0.0
charset-normalizer==2.0.4
click==8.0.4
cloudpickle==2.0.0
clyent==1.2.2
colorama==0.4.6
conda==23.1.0
conda-build==3.23.3
conda-package-handling==2.0.2
conda-package-streaming==0.7.0
conda-verify==3.4.2
cryptography==39.0.1
cycler==0.11.0
debugpy==1.5.1
decorator==5.1.1
defusedxml==0.7.1
distlib==0.3.9
doc8==1.0.0
docutils==0.20.1
entrypoints==0.4
-e git+https://github.com/OpenSourceEconomics/estimagic.git@db33ebce433eb3eac776b3de030c2a84937894cf#egg=estimagic
exceptiongroup==1.2.2
execnet==2.0.2
fastjsonschema==2.16.2
filelock==3.12.2
flit-core==3.6.0
fonttools==4.25.0
future==0.18.3
fuzzywuzzy==0.18.0
glob2==0.7
identify==2.5.24
idna==3.4
imagesize==1.4.1
importlib-metadata==4.11.3
importlib-resources==5.2.0
iniconfig==2.0.0
ipykernel==6.15.2
ipyparallel==6.3.0
ipython==7.31.1
ipython-genutils==0.2.0
ipywidgets==7.6.5
jedi==0.18.1
Jinja2==3.1.2
json5==0.9.6
jsonschema==4.17.3
jupyter==1.0.0
jupyter-client==7.4.9
jupyter-console==6.4.4
jupyter-core==4.11.2
jupyter-server==1.23.4
jupyterlab==3.5.3
jupyterlab-pygments==0.1.2
jupyterlab-server==2.19.0
jupyterlab-widgets==1.0.0
kiwisolver==1.4.4
libarchive-c==5.1
lxml==4.9.1
MarkupSafe==2.1.1
matplotlib==3.4.3
matplotlib-inline==0.1.6
mistune==0.8.4
munkres==1.1.4
mypy-extensions==1.0.0
nbclassic==0.5.2
nbclient==0.5.13
nbconvert==6.5.4
nbformat==5.7.0
nbsphinx==0.9.7
nest-asyncio==1.5.6
nodeenv==1.9.1
notebook==6.5.2
notebook-shim==0.2.2
numdifftools==0.9.41
numpy==1.16.6
packaging==22.0
pandas==0.24.2
pandocfilters==1.5.0
parso==0.8.3
pathspec==0.11.2
patsy==0.5.3
pbr==6.1.1
pexpect==4.8.0
pickleshare==0.7.5
Pillow==9.4.0
pkginfo==1.8.3
pkgutil-resolve-name==1.3.10
platformdirs==4.0.0
pluggy==1.0.0
ply==3.11
pre-commit==2.21.0
prometheus-client==0.14.1
prompt-toolkit==3.0.43
psutil==5.9.0
ptyprocess==0.7.0
py==1.11.0
pycosat==0.6.4
pycparser==2.21
Pygments==2.11.2
pyOpenSSL==23.0.0
pyparsing==3.0.9
PyQt5-sip==12.11.0
pyrsistent==0.18.0
PySocks==1.7.1
pytest==7.4.4
pytest-mock==3.11.1
pytest-xdist==3.5.0
python-dateutil==2.8.2
python-Levenshtein==0.12.2
pytz==2022.7
PyYAML==6.0
pyzmq==23.2.0
qtconsole==5.4.0
QtPy==2.2.0
requests==2.28.1
restructuredtext-lint==1.4.0
ruamel.yaml==0.17.21
ruamel.yaml.clib==0.2.6
scipy==1.2.1
seaborn==0.11.2
Send2Trash==1.8.0
sip==6.6.2
six==1.16.0
sniffio==1.2.0
snowballstemmer==2.2.0
soupsieve==2.3.2.post1
Sphinx==5.0.2
sphinx-rtd-theme==0.4.3
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-devhelp==1.0.2
sphinxcontrib-htmlhelp==2.0.0
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.3
sphinxcontrib-serializinghtml==1.1.5
statsmodels==0.11.1
stevedore==3.5.2
terminado==0.17.1
tinycss2==1.2.1
toml==0.10.2
tomli==2.0.1
toolz==0.12.0
tornado==6.2
tox==3.28.0
tox-conda==0.10.2
tqdm==4.64.1
traitlets==5.7.1
typed-ast==1.5.5
typing-extensions==4.4.0
urllib3==1.26.14
virtualenv==20.26.6
wcwidth==0.2.5
webencodings==0.5.1
websocket-client==0.58.0
widgetsnbextension==3.5.2
zipp==3.11.0
zstandard==0.19.0

name: estimagic
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - alabaster=0.7.12=pyhd3eb1b0_0
  - algopy=0.6.1=pyhd8ed1ab_0
  - ampl-mp=3.1.0=hf726d26_1005
  - anaconda-client=1.11.0=py37h06a4308_0
  - anyio=3.5.0=py37h06a4308_0
  - argon2-cffi=21.3.0=pyhd3eb1b0_0
  - argon2-cffi-bindings=21.2.0=py37h7f8727e_0
  - attrs=22.1.0=py37h06a4308_0
  - babel=2.11.0=py37h06a4308_0
  - backcall=0.2.0=pyhd3eb1b0_0
  - backports=1.1=pyhd3eb1b0_1
  - backports.functools_lru_cache=1.6.4=pyhd3eb1b0_0
  - backports.tempfile=1.0=pyhd3eb1b0_1
  - backports.weakref=1.0.post1=py_1
  - beautifulsoup4=4.11.1=py37h06a4308_0
  - blas=1.0=openblas
  - bleach=4.1.0=pyhd3eb1b0_0
  - bokeh=1.1.0=py37_0
  - boost=1.70.0=py37h9de70de_1
  - boost-cpp=1.70.0=ha2d47e9_1
  - brotli=1.0.9=h5eee18b_9
  - brotli-bin=1.0.9=h5eee18b_9
  - brotlipy=0.7.0=py37h27cfd23_1003
  - bzip2=1.0.8=h5eee18b_6
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - cffi=1.15.1=py37h5eee18b_3
  - chardet=4.0.0=py37h06a4308_1003
  - charset-normalizer=2.0.4=pyhd3eb1b0_0
  - click=8.0.4=py37h06a4308_0
  - cloudpickle=2.0.0=pyhd3eb1b0_0
  - clyent=1.2.2=py37_1
  - colorama=0.4.6=py37h06a4308_0
  - conda=23.1.0=py37h06a4308_0
  - conda-build=3.23.3=py37h06a4308_0
  - conda-package-handling=2.0.2=py37h06a4308_0
  - conda-package-streaming=0.7.0=py37h06a4308_0
  - conda-verify=3.4.2=py_1
  - cryptography=39.0.1=py37h9ce1e76_0
  - cycler=0.11.0=pyhd3eb1b0_0
  - cyrus-sasl=2.1.28=h9c0eb46_1
  - dbus=1.13.18=hb2f20db_0
  - debugpy=1.5.1=py37h295c915_0
  - decorator=5.1.1=pyhd3eb1b0_0
  - defusedxml=0.7.1=pyhd3eb1b0_0
  - eigen=3.4.0=hdb19cb5_0
  - entrypoints=0.4=py37h06a4308_0
  - expat=2.6.4=h6a678d5_0
  - flit-core=3.6.0=pyhd3eb1b0_0
  - fontconfig=2.14.1=h52c9d5c_1
  - fonttools=4.25.0=pyhd3eb1b0_0
  - freetype=2.12.1=h4a9f257_0
  - future=0.18.3=py37h06a4308_0
  - fuzzywuzzy=0.18.0=py37h06a4308_0
  - giflib=5.2.2=h5eee18b_0
  - glib=2.78.4=h6a678d5_0
  - glib-tools=2.78.4=h6a678d5_0
  - glob2=0.7=pyhd3eb1b0_0
  - gst-plugins-base=1.14.1=h6a678d5_1
  - gstreamer=1.14.1=h5eee18b_1
  - icu=58.2=he6710b0_3
  - idna=3.4=py37h06a4308_0
  - imagesize=1.4.1=py37h06a4308_0
  - importlib-metadata=4.11.3=py37h06a4308_0
  - importlib_metadata=4.11.3=hd3eb1b0_0
  - importlib_resources=5.2.0=pyhd3eb1b0_1
  - ipopt=3.14.6=h630875f_0
  - ipykernel=6.15.2=py37h06a4308_0
  - ipyparallel=6.3.0=py37h06a4308_0
  - ipython=7.31.1=py37h06a4308_1
  - ipython_genutils=0.2.0=pyhd3eb1b0_1
  - ipywidgets=7.6.5=pyhd3eb1b0_2
  - jedi=0.18.1=py37h06a4308_1
  - jinja2=3.1.2=py37h06a4308_0
  - jpeg=9e=h5eee18b_3
  - json5=0.9.6=pyhd3eb1b0_0
  - jsonschema=4.17.3=py37h06a4308_0
  - jupyter=1.0.0=py37h06a4308_8
  - jupyter_client=7.4.9=py37h06a4308_0
  - jupyter_console=6.4.4=py37h06a4308_0
  - jupyter_core=4.11.2=py37h06a4308_0
  - jupyter_server=1.23.4=py37h06a4308_0
  - jupyterlab=3.5.3=py37h06a4308_0
  - jupyterlab_pygments=0.1.2=py_0
  - jupyterlab_server=2.19.0=py37h06a4308_0
  - jupyterlab_widgets=1.0.0=pyhd3eb1b0_1
  - kiwisolver=1.4.4=py37h6a678d5_0
  - krb5=1.20.1=h568e23c_1
  - lcms2=2.16=hb9589c4_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - lerc=4.0.0=h6a678d5_0
  - libarchive=3.6.2=hab531cd_0
  - libblas=3.9.0=16_linux64_openblas
  - libbrotlicommon=1.0.9=h5eee18b_9
  - libbrotlidec=1.0.9=h5eee18b_9
  - libbrotlienc=1.0.9=h5eee18b_9
  - libclang=14.0.6=default_hc6dbbc7_2
  - libclang13=14.0.6=default_he11475f_2
  - libcups=2.4.2=ha637b67_0
  - libdeflate=1.22=h5eee18b_0
  - libedit=3.1.20230828=h5eee18b_0
  - libevent=2.1.12=h8f2d780_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc=14.2.0=h767d61c_2
  - libgcc-ng=14.2.0=h69a702a_2
  - libgfortran-ng=7.5.0=ha8ba4b0_17
  - libgfortran4=7.5.0=ha8ba4b0_17
  - libgfortran5=14.2.0=hf1ad2bd_2
  - libglib=2.78.4=hdc74915_0
  - libgomp=14.2.0=h767d61c_2
  - libiconv=1.16=h5eee18b_3
  - liblapack=3.9.0=16_linux64_openblas
  - liblief=0.12.3=h6a678d5_0
  - libllvm14=14.0.6=hecde1de_4
  - libopenblas=0.3.21=h043d6bf_0
  - libpng=1.6.39=h5eee18b_0
  - libpq=12.15=h37d81fd_1
  - libsodium=1.0.18=h7b6447c_0
  - libstdcxx-ng=11.2.0=h1234567_1
  - libtiff=4.5.1=hffd6297_1
  - libuuid=1.41.5=h5eee18b_0
  - libwebp=1.2.4=h11a3e52_1
  - libwebp-base=1.2.4=h5eee18b_1
  - libxcb=1.15=h7f8727e_0
  - libxkbcommon=1.0.1=hfa300c1_0
  - libxml2=2.9.14=h74e7548_0
  - libxslt=1.1.35=h4e12654_0
  - lxml=4.9.1=py37h1edc446_0
  - lz4-c=1.9.4=h6a678d5_1
  - markupsafe=2.1.1=py37h7f8727e_0
  - matplotlib=3.4.3=py37h06a4308_0
  - matplotlib-base=3.4.3=py37hbbc1b5f_0
  - matplotlib-inline=0.1.6=py37h06a4308_0
  - metis=5.1.0=hf484d3e_4
  - mistune=0.8.4=py37h14c3975_1001
  - mumps-include=5.2.1=ha770c72_14
  - mumps-seq=5.2.1=h2104b81_11
  - munkres=1.1.4=py_0
  - mysql=5.7.24=he378463_2
  - nbclassic=0.5.2=py37h06a4308_0
  - nbclient=0.5.13=py37h06a4308_0
  - nbconvert=6.5.4=py37h06a4308_0
  - nbformat=5.7.0=py37h06a4308_0
  - nbsphinx=0.9.7=pyhd8ed1ab_0
  - ncurses=6.4=h6a678d5_0
  - nest-asyncio=1.5.6=py37h06a4308_0
  - nlopt=2.6.1=py37h66931aa_2
  - notebook=6.5.2=py37h06a4308_0
  - notebook-shim=0.2.2=py37h06a4308_0
  - numdifftools=0.9.41=pyhd8ed1ab_0
  - numpy=1.16.6=py37h0708ffd_4
  - numpy-base=1.16.6=py37ha8aedfd_4
  - openssl=1.1.1w=h7f8727e_0
  - packaging=22.0=py37h06a4308_0
  - pagmo=2.10=h46e0a30_1002
  - pandas=0.24.2=py37he6710b0_0
  - pandocfilters=1.5.0=pyhd3eb1b0_0
  - parso=0.8.3=pyhd3eb1b0_0
  - patch=2.7.6=h7b6447c_1001
  - patchelf=0.17.2=h6a678d5_0
  - patsy=0.5.3=py37h06a4308_0
  - pcre2=10.42=hebb0a14_1
  - pexpect=4.8.0=pyhd3eb1b0_3
  - pickleshare=0.7.5=pyhd3eb1b0_1003
  - pillow=9.4.0=py37h6a678d5_0
  - pip=19.0.3=py37_0
  - pkginfo=1.8.3=py37h06a4308_0
  - pkgutil-resolve-name=1.3.10=py37h06a4308_0
  - pluggy=1.0.0=py37h06a4308_1
  - ply=3.11=py37_0
  - prometheus_client=0.14.1=py37h06a4308_0
  - prompt-toolkit=3.0.43=pyha770c72_0
  - prompt_toolkit=3.0.43=hd3eb1b0_0
  - psutil=5.9.0=py37h5eee18b_0
  - ptyprocess=0.7.0=pyhd3eb1b0_2
  - py-lief=0.12.3=py37h6a678d5_0
  - pycosat=0.6.4=py37h5eee18b_0
  - pycparser=2.21=pyhd3eb1b0_0
  - pygments=2.11.2=pyhd3eb1b0_0
  - pygmo=2.10=py37h86cc20e_1003
  - pyopenssl=23.0.0=py37h06a4308_0
  - pyparsing=3.0.9=py37h06a4308_0
  - pyqt=5.15.7=py37h6a678d5_1
  - pyqt5-sip=12.11.0=py37h6a678d5_1
  - pyrsistent=0.18.0=py37heee7806_0
  - pysocks=1.7.1=py37_1
  - python=3.7.16=h7a1cb2a_0
  - python-dateutil=2.8.2=pyhd3eb1b0_0
  - python-fastjsonschema=2.16.2=py37h06a4308_0
  - python-levenshtein=0.12.2=py37h27cfd23_0
  - python-libarchive-c=5.1=pyhd3eb1b0_0
  - python_abi=3.7=2_cp37m
  - pytz=2022.7=py37h06a4308_0
  - pyyaml=6.0=py37h5eee18b_1
  - pyzmq=23.2.0=py37h6a678d5_0
  - qt-main=5.15.2=h5b8104b_9
  - qt-webengine=5.15.9=hd2b0992_4
  - qtconsole=5.4.0=py37h06a4308_0
  - qtpy=2.2.0=py37h06a4308_0
  - qtwebkit=5.212=h4eab89a_4
  - readline=8.2=h5eee18b_0
  - requests=2.28.1=py37h06a4308_0
  - ripgrep=14.1.0=h594256b_0
  - ruamel.yaml=0.17.21=py37h5eee18b_0
  - ruamel.yaml.clib=0.2.6=py37h5eee18b_1
  - scipy=1.2.1=py37he2b7bc3_0
  - scotch=6.0.9=h3858553_1
  - seaborn=0.11.2=pyhd3eb1b0_0
  - send2trash=1.8.0=pyhd3eb1b0_1
  - setuptools=65.6.3=py37h06a4308_0
  - sip=6.6.2=py37h6a678d5_0
  - six=1.16.0=pyhd3eb1b0_1
  - sniffio=1.2.0=py37h06a4308_1
  - snowballstemmer=2.2.0=pyhd3eb1b0_0
  - soupsieve=2.3.2.post1=py37h06a4308_0
  - sphinx=5.0.2=py37h06a4308_0
  - sphinx_rtd_theme=0.4.3=pyhd3eb1b0_0
  - sphinxcontrib-applehelp=1.0.2=pyhd3eb1b0_0
  - sphinxcontrib-devhelp=1.0.2=pyhd3eb1b0_0
  - sphinxcontrib-htmlhelp=2.0.0=pyhd3eb1b0_0
  - sphinxcontrib-jsmath=1.0.1=pyhd3eb1b0_0
  - sphinxcontrib-qthelp=1.0.3=pyhd3eb1b0_0
  - sphinxcontrib-serializinghtml=1.1.5=pyhd3eb1b0_0
  - sqlite=3.45.3=h5eee18b_0
  - statsmodels=0.11.1=py37h7b6447c_0
  - terminado=0.17.1=py37h06a4308_0
  - tinycss2=1.2.1=py37h06a4308_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - tomli=2.0.1=py37h06a4308_0
  - toolz=0.12.0=py37h06a4308_0
  - tornado=6.2=py37h5eee18b_0
  - tqdm=4.64.1=py37h06a4308_0
  - traitlets=5.7.1=py37h06a4308_0
  - typing-extensions=4.4.0=py37h06a4308_0
  - typing_extensions=4.4.0=py37h06a4308_0
  - urllib3=1.26.14=py37h06a4308_0
  - wcwidth=0.2.5=pyhd3eb1b0_0
  - webencodings=0.5.1=py37_1
  - websocket-client=0.58.0=py37h06a4308_4
  - wheel=0.38.4=py37h06a4308_0
  - widgetsnbextension=3.5.2=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - yaml=0.2.5=h7b6447c_0
  - zeromq=4.3.5=h6a678d5_0
  - zipp=3.11.0=py37h06a4308_0
  - zlib=1.2.13=h5eee18b_1
  - zstandard=0.19.0=py37h5eee18b_0
  - zstd=1.5.6=hc292b87_0
  - pip:
      - black==23.3.0
      - cfgv==3.3.1
      - distlib==0.3.9
      - doc8==1.0.0
      - docutils==0.20.1
      - exceptiongroup==1.2.2
      - execnet==2.0.2
      - filelock==3.12.2
      - identify==2.5.24
      - iniconfig==2.0.0
      - mypy-extensions==1.0.0
      - nodeenv==1.9.1
      - pathspec==0.11.2
      - pbr==6.1.1
      - platformdirs==4.0.0
      - pre-commit==2.21.0
      - py==1.11.0
      - pytest==7.4.4
      - pytest-mock==3.11.1
      - pytest-xdist==3.5.0
      - restructuredtext-lint==1.4.0
      - stevedore==3.5.2
      - tox==3.28.0
      - tox-conda==0.10.2
      - typed-ast==1.5.5
      - virtualenv==20.26.6
prefix: /opt/conda/envs/estimagic

estimagic/tests/optimization/test_utilities.py::test_cov_to_sds_and_corr estimagic/tests/optimization/test_utilities.py::test_dimension_to_number_of_triangular_elements estimagic/tests/optimization/test_utilities.py::test_sds_and_corr_to_cov estimagic/tests/optimization/test_utilities.py::test_cov_matrix_to_sdcorr_params estimagic/tests/optimization/test_utilities.py::test_chol_params_to_lower_triangular_matrix estimagic/tests/optimization/test_utilities.py::test_sdcorr_params_to_sds_and_corr estimagic/tests/optimization/test_utilities.py::test_cov_params_to_matrix estimagic/tests/optimization/test_utilities.py::test_sdcorr_params_to_matrix estimagic/tests/optimization/test_utilities.py::test_robust_cholesky_with_zero_variance[8-98855] estimagic/tests/optimization/test_utilities.py::test_index_element_to_string estimagic/tests/optimization/test_utilities.py::test_robust_cholesky_with_zero_variance[12-4600] estimagic/tests/optimization/test_utilities.py::test_number_of_triangular_elements_to_dimension estimagic/tests/optimization/test_utilities.py::test_robust_cholesky_with_zero_variance[8-97741] estimagic/tests/optimization/test_utilities.py::test_robust_cholesky_with_zero_variance[10-10655] estimagic/tests/optimization/test_utilities.py::test_robust_cholesky_with_zero_variance[15-1151] estimagic/tests/optimization/test_utilities.py::test_cov_matrix_to_params estimagic/tests/optimization/test_utilities.py::test_robust_cholesky_with_extreme_cases estimagic/tests/optimization/test_utilities.py::test_robust_cholesky_with_zero_variance[8-58822] estimagic/tests/optimization/test_utilities.py::test_robust_cholesky_with_zero_variance[8-3181] estimagic/tests/optimization/test_utilities.py::test_robust_cholesky_with_zero_variance[8-47631] estimagic/tests/optimization/test_utilities.py::test_robust_cholesky_with_zero_variance[20-58189] estimagic/tests/optimization/test_utilities.py::test_robust_cholesky_with_zero_variance[8-44002]
setup.py estimagic/optimization/reparametrize.py estimagic/optimization/utilities.py
setup.py estimagic/optimization/reparametrize.py estimagic/optimization/utilities.py