Repository: rhayes777/PyAutoFit
Pull request #904 (2024-01-17 09:24:28)

create prior tuples for tuple annotated arguments with no default


Patch:
diff --git a/autofit/example/model.py b/autofit/example/model.py
index a349f2c5a..342135a26 100644
--- a/autofit/example/model.py
+++ b/autofit/example/model.py
@@ -1,4 +1,5 @@
 import math
+from typing import Tuple
 
 from autofit.jax_wrapper import numpy as np
 
@@ -152,3 +153,17 @@ class Exponential:
             The x coordinates in the original reference frame of the grid.
         """
         return self.model_data_1d_via_xvalues_from(xvalues=xvalues)
+
+
+class PhysicalNFW:
+    def __init__(
+        self,
+        centre: Tuple[float, float],
+        ell_comps: Tuple[float, float],
+        log10m: float,
+        concentration: float,
+    ):
+        self.centre = centre
+        self.ell_comps = ell_comps
+        self.log10m = log10m
+        self.concentration = concentration
diff --git a/autofit/mapper/prior_model/prior_model.py b/autofit/mapper/prior_model/prior_model.py
index 2d1865d14..1e2e99841 100644
--- a/autofit/mapper/prior_model/prior_model.py
+++ b/autofit/mapper/prior_model/prior_model.py
@@ -4,6 +4,7 @@ import copy
 import inspect
 import logging
 from typing import List
+import typing
 
 from autofit.jax_wrapper import register_pytree_node_class, register_pytree_node
 
@@ -144,18 +145,15 @@ class Model(AbstractPriorModel):
                     keyword_arg = self._convert_value(keyword_arg)
                     setattr(self, arg, keyword_arg)
             elif arg in defaults and isinstance(defaults[arg], tuple):
-                tuple_prior = TuplePrior()
-                for i in range(len(defaults[arg])):
-                    attribute_name = "{}_{}".format(arg, i)
-                    setattr(
-                        tuple_prior, attribute_name, self.make_prior(attribute_name)
-                    )
-                setattr(self, arg, tuple_prior)
+                setattr(self, arg, self.make_tuple_prior(arg, len(defaults[arg])))
             elif arg in annotations and annotations[arg] is not float:
                 spec = annotations[arg]
 
+                if isinstance(spec, typing._GenericAlias) and spec.__origin__ is tuple:
+                    setattr(self, arg, self.make_tuple_prior(arg, len(spec.__args__)))
+
                 # noinspection PyUnresolvedReferences
-                if inspect.isclass(spec) and issubclass(spec, float):
+                elif inspect.isclass(spec) and issubclass(spec, float):
                     from autofit.mapper.prior_model.annotation import (
                         AnnotationPriorModel,
                     )
@@ -324,6 +322,13 @@ class Model(AbstractPriorModel):
         except ConfigException as e:
             return e
 
+    def make_tuple_prior(self, name, length):
+        tuple_prior = TuplePrior()
+        for i in range(length):
+            attribute_name = "{}_{}".format(name, i)
+            setattr(tuple_prior, attribute_name, self.make_prior(attribute_name))
+        return tuple_prior
+
     @assert_not_frozen
     def __setattr__(self, key, value):
         try:


Test patch:
diff --git a/test_autofit/config/priors/model.yaml b/test_autofit/config/priors/model.yaml
index 5ca637328..0fda20896 100644
--- a/test_autofit/config/priors/model.yaml
+++ b/test_autofit/config/priors/model.yaml
@@ -29,3 +29,50 @@ Gaussian:
     width_modifier:
       type: Absolute
       value: 1.0
+
+
+PhysicalNFW:
+  centre_0:
+    type: Gaussian
+    mean: 0.0
+    sigma: 1.0
+    lower_limit: -inf
+    upper_limit: inf
+  centre_1:
+    type: Gaussian
+    mean: 0.0
+    sigma: 1.0
+    lower_limit: -inf
+    upper_limit: inf
+  ell_comps_0:
+    type: Gaussian
+    mean: 0.0
+    sigma: 0.3
+    lower_limit: -1.0
+    upper_limit: 1.0
+    width_modifier:
+      type: Absolute
+      value: 0.2
+    gaussian_limits:
+      lower: -1.0
+      upper: 1.0
+  ell_comps_1:
+    type: Gaussian
+    mean: 0.0
+    sigma: 0.3
+    lower_limit: -1.0
+    upper_limit: 1.0
+    width_modifier:
+      type: Absolute
+      value: 0.2
+    gaussian_limits:
+      lower: '-1.0'
+      upper: '1.0'
+  log10m:
+    type: Uniform
+    lower_limit: 6.0
+    upper_limit: 18.0
+  concentration:
+    type: Uniform
+    lower_limit: 1.0
+    upper_limit: 20.0
\ No newline at end of file
diff --git a/test_autofit/mapper/model/test_regression.py b/test_autofit/mapper/model/test_regression.py
index 63a1fe624..d43976fc6 100644
--- a/test_autofit/mapper/model/test_regression.py
+++ b/test_autofit/mapper/model/test_regression.py
@@ -4,6 +4,7 @@ import pytest
 
 import autofit as af
 from autoconf.exc import ConfigException
+from autofit.example.model import PhysicalNFW
 from autofit.mapper.model_object import Identifier
 
 
@@ -169,3 +170,8 @@ class TestModel:
 def test_typing_annotations():
     model = af.Model(TestModel)
     assert model.items == af.Collection()
+
+
+def test_no_default_tuple_priors():
+    model = af.Model(PhysicalNFW)
+    assert model.prior_count == 6