Repository: graspologic-org/graspologic

Issue:
[BUG] Graph matching errors when similarity matrix has unequal dimensions
## Expected Behavior

Graspologic handles similarity matrices with dimensions of different sizes for matrices A and B.

## Actual Behavior

```
~/projects/graspologic/graspologic/match/solver.py in __init__(self, A, B, AB, BA, S, partial_match, init, init_perturbation, verbose, shuffle_input, padding, maximize, max_iter, tol, transport, transport_regularizer, transport_tol, transport_max_iter)
    191             S = csr_array((self.n, self.n))
    192 
--> 193         _compare_dimensions(A, [S], "row", "row", "A", "S")
    194         _compare_dimensions(B, [S], "row", "column", "B", "S")
    195 

~/projects/graspologic/graspologic/match/solver.py in _compare_dimensions(A, B, dimension_A, dimension_B, name1, name2)
    686             f"`{name2}` number of {dimension_B}s."
    687         )
--> 688         raise ValueError(msg)
    689 
    690 

ValueError: Input matrix/matrices `A` number of rows must match `S` number of rows.
```

## Example Code
```python
from graspologic.simulations import er_np
from graspologic.match import graph_match
import numpy as np
adj_l = er_np(49, 0.2)
adj_r = er_np(51, 0.3)
sim = np.zeros((49,51))
graph_match(adj_l, adj_r, S = sim)

```


## Your Environment
* Python version: 3.9.7
* graspologic version:1.0.0

## Additional Details
It's due to the fact that padding of A and B happens before checking dimensions of A and B vs. S.



Discussion:

Resolving patch:
diff --git a/graspologic/match/solver.py b/graspologic/match/solver.py
--- a/graspologic/match/solver.py
+++ b/graspologic/match/solver.py
@@ -169,6 +169,9 @@ def __init__(
         _compare_dimensions(B, AB, "row", "column", "B", "AB")
         _compare_dimensions(A, BA, "row", "column", "A", "BA")
         _compare_dimensions(B, BA, "row", "row", "B", "BA")
+        if S is not None:
+            _compare_dimensions(A, [S], "row", "row", "A", "S")
+            _compare_dimensions(B, [S], "column", "column", "B", "S")
 
         # padding for unequally sized inputs
         if self.n_A != self.n_B:
@@ -189,9 +192,11 @@ def __init__(
         # check for similarity term
         if S is None:
             S = csr_array((self.n, self.n))
+        elif self.padded:
+            S = _adj_pad(S, n_padded=self.n, method="naive")
 
         _compare_dimensions(A, [S], "row", "row", "A", "S")
-        _compare_dimensions(B, [S], "row", "column", "B", "S")
+        _compare_dimensions(B, [S], "column", "column", "B", "S")
 
         self.A = A
         self.B = B
@@ -643,9 +648,7 @@ def _multilayer_adj_pad(
         return new_matrices
 
 
-def _adj_pad(
-    matrix: AdjacencyMatrix, n_padded: Int, method: PaddingType
-) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
+def _adj_pad(matrix: AdjacencyMatrix, n_padded: Int, method: PaddingType) -> np.ndarray:
     if isinstance(matrix, (csr_matrix, csr_array)) and (method == "adopted"):
         msg = (
             "Using adopted padding method with a sparse adjacency representation; this "


Test patch:
diff --git a/tests/test_match.py b/tests/test_match.py
--- a/tests/test_match.py
+++ b/tests/test_match.py
@@ -287,3 +287,18 @@ def test_similarity_term(self):
             ).mean() / n_sims
 
         self.assertTrue(mean_match_ratio >= 0.999)
+
+    def test_similatiry_padded(self):
+        np.random.seed(88)
+        A = np.random.rand(10, 10)
+        B = np.random.rand(11, 11)
+        S = np.eye(10, 11) * 10
+
+        _, perm_B, _, misc = graph_match(A, B, S=S)
+        self.assertEqual((perm_B == np.arange(10)).mean(), 1.0)
+
+        # want to make sure obj func value is the same as if we hadn't padded S,
+        # should be since we use naive padding only
+        score = misc[0]["score"]
+        out_score = np.sum(A * B[perm_B][:, perm_B]) + np.trace(S[:, perm_B])
+        self.assertEqual(score, out_score)