Repository: GPflow/GPflow

Issue:
print_summary does not display information on parameter priors
### `print_summary` does not display information on parameter priors

GPflow 2 (`develop-2.0` branch):
`print_summary` on a model with priors does not have a column for the `prior` attribute.

MWE:
```python
import gpflow
import tensorflow_probability as tfp
from gpflow.utilities import to_default_float
from gpflow.utilities import print_summary

k = gpflow.kernels.Matern32()
k.variance.prior = tfp.distributions.Gamma(
    to_default_float(2), to_default_float(3))

print_summary(k)
```
print_summary does not display information on parameter priors
### `print_summary` does not display information on parameter priors

GPflow 2 (`develop-2.0` branch):
`print_summary` on a model with priors does not have a column for the `prior` attribute.

MWE:
```python
import gpflow
import tensorflow_probability as tfp
from gpflow.utilities import to_default_float
from gpflow.utilities import print_summary

k = gpflow.kernels.Matern32()
k.variance.prior = tfp.distributions.Gamma(
    to_default_float(2), to_default_float(3))

print_summary(k)
```


Discussion:

Resolving patch:
diff --git a/gpflow/utilities/utilities.py b/gpflow/utilities/utilities.py
--- a/gpflow/utilities/utilities.py
+++ b/gpflow/utilities/utilities.py
@@ -137,26 +137,37 @@ def print_summary(module: tf.Module, fmt: str = None):
 
 
 def tabulate_module_summary(module: tf.Module, tablefmt: Optional[str] = None) -> str:
-    column_names = ['name', 'class', 'transform', 'trainable', 'shape', 'dtype', 'value']
-
-    def get_name(v):
-        return v.__class__.__name__
+    def get_transform(path, var):
+        if hasattr(var, 'transform') and var.transform is not None:
+            if isinstance(var.transform, tfp.bijectors.Chain):
+                return " + ".join(b.__class__.__name__ for b in var.transform.bijectors[::-1])
+            return var.transform.__class__.__name__
+        return None
 
-    def get_transform(v):
-        if hasattr(v, "transform") and v.transform is not None:
-            if isinstance(v.transform, tfp.bijectors.Chain):
-                return " + ".join(b.__class__.__name__ for b in v.transform.bijectors[::-1])
-            return v.transform.__class__.__name__
+    def get_prior(path, var):
+        if hasattr(var, 'prior') and var.prior is not None:
+            return var.prior.name
         return None
 
+    # list of (column_name: str, column_getter: Callable[[tf.Variable], str]) tuples:
+    column_definition = [
+        ("name", lambda path, var: path),
+        ("class", lambda path, var: var.__class__.__name__),
+        ("transform", get_transform),
+        ("prior", get_prior),
+        ("trainable", lambda path, var: var.trainable),
+        ("shape", lambda path, var: var.shape),
+        ("dtype", lambda path, var: var.dtype.name),
+        ("value", lambda path, var: _str_tensor_value(var.numpy())),
+        ]
+    column_names, column_getters = zip(*column_definition)
+
     merged_leaf_components = _merge_leaf_components(leaf_components(module))
 
-    column_values = [[
-        path,
-        get_name(variable),
-        get_transform(variable), variable.trainable, variable.shape, variable.dtype.name,
-        _str_tensor_value(variable.numpy())
-    ] for path, variable in merged_leaf_components.items()]
+    column_values = [
+        [getter(path, variable) for getter in column_getters]
+        for path, variable in merged_leaf_components.items()
+    ]
     return tabulate(column_values, headers=column_names, tablefmt=tablefmt)
 
 


Test patch:
diff --git a/tests/test_printing.py b/tests/test_printing.py
--- a/tests/test_printing.py
+++ b/tests/test_printing.py
@@ -190,70 +190,70 @@ def create_model():
 }
 
 compose_kernel_param_print_string = """\
-name                                       class      transform    trainable    shape    dtype      value\n\
------------------------------------------  ---------  -----------  -----------  -------  -------  -------\n\
-Product.kernels[0].kernels[0].variance     Parameter  Softplus     True         ()       float64        1\n\
-Product.kernels[0].kernels[0].lengthscale  Parameter  Softplus     False        ()       float64        2\n\
-Product.kernels[0].kernels[1].variance     Parameter  Softplus     True         ()       float64        1\n\
-Product.kernels[0].kernels[1].lengthscale  Parameter  Softplus     False        ()       float64        2\n\
-Product.kernels[1].kernels[0].variance     Parameter  Softplus     True         ()       float64        1\n\
-Product.kernels[1].kernels[0].lengthscale  Parameter  Softplus     False        ()       float64        2\n\
-Product.kernels[1].kernels[1].variance     Parameter  Softplus     True         ()       float64        1\n\
-Product.kernels[1].kernels[1].lengthscale  Parameter  Softplus     False        ()       float64        2"""
+name                                       class      transform    prior    trainable    shape    dtype      value\n\
+-----------------------------------------  ---------  -----------  -------  -----------  -------  -------  -------\n\
+Product.kernels[0].kernels[0].variance     Parameter  Softplus              True         ()       float64        1\n\
+Product.kernels[0].kernels[0].lengthscale  Parameter  Softplus              False        ()       float64        2\n\
+Product.kernels[0].kernels[1].variance     Parameter  Softplus              True         ()       float64        1\n\
+Product.kernels[0].kernels[1].lengthscale  Parameter  Softplus              False        ()       float64        2\n\
+Product.kernels[1].kernels[0].variance     Parameter  Softplus              True         ()       float64        1\n\
+Product.kernels[1].kernels[0].lengthscale  Parameter  Softplus              False        ()       float64        2\n\
+Product.kernels[1].kernels[1].variance     Parameter  Softplus              True         ()       float64        1\n\
+Product.kernels[1].kernels[1].lengthscale  Parameter  Softplus              False        ()       float64        2"""
 
 kernel_param_print_string = """\
-name                            class      transform    trainable    shape    dtype      value\n\
-------------------------------  ---------  -----------  -----------  -------  -------  -------\n\
-SquaredExponential.variance     Parameter  Softplus     True         ()       float64        1\n\
-SquaredExponential.lengthscale  Parameter  Softplus     False        ()       float64        2"""
+name                            class      transform    prior    trainable    shape    dtype      value\n\
+------------------------------  ---------  -----------  -------  -----------  -------  -------  -------\n\
+SquaredExponential.variance     Parameter  Softplus              True         ()       float64        1\n\
+SquaredExponential.lengthscale  Parameter  Softplus              False        ()       float64        2"""
 
 kernel_param_print_string_with_shift = """\
-name                            class      transform                trainable    shape    dtype      value\n\
-------------------------------  ---------  -----------------------  -----------  -------  -------  -------\n\
-SquaredExponential.variance     Parameter  Softplus + AffineScalar  True         ()       float64        1\n\
-SquaredExponential.lengthscale  Parameter  Softplus + AffineScalar  False        ()       float64        2"""
+name                            class      transform                prior    trainable    shape    dtype      value\n\
+------------------------------  ---------  -----------------------  -------  -----------  -------  -------  -------\n\
+SquaredExponential.variance     Parameter  Softplus + AffineScalar           True         ()       float64        1\n\
+SquaredExponential.lengthscale  Parameter  Softplus + AffineScalar           False        ()       float64        2"""
 
 model_gp_param_print_string = """\
-name                      class      transform    trainable    shape    dtype    value\n\
-------------------------  ---------  -----------  -----------  -------  -------  --------\n\
-SVGP.kernel.variance      Parameter  Softplus     True         ()       float64  1.0\n\
-SVGP.kernel.lengthscale   Parameter  Softplus     False        ()       float64  2.0\n\
-SVGP.likelihood.variance  Parameter  Softplus     True         ()       float64  1.0\n\
-SVGP.inducing_variable.Z  Parameter               True         (10, 1)  float64  [[0.5...\n\
-SVGP.q_mu                 Parameter               False        (10, 1)  float64  [[0....\n\
-SVGP.q_sqrt               Parameter  Softplus     True         (10, 1)  float64  [[1...."""
+name                      class      transform    prior    trainable    shape    dtype    value\n\
+------------------------  ---------  -----------  -------  -----------  -------  -------  --------\n\
+SVGP.kernel.variance      Parameter  Softplus              True         ()       float64  1.0\n\
+SVGP.kernel.lengthscale   Parameter  Softplus              False        ()       float64  2.0\n\
+SVGP.likelihood.variance  Parameter  Softplus              True         ()       float64  1.0\n\
+SVGP.inducing_variable.Z  Parameter                        True         (10, 1)  float64  [[0.5...\n\
+SVGP.q_mu                 Parameter                        False        (10, 1)  float64  [[0....\n\
+SVGP.q_sqrt               Parameter  Softplus              True         (10, 1)  float64  [[1...."""
 
 example_tf_module_variable_print_string = """\
-name             class             transform    trainable    shape      dtype    value\n\
----------------  ----------------  -----------  -----------  ---------  -------  --------\n\
-A.var_trainable  ResourceVariable               True         (2, 2, 1)  float32  [[[0....\n\
-A.var_fixed      ResourceVariable               False        (2, 2, 1)  float32  [[[1...."""
+name             class             transform    prior    trainable    shape      dtype    value\n\
+---------------  ----------------  -----------  -------  -----------  ---------  -------  --------\n\
+A.var_trainable  ResourceVariable                        True         (2, 2, 1)  float32  [[[0....\n\
+A.var_fixed      ResourceVariable                        False        (2, 2, 1)  float32  [[[1...."""
 
 example_module_list_variable_print_string = """\
-name                                 class             transform    trainable    shape      dtype    value\n\
------------------------------------  ----------------  -----------  -----------  ---------  -------  --------\n\
-B.submodule_list[0].var_trainable    ResourceVariable               True         (2, 2, 1)  float32  [[[0....\n\
-B.submodule_list[0].var_fixed        ResourceVariable               False        (2, 2, 1)  float32  [[[1....\n\
-B.submodule_list[1].var_trainable    ResourceVariable               True         (2, 2, 1)  float32  [[[0....\n\
-B.submodule_list[1].var_fixed        ResourceVariable               False        (2, 2, 1)  float32  [[[1....\n\
-B.submodule_dict['a'].var_trainable  ResourceVariable               True         (2, 2, 1)  float32  [[[0....\n\
-B.submodule_dict['a'].var_fixed      ResourceVariable               False        (2, 2, 1)  float32  [[[1....\n\
-B.submodule_dict['b'].var_trainable  ResourceVariable               True         (2, 2, 1)  float32  [[[0....\n\
-B.submodule_dict['b'].var_fixed      ResourceVariable               False        (2, 2, 1)  float32  [[[1....\n\
-B.var_trainable                      ResourceVariable               True         (2, 2, 1)  float32  [[[0....\n\
-B.var_fixed                          ResourceVariable               False        (2, 2, 1)  float32  [[[1...."""
+name                                 class             transform    prior    trainable    shape      dtype    value\n\
+-----------------------------------  ----------------  -----------  -------  -----------  ---------  -------  --------\n\
+B.submodule_list[0].var_trainable    ResourceVariable                        True         (2, 2, 1)  float32  [[[0....\n\
+B.submodule_list[0].var_fixed        ResourceVariable                        False        (2, 2, 1)  float32  [[[1....\n\
+B.submodule_list[1].var_trainable    ResourceVariable                        True         (2, 2, 1)  float32  [[[0....\n\
+B.submodule_list[1].var_fixed        ResourceVariable                        False        (2, 2, 1)  float32  [[[1....\n\
+B.submodule_dict['a'].var_trainable  ResourceVariable                        True         (2, 2, 1)  float32  [[[0....\n\
+B.submodule_dict['a'].var_fixed      ResourceVariable                        False        (2, 2, 1)  float32  [[[1....\n\
+B.submodule_dict['b'].var_trainable  ResourceVariable                        True         (2, 2, 1)  float32  [[[0....\n\
+B.submodule_dict['b'].var_fixed      ResourceVariable                        False        (2, 2, 1)  float32  [[[1....\n\
+B.var_trainable                      ResourceVariable                        True         (2, 2, 1)  float32  [[[0....\n\
+B.var_fixed                          ResourceVariable                        False        (2, 2, 1)  float32  [[[1...."""
 
 # Note: we use grid format here because we have a double reference to the same variable
 # which does not render nicely in the table formatting.
 example_tf_keras_model = """\
-+-------------------------+------------------+-------------+-------------+-----------+---------+----------+\n\
-| name                    | class            | transform   | trainable   | shape     | dtype   | value    |\n\
-+=========================+==================+=============+=============+===========+=========+==========+\n\
-| C._trainable_weights[0] | ResourceVariable |             | True        | (2, 2, 1) | float32 | [[[0.... |\n\
-| C.variable              |                  |             |             |           |         |          |\n\
-+-------------------------+------------------+-------------+-------------+-----------+---------+----------+\n\
-| C.param                 | Parameter        |             | True        | ()        | float64 | 0.0      |\n\
-+-------------------------+------------------+-------------+-------------+-----------+---------+----------+"""
++-------------------------+------------------+-------------+---------+-------------+-----------+---------+----------+\n\
+| name                    | class            | transform   | prior   | trainable   | shape     | dtype   | value    |\n\
++=========================+==================+=============+=========+=============+===========+=========+==========+\n\
+| C._trainable_weights[0] | ResourceVariable |             |         | True        | (2, 2, 1) | float32 | [[[0.... |\n\
+| C.variable              |                  |             |         |             |           |         |          |\n\
++-------------------------+------------------+-------------+---------+-------------+-----------+---------+----------+\n\
+| C.param                 | Parameter        |             |         | True        | ()        | float64 | 0.0      |\n\
++-------------------------+------------------+-------------+---------+-------------+-----------+---------+----------+"""
 
 # ------------------------------------------
 # Fixtures