We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Change default for MASE
<!--
The issue tracker is a tool to address bugs in GraSPy itself. If you'd like to report a bug in GraSPy, fill out the template below and provide any extra information that may be useful / related to your problem.
-->
Make `scaled = True` as default for MASE

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `graspy/embed/mase.py`
Content:
```
1 # Copyright 2019 NeuroData (http://neurodata.io)
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import numpy as np
16 from sklearn.utils.validation import check_is_fitted
17 
18 from ..utils import import_graph, is_almost_symmetric
19 from .base import BaseEmbedMulti
20 from .svd import select_dimension, selectSVD
21 
22 
23 class MultipleASE(BaseEmbedMulti):
24     r"""
25     Multiple Adjacency Spectral Embedding (MASE) embeds arbitrary number of input 
26     graphs with matched vertex sets.
27 
28     For a population of undirected graphs, MASE assumes that the population of graphs 
29     is sampled from :math:`VR^{(i)}V^T` where :math:`V \in \mathbb{R}^{n\times d}` and 
30     :math:`R^{(i)} \in \mathbb{R}^{d\times d}`. Score matrices, :math:`R^{(i)}`, are 
31     allowed to vary for each graph, but are symmetric. All graphs share a common a 
32     latent position matrix :math:`V`. 
33     
34     For a population of directed graphs, MASE assumes that the population is sampled
35     from :math:`UR^{(i)}V^T` where :math:`U \in \mathbb{R}^{n\times d_1}`, 
36     :math:`V \in \mathbb{R}^{n\times d_2}`, and 
37     :math:`R^{(i)} \in \mathbb{R}^{d_1\times d_2}`. In this case, score matrices 
38     :math:`R^{(i)}` can be assymetric and non-square, but all graphs still share a 
39     common latent position matrices :math:`U` and :math:`V`.
40 
41     Parameters
42     ----------
43     n_components : int or None, default = None
44         Desired dimensionality of output data. If "full", 
45         n_components must be <= min(X.shape). Otherwise, n_components must be
46         < min(X.shape). If None, then optimal dimensions will be chosen by
47         :func:`~graspy.embed.select_dimension` using ``n_elbows`` argument.
48 
49     n_elbows : int, optional, default: 2
50         If ``n_components=None``, then compute the optimal embedding dimension using
51         :func:`~graspy.embed.select_dimension`. Otherwise, ignored.
52 
53     algorithm : {'randomized' (default), 'full', 'truncated'}, optional
54         SVD solver to use:
55 
56         - 'randomized'
57             Computes randomized svd using 
58             :func:`sklearn.utils.extmath.randomized_svd`
59         - 'full'
60             Computes full svd using :func:`scipy.linalg.svd`
61         - 'truncated'
62             Computes truncated svd using :func:`scipy.sparse.linalg.svds`
63 
64     n_iter : int, optional (default = 5)
65         Number of iterations for randomized SVD solver. Not used by 'full' or 
66         'truncated'. The default is larger than the default in randomized_svd 
67         to handle sparse matrices that may have large slowly decaying spectrum.
68 
69     scaled : bool, optional (default=False)
70         Whether to scale individual eigenvectors with eigenvalues in first embedding 
71         stage.
72 
73     Attributes
74     ----------
75     n_graphs_ : int
76         Number of graphs
77 
78     n_vertices_ : int
79         Number of vertices in each graph
80 
81     latent_left_ : array, shape (n_samples, n_components)
82         Estimated left latent positions of the graph. 
83 
84     latent_right_ : array, shape (n_samples, n_components), or None
85         Estimated right latent positions of the graph. Only computed when the an input 
86         graph is directed, or adjacency matrix is assymetric. Otherwise, None.
87 
88     scores_ : array, shape (n_samples, n_components, n_components)
89         Estimated :math:`\hat{R}` matrices for each input graph.
90 
91     Notes
92     -----
93     When an input graph is directed, `n_components` of `latent_left_` may not be equal
94     to `n_components` of `latent_right_`.
95     """
96 
97     def __init__(
98         self,
99         n_components=None,
100         n_elbows=2,
101         algorithm="randomized",
102         n_iter=5,
103         scaled=False,
104     ):
105         if not isinstance(scaled, bool):
106             msg = "scaled must be a boolean, not {}".format(scaled)
107             raise TypeError(msg)
108 
109         super().__init__(
110             n_components=n_components,
111             n_elbows=n_elbows,
112             algorithm=algorithm,
113             n_iter=n_iter,
114         )
115         self.scaled = scaled
116 
117     def _reduce_dim(self, graphs):
118         # first embed into log2(n_vertices) for each graph
119         n_components = int(np.ceil(np.log2(np.min(self.n_vertices_))))
120 
121         # embed individual graphs
122         embeddings = [
123             selectSVD(
124                 graph,
125                 n_components=n_components,
126                 algorithm=self.algorithm,
127                 n_iter=self.n_iter,
128             )
129             for graph in graphs
130         ]
131         Us, Ds, Vs = zip(*embeddings)
132 
133         # Choose the best embedding dimension for each graphs
134         if self.n_components is None:
135             embedding_dimensions = []
136             for D in Ds:
137                 elbows, _ = select_dimension(D, n_elbows=self.n_elbows)
138                 embedding_dimensions.append(elbows[-1])
139 
140             # Choose the max of all of best embedding dimension of all graphs
141             best_dimension = int(np.ceil(np.max(embedding_dimensions)))
142         else:
143             best_dimension = self.n_components
144 
145         if not self.scaled:
146             Us = np.hstack([U[:, :best_dimension] for U in Us])
147             Vs = np.hstack([V.T[:, :best_dimension] for V in Vs])
148         else:
149             # Equivalent to ASE
150             Us = np.hstack(
151                 [
152                     U[:, :best_dimension] @ np.diag(np.sqrt(D[:best_dimension]))
153                     for U, D in zip(Us, Ds)
154                 ]
155             )
156             Vs = np.hstack(
157                 [
158                     V.T[:, :best_dimension] @ np.diag(np.sqrt(D[:best_dimension]))
159                     for V, D in zip(Vs, Ds)
160                 ]
161             )
162 
163         # Second SVD for vertices
164         # The notation is slightly different than the paper
165         Uhat, _, _ = selectSVD(
166             Us,
167             n_components=self.n_components,
168             n_elbows=self.n_elbows,
169             algorithm=self.algorithm,
170             n_iter=self.n_iter,
171         )
172 
173         Vhat, _, _ = selectSVD(
174             Vs,
175             n_components=self.n_components,
176             n_elbows=self.n_elbows,
177             algorithm=self.algorithm,
178             n_iter=self.n_iter,
179         )
180         return Uhat, Vhat
181 
182     def fit(self, graphs, y=None):
183         """
184         Fit the model with graphs.
185 
186         Parameters
187         ----------
188         graphs : list of nx.Graph or ndarray, or ndarray
189             If list of nx.Graph, each Graph must contain same number of nodes.
190             If list of ndarray, each array must have shape (n_vertices, n_vertices).
191             If ndarray, then array must have shape (n_graphs, n_vertices, n_vertices).
192 
193         Returns
194         -------
195         self : object
196             Returns an instance of self.
197         """
198         graphs = self._check_input_graphs(graphs)
199 
200         # Check if undirected
201         undirected = all(is_almost_symmetric(g) for g in graphs)
202 
203         # embed
204         Uhat, Vhat = self._reduce_dim(graphs)
205         self.latent_left_ = Uhat
206         if not undirected:
207             self.latent_right_ = Vhat
208             self.scores_ = Uhat.T @ graphs @ Vhat
209         else:
210             self.latent_right_ = None
211             self.scores_ = Uhat.T @ graphs @ Uhat
212 
213         return self
214 
215     def fit_transform(self, graphs, y=None):
216         """
217         Fit the model with graphs and apply the embedding on graphs. 
218         n_components is either automatically determined or based on user input.
219 
220         Parameters
221         ----------
222         graphs : list of nx.Graph or ndarray, or ndarray
223             If list of nx.Graph, each Graph must contain same number of nodes.
224             If list of ndarray, each array must have shape (n_vertices, n_vertices).
225             If ndarray, then array must have shape (n_graphs, n_vertices, n_vertices).
226 
227         Returns
228         -------
229         out : array-like, shape (n_vertices, n_components) if input 
230             graphs were symmetric. If graphs were directed, returns tuple of 
231             two arrays (same shape as above) where the first corresponds to the
232             left latent positions, and the right to the right latent positions
233         """
234         return self._fit_transform(graphs)
235
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/graspy/embed/mase.py b/graspy/embed/mase.py
--- a/graspy/embed/mase.py
+++ b/graspy/embed/mase.py
@@ -66,7 +66,7 @@
         'truncated'. The default is larger than the default in randomized_svd 
         to handle sparse matrices that may have large slowly decaying spectrum.
 
-    scaled : bool, optional (default=False)
+    scaled : bool, optional (default=True)
         Whether to scale individual eigenvectors with eigenvalues in first embedding 
         stage.
 
@@ -100,7 +100,7 @@
         n_elbows=2,
         algorithm="randomized",
         n_iter=5,
-        scaled=False,
+        scaled=True,
     ):
         if not isinstance(scaled, bool):
             msg = "scaled must be a boolean, not {}".format(scaled)

{"golden_diff": "diff --git a/graspy/embed/mase.py b/graspy/embed/mase.py\n--- a/graspy/embed/mase.py\n+++ b/graspy/embed/mase.py\n@@ -66,7 +66,7 @@\n         'truncated'. The default is larger than the default in randomized_svd \n         to handle sparse matrices that may have large slowly decaying spectrum.\n \n-    scaled : bool, optional (default=False)\n+    scaled : bool, optional (default=True)\n         Whether to scale individual eigenvectors with eigenvalues in first embedding \n         stage.\n \n@@ -100,7 +100,7 @@\n         n_elbows=2,\n         algorithm=\"randomized\",\n         n_iter=5,\n-        scaled=False,\n+        scaled=True,\n     ):\n         if not isinstance(scaled, bool):\n             msg = \"scaled must be a boolean, not {}\".format(scaled)\n", "issue": "Change default for MASE\n<!--\r\nThe issue tracker is a tool to address bugs in GraSPy itself. If you'd like to report a bug in GraSPy, fill out the template below and provide any extra information that may be useful / related to your problem.\r\n-->\r\nMake `scaled = True` as default for MASE\n", "before_files": [{"content": "# Copyright 2019 NeuroData (http://neurodata.io)\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport numpy as np\nfrom sklearn.utils.validation import check_is_fitted\n\nfrom ..utils import import_graph, is_almost_symmetric\nfrom .base import BaseEmbedMulti\nfrom .svd import select_dimension, selectSVD\n\n\nclass MultipleASE(BaseEmbedMulti):\n    r\"\"\"\n    Multiple Adjacency Spectral Embedding (MASE) embeds arbitrary number of input \n    graphs with matched vertex sets.\n\n    For a population of undirected graphs, MASE assumes that the population of graphs \n    is sampled from :math:`VR^{(i)}V^T` where :math:`V \\in \\mathbb{R}^{n\\times d}` and \n    :math:`R^{(i)} \\in \\mathbb{R}^{d\\times d}`. Score matrices, :math:`R^{(i)}`, are \n    allowed to vary for each graph, but are symmetric. All graphs share a common a \n    latent position matrix :math:`V`. \n    \n    For a population of directed graphs, MASE assumes that the population is sampled\n    from :math:`UR^{(i)}V^T` where :math:`U \\in \\mathbb{R}^{n\\times d_1}`, \n    :math:`V \\in \\mathbb{R}^{n\\times d_2}`, and \n    :math:`R^{(i)} \\in \\mathbb{R}^{d_1\\times d_2}`. In this case, score matrices \n    :math:`R^{(i)}` can be assymetric and non-square, but all graphs still share a \n    common latent position matrices :math:`U` and :math:`V`.\n\n    Parameters\n    ----------\n    n_components : int or None, default = None\n        Desired dimensionality of output data. If \"full\", \n        n_components must be <= min(X.shape). Otherwise, n_components must be\n        < min(X.shape). If None, then optimal dimensions will be chosen by\n        :func:`~graspy.embed.select_dimension` using ``n_elbows`` argument.\n\n    n_elbows : int, optional, default: 2\n        If ``n_components=None``, then compute the optimal embedding dimension using\n        :func:`~graspy.embed.select_dimension`. Otherwise, ignored.\n\n    algorithm : {'randomized' (default), 'full', 'truncated'}, optional\n        SVD solver to use:\n\n        - 'randomized'\n            Computes randomized svd using \n            :func:`sklearn.utils.extmath.randomized_svd`\n        - 'full'\n            Computes full svd using :func:`scipy.linalg.svd`\n        - 'truncated'\n            Computes truncated svd using :func:`scipy.sparse.linalg.svds`\n\n    n_iter : int, optional (default = 5)\n        Number of iterations for randomized SVD solver. Not used by 'full' or \n        'truncated'. The default is larger than the default in randomized_svd \n        to handle sparse matrices that may have large slowly decaying spectrum.\n\n    scaled : bool, optional (default=False)\n        Whether to scale individual eigenvectors with eigenvalues in first embedding \n        stage.\n\n    Attributes\n    ----------\n    n_graphs_ : int\n        Number of graphs\n\n    n_vertices_ : int\n        Number of vertices in each graph\n\n    latent_left_ : array, shape (n_samples, n_components)\n        Estimated left latent positions of the graph. \n\n    latent_right_ : array, shape (n_samples, n_components), or None\n        Estimated right latent positions of the graph. Only computed when the an input \n        graph is directed, or adjacency matrix is assymetric. Otherwise, None.\n\n    scores_ : array, shape (n_samples, n_components, n_components)\n        Estimated :math:`\\hat{R}` matrices for each input graph.\n\n    Notes\n    -----\n    When an input graph is directed, `n_components` of `latent_left_` may not be equal\n    to `n_components` of `latent_right_`.\n    \"\"\"\n\n    def __init__(\n        self,\n        n_components=None,\n        n_elbows=2,\n        algorithm=\"randomized\",\n        n_iter=5,\n        scaled=False,\n    ):\n        if not isinstance(scaled, bool):\n            msg = \"scaled must be a boolean, not {}\".format(scaled)\n            raise TypeError(msg)\n\n        super().__init__(\n            n_components=n_components,\n            n_elbows=n_elbows,\n            algorithm=algorithm,\n            n_iter=n_iter,\n        )\n        self.scaled = scaled\n\n    def _reduce_dim(self, graphs):\n        # first embed into log2(n_vertices) for each graph\n        n_components = int(np.ceil(np.log2(np.min(self.n_vertices_))))\n\n        # embed individual graphs\n        embeddings = [\n            selectSVD(\n                graph,\n                n_components=n_components,\n                algorithm=self.algorithm,\n                n_iter=self.n_iter,\n            )\n            for graph in graphs\n        ]\n        Us, Ds, Vs = zip(*embeddings)\n\n        # Choose the best embedding dimension for each graphs\n        if self.n_components is None:\n            embedding_dimensions = []\n            for D in Ds:\n                elbows, _ = select_dimension(D, n_elbows=self.n_elbows)\n                embedding_dimensions.append(elbows[-1])\n\n            # Choose the max of all of best embedding dimension of all graphs\n            best_dimension = int(np.ceil(np.max(embedding_dimensions)))\n        else:\n            best_dimension = self.n_components\n\n        if not self.scaled:\n            Us = np.hstack([U[:, :best_dimension] for U in Us])\n            Vs = np.hstack([V.T[:, :best_dimension] for V in Vs])\n        else:\n            # Equivalent to ASE\n            Us = np.hstack(\n                [\n                    U[:, :best_dimension] @ np.diag(np.sqrt(D[:best_dimension]))\n                    for U, D in zip(Us, Ds)\n                ]\n            )\n            Vs = np.hstack(\n                [\n                    V.T[:, :best_dimension] @ np.diag(np.sqrt(D[:best_dimension]))\n                    for V, D in zip(Vs, Ds)\n                ]\n            )\n\n        # Second SVD for vertices\n        # The notation is slightly different than the paper\n        Uhat, _, _ = selectSVD(\n            Us,\n            n_components=self.n_components,\n            n_elbows=self.n_elbows,\n            algorithm=self.algorithm,\n            n_iter=self.n_iter,\n        )\n\n        Vhat, _, _ = selectSVD(\n            Vs,\n            n_components=self.n_components,\n            n_elbows=self.n_elbows,\n            algorithm=self.algorithm,\n            n_iter=self.n_iter,\n        )\n        return Uhat, Vhat\n\n    def fit(self, graphs, y=None):\n        \"\"\"\n        Fit the model with graphs.\n\n        Parameters\n        ----------\n        graphs : list of nx.Graph or ndarray, or ndarray\n            If list of nx.Graph, each Graph must contain same number of nodes.\n            If list of ndarray, each array must have shape (n_vertices, n_vertices).\n            If ndarray, then array must have shape (n_graphs, n_vertices, n_vertices).\n\n        Returns\n        -------\n        self : object\n            Returns an instance of self.\n        \"\"\"\n        graphs = self._check_input_graphs(graphs)\n\n        # Check if undirected\n        undirected = all(is_almost_symmetric(g) for g in graphs)\n\n        # embed\n        Uhat, Vhat = self._reduce_dim(graphs)\n        self.latent_left_ = Uhat\n        if not undirected:\n            self.latent_right_ = Vhat\n            self.scores_ = Uhat.T @ graphs @ Vhat\n        else:\n            self.latent_right_ = None\n            self.scores_ = Uhat.T @ graphs @ Uhat\n\n        return self\n\n    def fit_transform(self, graphs, y=None):\n        \"\"\"\n        Fit the model with graphs and apply the embedding on graphs. \n        n_components is either automatically determined or based on user input.\n\n        Parameters\n        ----------\n        graphs : list of nx.Graph or ndarray, or ndarray\n            If list of nx.Graph, each Graph must contain same number of nodes.\n            If list of ndarray, each array must have shape (n_vertices, n_vertices).\n            If ndarray, then array must have shape (n_graphs, n_vertices, n_vertices).\n\n        Returns\n        -------\n        out : array-like, shape (n_vertices, n_components) if input \n            graphs were symmetric. If graphs were directed, returns tuple of \n            two arrays (same shape as above) where the first corresponds to the\n            left latent positions, and the right to the right latent positions\n        \"\"\"\n        return self._fit_transform(graphs)\n", "path": "graspy/embed/mase.py"}], "after_files": [{"content": "# Copyright 2019 NeuroData (http://neurodata.io)\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport numpy as np\nfrom sklearn.utils.validation import check_is_fitted\n\nfrom ..utils import import_graph, is_almost_symmetric\nfrom .base import BaseEmbedMulti\nfrom .svd import select_dimension, selectSVD\n\n\nclass MultipleASE(BaseEmbedMulti):\n    r\"\"\"\n    Multiple Adjacency Spectral Embedding (MASE) embeds arbitrary number of input \n    graphs with matched vertex sets.\n\n    For a population of undirected graphs, MASE assumes that the population of graphs \n    is sampled from :math:`VR^{(i)}V^T` where :math:`V \\in \\mathbb{R}^{n\\times d}` and \n    :math:`R^{(i)} \\in \\mathbb{R}^{d\\times d}`. Score matrices, :math:`R^{(i)}`, are \n    allowed to vary for each graph, but are symmetric. All graphs share a common a \n    latent position matrix :math:`V`. \n    \n    For a population of directed graphs, MASE assumes that the population is sampled\n    from :math:`UR^{(i)}V^T` where :math:`U \\in \\mathbb{R}^{n\\times d_1}`, \n    :math:`V \\in \\mathbb{R}^{n\\times d_2}`, and \n    :math:`R^{(i)} \\in \\mathbb{R}^{d_1\\times d_2}`. In this case, score matrices \n    :math:`R^{(i)}` can be assymetric and non-square, but all graphs still share a \n    common latent position matrices :math:`U` and :math:`V`.\n\n    Parameters\n    ----------\n    n_components : int or None, default = None\n        Desired dimensionality of output data. If \"full\", \n        n_components must be <= min(X.shape). Otherwise, n_components must be\n        < min(X.shape). If None, then optimal dimensions will be chosen by\n        :func:`~graspy.embed.select_dimension` using ``n_elbows`` argument.\n\n    n_elbows : int, optional, default: 2\n        If ``n_components=None``, then compute the optimal embedding dimension using\n        :func:`~graspy.embed.select_dimension`. Otherwise, ignored.\n\n    algorithm : {'randomized' (default), 'full', 'truncated'}, optional\n        SVD solver to use:\n\n        - 'randomized'\n            Computes randomized svd using \n            :func:`sklearn.utils.extmath.randomized_svd`\n        - 'full'\n            Computes full svd using :func:`scipy.linalg.svd`\n        - 'truncated'\n            Computes truncated svd using :func:`scipy.sparse.linalg.svds`\n\n    n_iter : int, optional (default = 5)\n        Number of iterations for randomized SVD solver. Not used by 'full' or \n        'truncated'. The default is larger than the default in randomized_svd \n        to handle sparse matrices that may have large slowly decaying spectrum.\n\n    scaled : bool, optional (default=True)\n        Whether to scale individual eigenvectors with eigenvalues in first embedding \n        stage.\n\n    Attributes\n    ----------\n    n_graphs_ : int\n        Number of graphs\n\n    n_vertices_ : int\n        Number of vertices in each graph\n\n    latent_left_ : array, shape (n_samples, n_components)\n        Estimated left latent positions of the graph. \n\n    latent_right_ : array, shape (n_samples, n_components), or None\n        Estimated right latent positions of the graph. Only computed when the an input \n        graph is directed, or adjacency matrix is assymetric. Otherwise, None.\n\n    scores_ : array, shape (n_samples, n_components, n_components)\n        Estimated :math:`\\hat{R}` matrices for each input graph.\n\n    Notes\n    -----\n    When an input graph is directed, `n_components` of `latent_left_` may not be equal\n    to `n_components` of `latent_right_`.\n    \"\"\"\n\n    def __init__(\n        self,\n        n_components=None,\n        n_elbows=2,\n        algorithm=\"randomized\",\n        n_iter=5,\n        scaled=True,\n    ):\n        if not isinstance(scaled, bool):\n            msg = \"scaled must be a boolean, not {}\".format(scaled)\n            raise TypeError(msg)\n\n        super().__init__(\n            n_components=n_components,\n            n_elbows=n_elbows,\n            algorithm=algorithm,\n            n_iter=n_iter,\n        )\n        self.scaled = scaled\n\n    def _reduce_dim(self, graphs):\n        # first embed into log2(n_vertices) for each graph\n        n_components = int(np.ceil(np.log2(np.min(self.n_vertices_))))\n\n        # embed individual graphs\n        embeddings = [\n            selectSVD(\n                graph,\n                n_components=n_components,\n                algorithm=self.algorithm,\n                n_iter=self.n_iter,\n            )\n            for graph in graphs\n        ]\n        Us, Ds, Vs = zip(*embeddings)\n\n        # Choose the best embedding dimension for each graphs\n        if self.n_components is None:\n            embedding_dimensions = []\n            for D in Ds:\n                elbows, _ = select_dimension(D, n_elbows=self.n_elbows)\n                embedding_dimensions.append(elbows[-1])\n\n            # Choose the max of all of best embedding dimension of all graphs\n            best_dimension = int(np.ceil(np.max(embedding_dimensions)))\n        else:\n            best_dimension = self.n_components\n\n        if not self.scaled:\n            Us = np.hstack([U[:, :best_dimension] for U in Us])\n            Vs = np.hstack([V.T[:, :best_dimension] for V in Vs])\n        else:\n            # Equivalent to ASE\n            Us = np.hstack(\n                [\n                    U[:, :best_dimension] @ np.diag(np.sqrt(D[:best_dimension]))\n                    for U, D in zip(Us, Ds)\n                ]\n            )\n            Vs = np.hstack(\n                [\n                    V.T[:, :best_dimension] @ np.diag(np.sqrt(D[:best_dimension]))\n                    for V, D in zip(Vs, Ds)\n                ]\n            )\n\n        # Second SVD for vertices\n        # The notation is slightly different than the paper\n        Uhat, _, _ = selectSVD(\n            Us,\n            n_components=self.n_components,\n            n_elbows=self.n_elbows,\n            algorithm=self.algorithm,\n            n_iter=self.n_iter,\n        )\n\n        Vhat, _, _ = selectSVD(\n            Vs,\n            n_components=self.n_components,\n            n_elbows=self.n_elbows,\n            algorithm=self.algorithm,\n            n_iter=self.n_iter,\n        )\n        return Uhat, Vhat\n\n    def fit(self, graphs, y=None):\n        \"\"\"\n        Fit the model with graphs.\n\n        Parameters\n        ----------\n        graphs : list of nx.Graph or ndarray, or ndarray\n            If list of nx.Graph, each Graph must contain same number of nodes.\n            If list of ndarray, each array must have shape (n_vertices, n_vertices).\n            If ndarray, then array must have shape (n_graphs, n_vertices, n_vertices).\n\n        Returns\n        -------\n        self : object\n            Returns an instance of self.\n        \"\"\"\n        graphs = self._check_input_graphs(graphs)\n\n        # Check if undirected\n        undirected = all(is_almost_symmetric(g) for g in graphs)\n\n        # embed\n        Uhat, Vhat = self._reduce_dim(graphs)\n        self.latent_left_ = Uhat\n        if not undirected:\n            self.latent_right_ = Vhat\n            self.scores_ = Uhat.T @ graphs @ Vhat\n        else:\n            self.latent_right_ = None\n            self.scores_ = Uhat.T @ graphs @ Uhat\n\n        return self\n\n    def fit_transform(self, graphs, y=None):\n        \"\"\"\n        Fit the model with graphs and apply the embedding on graphs. \n        n_components is either automatically determined or based on user input.\n\n        Parameters\n        ----------\n        graphs : list of nx.Graph or ndarray, or ndarray\n            If list of nx.Graph, each Graph must contain same number of nodes.\n            If list of ndarray, each array must have shape (n_vertices, n_vertices).\n            If ndarray, then array must have shape (n_graphs, n_vertices, n_vertices).\n\n        Returns\n        -------\n        out : array-like, shape (n_vertices, n_components) if input \n            graphs were symmetric. If graphs were directed, returns tuple of \n            two arrays (same shape as above) where the first corresponds to the\n            left latent positions, and the right to the right latent positions\n        \"\"\"\n        return self._fit_transform(graphs)\n", "path": "graspy/embed/mase.py"}]}