Repository: graspologic-org/graspologic

Issue:
singular_values_ attribute needed for MultipleASE class
## Expected Behavior
MultipleASE should have an attribute that stores singular values for ease of generating scree plots, consistent with the other embedding classes.  Specifically, it should output the singular values of the concatenated adjacency spectral embeddings, consistent with Figure 10 of the [paper](https://arxiv.org/pdf/1906.10026.pdf) where it is introduced.

## Actual Behavior
MultipleASE has no attribute for singular values.

## Template Code
N/A

## Full Traceback
N/A

## Your Environment
* Python version: 3.7.6
* graspologic version: 0.1.0

## Proposed Labels
 * Question


Discussion:
@pauladkisson welcome to work on this if you run out of stuff to do this week before I get back to you, just FYI

Resolving patch:
diff --git a/graspologic/embed/mase.py b/graspologic/embed/mase.py
--- a/graspologic/embed/mase.py
+++ b/graspologic/embed/mase.py
@@ -87,6 +87,13 @@ class MultipleASE(BaseEmbedMulti):
     scores_ : array, shape (n_samples, n_components, n_components)
         Estimated :math:`\hat{R}` matrices for each input graph.
 
+    singular_values_ : array, shape (n_components) OR length 2 tuple of arrays
+        If input graph is undirected, equal to the singular values of the concatenated
+        adjacency spectral embeddings. If input graph is directed, :attr:`singular_values_`
+        is a tuple of length 2, where :attr:`singular_values_[0]` corresponds to
+        the singular values of the concatenated left adjacency spectral embeddings,
+        and :attr:`singular_values_[1]` corresponds to
+        the singular values of the concatenated right adjacency spectral embeddings.
 
     Notes
     -----
@@ -166,7 +173,7 @@ def _reduce_dim(self, graphs):
 
         # Second SVD for vertices
         # The notation is slightly different than the paper
-        Uhat, _, _ = selectSVD(
+        Uhat, sing_vals_left, _ = selectSVD(
             Us,
             n_components=self.n_components,
             n_elbows=self.n_elbows,
@@ -174,14 +181,14 @@ def _reduce_dim(self, graphs):
             n_iter=self.n_iter,
         )
 
-        Vhat, _, _ = selectSVD(
+        Vhat, sing_vals_right, _ = selectSVD(
             Vs,
             n_components=self.n_components,
             n_elbows=self.n_elbows,
             algorithm=self.algorithm,
             n_iter=self.n_iter,
         )
-        return Uhat, Vhat
+        return Uhat, Vhat, sing_vals_left, sing_vals_right
 
     def fit(self, graphs, y=None):
         """
@@ -209,14 +216,16 @@ def fit(self, graphs, y=None):
             graphs = self._diag_aug(graphs)
 
         # embed
-        Uhat, Vhat = self._reduce_dim(graphs)
+        Uhat, Vhat, sing_vals_left, sing_vals_right = self._reduce_dim(graphs)
         self.latent_left_ = Uhat
         if not undirected:
             self.latent_right_ = Vhat
             self.scores_ = Uhat.T @ graphs @ Vhat
+            self.singular_values_ = (sing_vals_left, sing_vals_right)
         else:
             self.latent_right_ = None
             self.scores_ = Uhat.T @ graphs @ Uhat
+            self.singular_values_ = sing_vals_left
 
         return self
 


Test patch: