Repository: netket/netket

Issue:
Rename `netket.stats.Stats.R` to `Rhat`?
As we have seen in the discussion on #365, the `stats.R` parameter is ambiguously named; it is sometimes called "Gelman-Rubin" statistic or "potential scale reduction", but I think the most common way to refer to it is $\hat R$ in LaTeX math or "Rhat" in words (this name is used, e.g., by the [stan](https://mc-stan.org/rstan/reference/Rhat.html) framework). So I propose we also call it `Rhat` starting in 3.0.

What do you think?


Discussion:

Resolving patch:
diff --git a/netket/stats/mc_stats.py b/netket/stats/mc_stats.py
--- a/netket/stats/mc_stats.py
+++ b/netket/stats/mc_stats.py
@@ -19,27 +19,32 @@ class Stats:
     _NaN = float("NaN")
 
     def __init__(
-        self, mean=_NaN, error_of_mean=_NaN, variance=_NaN, tau_corr=_NaN, R=_NaN
+        self,
+        mean=_NaN,
+        error_of_mean=_NaN,
+        variance=_NaN,
+        tau_corr=_NaN,
+        R_hat=_NaN,
     ):
         self.mean = mean
         self.error_of_mean = error_of_mean
         self.variance = variance
         self.tau_corr = tau_corr
-        self.R = R
+        self.R_hat = R_hat
 
     def to_json(self):
         jsd = {}
         jsd["Mean"] = self.mean.real
         jsd["Variance"] = self.variance
         jsd["Sigma"] = self.error_of_mean
-        jsd["R"] = self.R
+        jsd["R_hat"] = self.R_hat
         jsd["TauCorr"] = self.tau_corr
         return jsd
 
     def __repr__(self):
         mean, err = _format_decimal(self.mean, self.error_of_mean)
-        return "{} ± {} [var={:.1e}, R={:.4f}]".format(
-            mean, err, self.variance, self.R
+        return "{} ± {} [var={:.1e}, R_hat={:.4f}]".format(
+            mean, err, self.variance, self.R_hat
         )
 
     def __getitem__(self, name):
@@ -49,8 +54,8 @@ def __getitem__(self, name):
             return self.variance
         elif name is "error_of_mean" or "Sigma":
             return self.error_of_mean
-        elif name is "R":
-            return self.R
+        elif name is "R_hat":
+            return self.R_hat
         elif name is "tau_corr" or "TauCorr":
             return self.tau_corr
 
@@ -144,6 +149,13 @@ def statistics(data):
 
     if n_batches > 1:
         N = data.shape[-1]
-        stats.R = _np.sqrt((N - 1) / N + batch_var / stats.variance)
+
+        # V_loc = _np.var(data, axis=-1, ddof=0)
+        # W_loc = _np.mean(V_loc)
+        # W = _mean(W_loc)
+        # # This approximation seems to hold well enough for larger n_samples
+        W = stats.variance
+
+        stats.R_hat = _np.sqrt((N - 1) / N + batch_var / W)
 
     return stats


Test patch:
diff --git a/Test/GroundState/test_groundstate.py b/Test/GroundState/test_groundstate.py
--- a/Test/GroundState/test_groundstate.py
+++ b/Test/GroundState/test_groundstate.py
@@ -74,7 +74,7 @@ def test_vmc_iterator():
                 and hasattr(e, "error_of_mean")
                 and hasattr(e, "variance")
                 and hasattr(e, "tau_corr")
-                and hasattr(e, "R")
+                and hasattr(e, "R_hat")
             )
         last_obs = obs
 
@@ -99,7 +99,11 @@ def test_vmc_iterator_iterative():
         for name in "Energy", "SigmaX":
             assert name in obs
             e = obs[name]
-            assert hasattr(e, "mean") and hasattr(e, "variance") and hasattr(e, "R")
+            assert (
+                hasattr(e, "mean")
+                and hasattr(e, "variance")
+                and hasattr(e, "R_hat")
+            )
         last_obs = obs
 
     assert count == 300
diff --git a/Test/Stats/mpi_test_stats.py b/Test/Stats/mpi_test_stats.py
--- a/Test/Stats/mpi_test_stats.py
+++ b/Test/Stats/mpi_test_stats.py
@@ -28,9 +28,9 @@ def reference_stats(data):
     var_mean = np.mean(chain_vars)
     var_between = N * np.var(chain_means, ddof=0)
 
-    Rhat = np.sqrt((N - 1) / N + var_between / (N * var_mean))
+    R_hat = np.sqrt((N - 1) / N + var_between / (N * var_mean))
 
-    return mean_full, var_full, Rhat
+    return mean_full, var_full, R_hat
 
 
 def test_mc_stats():
@@ -46,7 +46,7 @@ def test_mc_stats():
 
     assert stats.mean == approx(ref_mean)
     assert stats.variance == approx(ref_var)
-    assert stats.R == approx(ref_R)
+    assert stats.R_hat == approx(ref_R)
 
 
 def test_mean():
diff --git a/Test/Stats/test_stats.py b/Test/Stats/test_stats.py
--- a/Test/Stats/test_stats.py
+++ b/Test/Stats/test_stats.py
@@ -50,7 +50,7 @@ def _test_stats_mean_std(hi, ham, ma, n_chains):
         # R estimate
         B_over_n = stats.error_of_mean ** 2
         W = stats.variance
-        assert stats.R == pytest.approx(np.sqrt(1.0 + B_over_n / W), abs=1e-3)
+        assert stats.R_hat == pytest.approx(np.sqrt(1.0 + B_over_n / W), abs=1e-3)
 
 
 def test_stats_mean_std():
diff --git a/Test/SteadyState/test_steadystate.py b/Test/SteadyState/test_steadystate.py
--- a/Test/SteadyState/test_steadystate.py
+++ b/Test/SteadyState/test_steadystate.py
@@ -119,7 +119,7 @@ def test_ss_iterator():
                     and hasattr(e, "error_of_mean")
                     and hasattr(e, "variance")
                     and hasattr(e, "tau_corr")
-                    and hasattr(e, "R")
+                    and hasattr(e, "R_hat")
             )
         losses.append(vmc.ldagl["mean"])
 
@@ -147,7 +147,7 @@ def test_ss_iterator_sr():
         for name in "LdagL", "SigmaX":
             assert name in obs
             e = obs[name]
-            assert hasattr(e, "mean") and hasattr(e, "variance") and hasattr(e, "R")
+            assert hasattr(e, "mean") and hasattr(e, "variance") and hasattr(e, "R_hat")
         losses.append(vmc.ldagl["mean"])
 
     assert count == N_iters