Repository: rhayes777/PyAutoFit
Pull request #1004 (2024-04-22 08:53:55)

feature/samples summary
Along with changes to autoconf this resolves https://github.com/rhayes777/PyAutoFit/issues/976



Patch:
diff --git a/autofit/non_linear/paths/directory.py b/autofit/non_linear/paths/directory.py
index 687dee45a..5b6f5b178 100644
--- a/autofit/non_linear/paths/directory.py
+++ b/autofit/non_linear/paths/directory.py
@@ -285,8 +285,27 @@ class DirectoryPaths(AbstractPaths):
     def save_samples_summary(self, samples_summary: SamplesSummary):
         model = samples_summary.model
 
+        filter_args = tuple(
+            name
+            for name in (
+                "errors_at_sigma_1",
+                "errors_at_sigma_3",
+                "values_at_sigma_1",
+                "values_at_sigma_3",
+                "max_log_likelihood_sample",
+                "median_pdf_sample",
+            )
+            if not should_output(name)
+        )
+
         samples_summary.model = None
-        self.save_json("samples_summary", to_dict(samples_summary))
+        self.save_json(
+            "samples_summary",
+            to_dict(
+                samples_summary,
+                filter_args=filter_args,
+            ),
+        )
         samples_summary.model = model
 
     def load_samples_summary(self) -> SamplesSummary:
diff --git a/autofit/non_linear/samples/pdf.py b/autofit/non_linear/samples/pdf.py
index e9f378410..6e71f87f6 100644
--- a/autofit/non_linear/samples/pdf.py
+++ b/autofit/non_linear/samples/pdf.py
@@ -45,13 +45,10 @@ class SamplesPDF(Samples):
         """
 
         super().__init__(
-            model=model,
-            sample_list=sample_list,
-            samples_info=samples_info
+            model=model, sample_list=sample_list, samples_info=samples_info
         )
 
     def summary(self):
-
         median_pdf_sample = Sample.from_lists(
             model=self.model,
             parameter_lists=[self.median_pdf(as_instance=False)],
@@ -65,6 +62,10 @@ class SamplesPDF(Samples):
             max_log_likelihood_sample=self.max_log_likelihood_sample,
             median_pdf_sample=median_pdf_sample,
             log_evidence=self.log_evidence,
+            errors_at_sigma_1=self.errors_at_sigma(sigma=1.0, as_instance=False),
+            errors_at_sigma_3=self.errors_at_sigma(sigma=3.0, as_instance=False),
+            values_at_sigma_1=self.values_at_sigma(sigma=1.0, as_instance=False),
+            values_at_sigma_3=self.values_at_sigma(sigma=3.0, as_instance=False),
         )
 
     @classmethod
@@ -366,7 +367,9 @@ class SamplesPDF(Samples):
 
         with warnings.catch_warnings():
             warnings.simplefilter("ignore")
-            return np.cov(m=self.parameter_lists, rowvar=False, aweights=self.weight_list)
+            return np.cov(
+                m=self.parameter_lists, rowvar=False, aweights=self.weight_list
+            )
 
     def save_covariance_matrix(self, filename: Union[pathlib.Path, str]):
         """
diff --git a/autofit/non_linear/samples/summary.py b/autofit/non_linear/samples/summary.py
index b19273866..1103c82f7 100644
--- a/autofit/non_linear/samples/summary.py
+++ b/autofit/non_linear/samples/summary.py
@@ -14,12 +14,18 @@ logger = logging.getLogger(__name__)
 
 
 class SamplesSummary(SamplesInterface):
