# Source code for evomap.mapping._cmds

```"""
Classic (SVD-based) Multidimensional Scaling, as proposed in:

Torgerson, W.S. Multidimensional scaling: I. Theory and method. Psychometrika 17, 401–419 (1952).

Thanks to Francis Song, from whom this implementation has borrowed. Source: http://www.nervouscomputer.com/hfs/cmdscale-in-python/
"""

from __future__ import division
import numpy as np

[docs]class CMDS():

def __init__(self, n_dims = 2):
self.n_dims = 2

[docs]    @staticmethod
def _cmdscale(D, n_dims):
"""
Classical multidimensional scaling (MDS)

Parameters
----------
D : (n, n) array
Symmetric distance matrix.

Returns
-------
Y : (n, p) array
Configuration matrix. Each column represents a dimension. Only the
p dimensions corresponding to positive eigenvalues of B are returned.
Note that each dimension is only determined up to an overall sign,
corresponding to a reflection.

e : (n,) array
Eigenvalues of B.

"""
# Number of points
n = len(D)

# Centering matrix
H = np.eye(n) - np.ones((n, n))/n

# YY^T
B = -H.dot(D**2).dot(H)/2

# Diagonalize
evals, evecs = np.linalg.eigh(B)

# Sort by eigenvalue in descending order
idx   = np.argsort(evals)[::-1]
evals = evals[idx]
evecs = evecs[:,idx]

# Compute the coordinates using positive-eigenvalued components only
w, = np.where(evals > 0)
L  = np.diag(np.sqrt(evals[w]))
V  = evecs[:,w]
Y  = V.dot(L)

return Y[:, :n_dims], evals[evals > 0]

[docs]    def fit(self, X):
self.Y_, _ = self._cmdscale(X, self.n_dims)
return self

[docs]    def fit_transform(self, X):
self.fit(X)
return self.Y_
```