+    __exclude_fields__ = ["model"]
+
     def __init__(
         self,
         max_log_likelihood_sample: Sample,
         model: AbstractPriorModel = None,
-        median_pdf_sample : Optional[Sample] = None,
+        median_pdf_sample: Optional[Sample] = None,
         log_evidence: Optional[float] = None,
+        errors_at_sigma_1=None,
+        errors_at_sigma_3=None,
+        values_at_sigma_1=None,
+        values_at_sigma_3=None,
     ):
         """
         A summary of the results of a `NonLinearSearch` that has been run, including the maximum log likelihood
@@ -40,6 +46,11 @@ class SamplesSummary(SamplesInterface):
         self._log_evidence = log_evidence
         self.derived_summary = None
 
+        self.errors_at_sigma_1 = errors_at_sigma_1
+        self.errors_at_sigma_3 = errors_at_sigma_3
+        self.values_at_sigma_1 = values_at_sigma_1
+        self.values_at_sigma_3 = values_at_sigma_3
+
     @property
     def max_log_likelihood_sample(self):
         return self._max_log_likelihood_sample


Test patch:
diff --git a/test_autofit/serialise/test_samples.py b/test_autofit/serialise/test_samples.py
index 266e3d3b5..918f05e2a 100644
--- a/test_autofit/serialise/test_samples.py
+++ b/test_autofit/serialise/test_samples.py
@@ -49,34 +49,62 @@ def test_summary(summary, model, sample):
 @pytest.fixture(name="summary_dict")
 def make_summary_dict():
     return {
-        'type':
-            'instance', 'class_path':
-            'autofit.non_linear.samples.summary.SamplesSummary', 'arguments': {
-                'log_evidence': None,
-                'model': {
-                    'class_path': 'autofit.example.model.Gaussian',
-                    'type': 'model',
-                    'arguments': {
-                        'centre': {
-                            'lower_limit': 0.0, 'upper_limit': 1.0, 'type': 'Uniform'},
-                                                  'normalization': {'lower_limit': 0.0, 'upper_limit': 1.0,
-                                                                    'type': 'Uniform'},
-                                                  'sigma': {'lower_limit': 0.0, 'upper_limit': 1.0,
-                                                            'type': 'Uniform'}}},
-                          'max_log_likelihood_sample': {'type': 'instance',
-                                                        'class_path': 'autofit.non_linear.samples.sample.Sample',
-                                                        'arguments': {'log_likelihood': 4.0, 'log_prior': 5.0,
-                                                                      'weight': 6.0, 'kwargs': {'type': 'dict',
-                                                                                                'arguments': {
-                                                                                                    'centre': 2.0,
-                                                                                                    'normalization': 4.0,
-                                                                                                    'sigma': 6.0}}}},
-                          'median_pdf_sample': {'type': 'instance',
-                                                'class_path': 'autofit.non_linear.samples.sample.Sample',
-                                                'arguments': {'log_likelihood': 4.0, 'log_prior': 5.0, 'weight': 6.0,
-                                                              'kwargs': {'type': 'dict', 'arguments': {'centre': 2.0,
-                                                                                                       'normalization': 4.0,
-                                                                                                       'sigma': 6.0}}}}}}
+        "type": "instance",
+        "class_path": "autofit.non_linear.samples.summary.SamplesSummary",
+        "arguments": {
+            "errors_at_sigma_1": {
+                "type": "list",
+                "values": [(2.0, 0.0), (3.0, 0.0), (4.0, 0.0)],
+            },
+            "errors_at_sigma_3": {
+                "type": "list",
+                "values": [(2.0, 0.0), (3.0, 0.0), (4.0, 0.0)],
+            },
+            "values_at_sigma_3": {
+                "type": "list",
+                "values": [(0.0, 2.0), (1.0, 4.0), (2.0, 6.0)],
+            },
+            "max_log_likelihood_sample": {
+                "type": "instance",
+                "class_path": "autofit.non_linear.samples.sample.Sample",
+                "arguments": {
+                    "log_likelihood": 4.0,
+                    "log_prior": 5.0,
+                    "weight": 6.0,
+                    "kwargs": {
+                        "type": "dict",
+                        "arguments": {
+                            "centre": 2.0,
+                            "normalization": 4.0,
+                            "sigma": 6.0,
+                        },
+                    },
+                },
+            },
+            "values_at_sigma_1": {
+                "type": "list",
+                "values": [(0.0, 2.0), (1.0, 4.0), (2.0, 6.0)],
+            },
+            "log_evidence": None,
+            "median_pdf_sample": {
+                "type": "instance",
+                "class_path": "autofit.non_linear.samples.sample.Sample",
+                "arguments": {
+                    "log_likelihood": 4.0,
+                    "log_prior": 5.0,
+                    "weight": 6.0,
+                    "kwargs": {
+                        "type": "dict",
+                        "arguments": {
+                            "centre": 2.0,
+                            "normalization": 4.0,
+                            "sigma": 6.0,
+                        },
+                    },
+                },
+            },
+        },
+    }
 
 
 def test_dict(summary, summary_dict, remove_ids):
@@ -88,13 +116,7 @@ def test_from_dict(summary_dict):
     assert isinstance(summary, SamplesSummary)
 
 
-
 def test_generic_from_dict(summary_dict):
     summary = from_dict(summary_dict)
     assert isinstance(summary, SamplesSummary)
-    #  assert isinstance(summary.model, af.Model)
     assert isinstance(summary.max_log_likelihood_sample, af.Sample)
-
-# def test_covariance_interpolator(summary):
-#     interpolator = af.CovarianceInterpolator([summary])
-#     assert interpolator[interpolator.centre == 0.5]