Esempio n. 1
0
def test_orthogonal_procrustes():
    np.random.seed(1234)
    for m, n in ((6, 4), (4, 4), (4, 6)):
        # Sample a random target matrix.
        B = np.random.randn(m, n)
        # Sample a random orthogonal matrix
        # by computing eigh of a sampled symmetric matrix.
        X = np.random.randn(n, n)
        w, V = eigh(X.T + X)
        assert_allclose(inv(V), V.T)
        # Compute a matrix with a known orthogonal transformation that gives B.
        A = np.dot(B, V.T)
        # Check that an orthogonal transformation from A to B can be recovered.
        R, s = orthogonal_procrustes(A, B)
        assert_allclose(inv(R), R.T)
        assert_allclose(A.dot(R), B)
        # Create a perturbed input matrix.
        A_perturbed = A + 1e-2 * np.random.randn(m, n)
        # Check that the orthogonal procrustes function can find an orthogonal
        # transformation that is better than the orthogonal transformation
        # computed from the original input matrix.
        R_prime, s = orthogonal_procrustes(A_perturbed, B)
        assert_allclose(inv(R_prime), R_prime.T)
        # Compute the naive and optimal transformations of the perturbed input.
        naive_approx = A_perturbed.dot(R)
        optim_approx = A_perturbed.dot(R_prime)
        # Compute the Frobenius norm errors of the matrix approximations.
        naive_approx_error = norm(naive_approx - B, ord='fro')
        optim_approx_error = norm(optim_approx - B, ord='fro')
        # Check that the orthogonal Procrustes approximation is better.
        assert_array_less(optim_approx_error, naive_approx_error)
Esempio n. 2
0
def EM_aux(X, Y, alpha, Q, sigma, muy, sigmay, is_soft):
    """
    EM noise aware
    :param X: matrix 1
    :param Y: matrix 2
    :param alpha: percentage of clean pairs
    :param Q: transform matrix
    :param sigma: clean pairs variance
    :param muy: noisy pairs mean
    :param sigmay: noisy pair variance
    :param is_soft: true - soft EM, false - hard EM
    :return: transform matrix, alpha, clean indices, noisy indices
    """
    n, dim = X.shape
    threshold = 0.00001
    prev_alpha = -1
    j = -1
    while abs(alpha - prev_alpha) > threshold:
        j = j + 1
        prev_alpha = alpha
        # E-step
        ws = [0] * n
        nom = [0] * n
        sup = [0] * n
        nom[:] = np.log(alpha) + P(Y, dim, np.dot(X, Q), sigma)
        sup[:] = np.log((1 - alpha)) + P(Y, dim, muy, sigmay)
        m = max(nom)
        ws[:] = np.exp(nom[:] - m) / (np.exp(nom[:] - m) + np.exp(sup[:] - m))
        ws = np.where(np.isnan(ws), 0, ws)
        # M-step
        if is_soft:
            sum_ws = float(sum(ws))
            alpha = sum_ws / float(n)
            Q, _ = orthogonal_procrustes(np.multiply(np.array(ws).reshape((n,1)),X), np.multiply(np.array(ws).reshape((n,1)),Y))
            sigma = sum(np.linalg.norm(np.dot(X[i, :], Q) - Y[i, :]) ** 2 * ws[i] for i in range(0,n)) / (sum_ws * dim)
            muy = sum(Y[i, :] * (1 - ws[i]) for i in range(0,n)) / (n-sum_ws)
            sigmay = sum(np.linalg.norm(muy - Y[i, :]) ** 2 * (1 - ws[i]) for i in range(0,n)) / ((n-sum_ws) * dim)
        else: #hard EM
            t_indices = np.where(np.asarray(ws) >= 0.5)[0]
            f_indices = np.where(np.asarray(ws) < 0.5)[0]
            assert (len(t_indices) > 0)
            assert (len(f_indices) > 0)
            X_clean = np.squeeze(X[[t_indices], :])
            Y_clean = np.squeeze(Y[[t_indices], :])
            alpha = float(len(t_indices)) / float(n)
            Q, _ = orthogonal_procrustes(X_clean, Y_clean)
            sigma = sum(np.linalg.norm(np.dot(X[i, :], Q) - Y[i, :]) ** 2 for i in t_indices) / (len(t_indices) * dim)
            muy = sum(Y[i, :] for i in f_indices) / len(f_indices)
            sigmay = sum(np.linalg.norm(muy - Y[i, :]) ** 2 for i in f_indices) / (len(f_indices) * dim)

        # print('iter:', j, 'alpha:', round(alpha,3), 'sigma:', round(sigma,3), 'sigmay', round(sigmay,3))

    t_indices = np.where(np.asarray(ws) >= 0.5)[0]
    f_indices = np.where(np.asarray(ws) < 0.5)[0]
    return np.asarray(Q), alpha, t_indices, f_indices
Esempio n. 3
0
def test_orthogonal_procrustes_scale_invariance():
    np.random.seed(1234)
    m, n = 4, 3
    for i in range(3):
        A_orig = np.random.randn(m, n)
        B_orig = np.random.randn(m, n)
        R_orig, s = orthogonal_procrustes(A_orig, B_orig)
        for A_scale in np.square(np.random.randn(3)):
            for B_scale in np.square(np.random.randn(3)):
                R, s = orthogonal_procrustes(A_orig * A_scale, B_orig * B_scale)
                assert_allclose(R, R_orig)
Esempio n. 4
0
def test_orthogonal_procrustes_scale_invariance():
    np.random.seed(1234)
    m, n = 4, 3
    for i in range(3):
        A_orig = np.random.randn(m, n)
        B_orig = np.random.randn(m, n)
        R_orig, s = orthogonal_procrustes(A_orig, B_orig)
        for A_scale in np.square(np.random.randn(3)):
            for B_scale in np.square(np.random.randn(3)):
                R, s = orthogonal_procrustes(A_orig * A_scale, B_orig * B_scale)
                assert_allclose(R, R_orig)
Esempio n. 5
0
def test_orthogonal_procrustes_array_conversion():
    np.random.seed(1234)
    for m, n in ((6, 4), (4, 4), (4, 6)):
        A_arr = np.random.randn(m, n)
        B_arr = np.random.randn(m, n)
        As = (A_arr, A_arr.tolist(), np.matrix(A_arr))
        Bs = (B_arr, B_arr.tolist(), np.matrix(B_arr))
        R_arr, s = orthogonal_procrustes(A_arr, B_arr)
        AR_arr = A_arr.dot(R_arr)
        for A, B in product(As, Bs):
            R, s = orthogonal_procrustes(A, B)
            AR = A_arr.dot(R)
            assert_allclose(AR, AR_arr)
Esempio n. 6
0
def PointCrustes(mtx1,mtx2):

    # translate all the data to the origin
    mu1=np.mean(mtx1, 0)
    mu2=np.mean(mtx2, 0)
    mtx1t =mtx1 - mu1
    mtx2t =mtx2 - mu2

    norm1 = np.linalg.norm(mtx1t)
    norm2 = np.linalg.norm(mtx2t)



    if norm1 == 0 or norm2 == 0:
        raise ValueError("Input matrices must contain >1 unique points")

    # change scaling of data (in rows) such that trace(mtx*mtx') = 1
    mtx1t /= norm1
    mtx2t /= norm2

    # transform mtx2 to minimize disparity
    R, s = orthogonal_procrustes(mtx1t, mtx2t)

    
    print("Procs Point")
    print(mu2)
    print(s)
    print(mu1)
    print(R)

    t = mu2-s*np.dot(R.T,mu1) #or mu2-np.dot(mu1, R)

    return R,t
Esempio n. 7
0
    def sem_disp(self, other, average=True, align=True, n=-1):
        """
        Computes the semantic displacement measure between the current instance and another Embedding.

        :param other: other Embedding object to compare
        :param average: (optional) average over the cosine distance between 'n' word vectors from
            two embeddings.
        :param align: (optional) bool value, use orthogonal Procrustes to align the current instance
            to the other Embedding prior to computing the measure.
        :param n: (optional) int value representing the number of words to use to compute the distance,
            where the words are assumed to be sorted by frequency in the current instance.

        :return: float distance
        """
        if not isinstance(other, Embedding):
            raise ValueError("Only Embedding objects supported.")
        emb1, emb2 = self.get_subembeds_same_vocab(other, n=n)
        if align:
            R, _ = orthogonal_procrustes(emb1, emb2)
            emb1 = np.dot(emb1, R)
        rcos_dist = np.array([
            spatial.distance.cosine(emb1[k], emb2[k])
            for k in range(emb2.shape[0])
        ])
        if average:
            rcos_dist = np.nanmean(rcos_dist, axis=0)
        return rcos_dist
Esempio n. 8
0
def get_rotations_realistic(era_axis, JD_INIT, array_location):
    p1 = np.array([1.0, 0.0, 0.0])
    p2 = np.array([0.0, 1.0, 0.0])
    p3 = np.array([0.0, 0.0, 1.0])

    jd_axis = map(lambda era: era2JD(era, JD_INIT), era_axis)

    JDs = Time(jd_axis, format="jd", scale="ut1")

    rotations_axis = np.zeros((JDs.size, 3, 3), dtype=np.float)
    for i in range(JDs.size):
        gcrs_axes = coord.SkyCoord(
            x=p1 * units.one,
            y=p2 * units.one,
            z=p3 * units.one,
            location=array_location,
            obstime=JDs[i],
            frame="gcrs",
            representation="cartesian",
        )

        transf_gcrs_axes = gcrs_axes.transform_to("altaz")
        M = np.zeros((3, 3))
        M[:, 0] = transf_gcrs_axes.cartesian.x.value
        M[:, 1] = transf_gcrs_axes.cartesian.y.value
        M[:, 2] = transf_gcrs_axes.cartesian.z.value

        # the matrix M is generally not an orthogonal matrix
        # to working precision, but it is very close. This procedure
        # finds the orthogonal matrix that is nearest to M,
        # as measured by the Frobenius norm.
        Rt, _ = linalg.orthogonal_procrustes(M, np.eye(3))
        rotations_axis[i] = np.transpose(Rt)

    return rotations_axis, JDs.jd
Esempio n. 9
0
def createTransformationMatrix(modelA, modelB):
    # initialize the matrices
    labels = []
    A = []
    B = []
    # keep the common words and add them to the matrices
    nb_words_A = len(modelA.index2word)
    nb_words_B = len(modelA.index2word)
    for i in range(0, nb_words_A):
        word = modelA.index2word[i]
        if word in modelB.index2word:
            # add the word to the matrices (and the labels)
            labels.append(word)
            A.append(modelA[word])
            B.append(modelB[word])
    # create the transformation matrix
    TransM, _ = orthogonal_procrustes(np.asarray(A),
                                      np.asarray(B),
                                      check_finite=False)

    # apply the transofrmation matrix to the first model matrix
    Z = np.matmul(A, TransM)

    # create the 2 models manually (by first creating a text file and reading it).
    # it would be most efficient not to have to store the results on files like this.
    constructModel(np.asarray(Z), labels, "tmpZ.model.txt")
    constructModel(np.asarray(B), labels, "tmpB.model.txt")

    modelZ_ = Word2Vec.load_word2vec_format('tmpZ.model.txt', binary=False)
    modelB_ = Word2Vec.load_word2vec_format('tmpB.model.txt', binary=False)

    return modelZ_, modelB_
Esempio n. 10
0
def test_orthogonal_procrustes_skbio_example():
    # This transformation is also exact.
    # It uses translation, scaling, and reflection.
    #
    #   |
    #   | a
    #   | b
    #   | c d
    # --+---------
    #   |
    #   |       w
    #   |
    #   |       x
    #   |
    #   |   z   y
    #   |
    #
    A_orig = np.array([[4, -2], [4, -4], [4, -6], [2, -6]], dtype=float)
    B_orig = np.array([[1, 3], [1, 2], [1, 1], [2, 1]], dtype=float)
    B_standardized = np.array([
        [-0.13363062, 0.6681531],
        [-0.13363062, 0.13363062],
        [-0.13363062, -0.40089186],
        [0.40089186, -0.40089186]])
    A, A_mu = _centered(A_orig)
    B, B_mu = _centered(B_orig)
    R, s = orthogonal_procrustes(A, B)
    scale = s / np.square(norm(A))
    B_approx = scale * np.dot(A, R) + B_mu
    assert_allclose(B_approx, B_orig)
    assert_allclose(B / norm(B), B_standardized)
Esempio n. 11
0
def unscaled_procrustes(reference, data):
    """Fit `data` to `reference` using procrustes analysis without scaling.
    Uses translation (mean-centering), reflection, and orthogonal rotation.

    Parameters:
        reference (array-like of shape (n_points, n_dim)): reference shape to
            fit `data` to
        data (array-like of shape (n_points, n_dim)): shape to align to
            `reference`

    Returns:
        reference_centered (np.ndarray of shape (n_points, n_dim)): 0-centered
            `reference` shape
        data_aligned (np.ndarray of shape (n_points, n_dim)): `data` aligned to
            the reference shape
    """
    # Convert inputs to np.ndarray types
    reference = np.array(reference, dtype=np.double)
    data = np.array(data, dtype=np.double)

    # Translate data to the origin
    reference_centered = reference - reference.mean(axis=0)
    data_centered = data - data.mean(axis=0)

    # Rotate / reflect data to match reference
    # transform mtx2 to minimize disparity
    R, _ = orthogonal_procrustes(data_centered, reference_centered)
    data_aligned = data_centered @ R

    return reference_centered, data_aligned
Esempio n. 12
0
def get_galactic_to_gcrs_rotation_matrix():
    x_c = np.array([1.0, 0, 0])  # unit vectors to be transformed by astropy
    y_c = np.array([0, 1.0, 0])
    z_c = np.array([0, 0, 1.0])

    axes_gcrs = coord.SkyCoord(x=x_c,
                               y=y_c,
                               z=z_c,
                               frame="gcrs",
                               representation="cartesian")
    axes_gal = axes_gcrs.transform_to("galactic")
    axes_gal.representation = "cartesian"

    M = np.zeros((3, 3))
    M[:, 0] = axes_gal.cartesian.x.value
    M[:, 1] = axes_gal.cartesian.y.value
    M[:, 2] = axes_gal.cartesian.z.value

    # the matrix M is generally not an orthogonal matrix
    # to working precision, but it is very close. This procedure
    # finds the orthogonal matrix that is nearest to M,
    # as measured by the Frobenius norm.
    Rt, _ = linalg.orthogonal_procrustes(M, np.eye(3))

    # The 3D rotation matrix that defines the coordinate transformation.
    R_g2gcrs = np.transpose(Rt)
    return R_g2gcrs
Esempio n. 13
0
def align(wv1,
          wv2,
          anchor_indices=None,
          anchor_words=None,
          anchor_top=None,
          anchor_bot=None,
          anchor_random=None,
          exclude={},
          method="procrustes"):
    """
    Implement OP alignment for a given set of landmarks.
    If no landmark is given, performs global alignment.
    Arguments:
        wv1 - WordVectors object to align to wv2
        wv2 - Target WordVectors. Will align wv1 to it.
        anchor_indices - (optional) uses word indices as landmarks
        anchor_words - (optional) uses words as landmarks
        exclude - set of words to exclude from alignment
        method - Alignment objective. Currently only supports orthogonal procrustes.
    """
    if anchor_top is not None:
        v1 = [
            wv1.vectors[i] for i in range(anchor_top)
            if wv1.words[i] not in exclude
        ]
        v2 = [
            wv2.vectors[i] for i in range(anchor_top)
            if wv2.words[i] not in exclude
        ]
    elif anchor_bot is not None:
        v1 = [
            wv1.vectors[-i] for i in range(anchor_bot)
            if wv1.words[i] not in exclude
        ]
        v2 = [
            wv2.vectors[-i] for i in range(anchor_bot)
            if wv2.words[i] not in exclude
        ]
    elif anchor_random is not None:
        anchors = np.random.choice(range(len(wv1.vectors)), anchor_random)
        v1 = [wv1.vectors[i] for i in anchors if wv1.words[i] not in exclude]
        v2 = [wv2.vectors[i] for i in anchors if wv2.words[i] not in exclude]
    elif anchor_indices is not None:
        v1 = [wv1.vectors[i] for i in indices if wv1.words[i] not in exclude]
        v2 = [wv2.vectors[i] for i in indices if wv2.words[i] not in exclude]
    elif anchor_words is not None:
        v1 = [wv1[w] for w in anchor_words if w not in exclude]
        v2 = [wv2[w] for w in anchor_words if w not in exclude]
    else:  # just use all words
        v1 = [wv1[w] for w in wv1.words if w not in exclude]
        v2 = [wv2[w] for w in wv2.words if w not in exclude]
    v1 = np.array(v1)
    v2 = np.array(v2)
    if method == "procrustes":  # align with OP
        Q, _ = orthogonal_procrustes(v1, v2)

    wv1_ = WordVectors(words=wv1.words, vectors=np.dot(wv1.vectors, Q))

    return wv1_, wv2, Q
Esempio n. 14
0
 def update_rotation(self):
     """ Update the rotation matrix (self.R) based on the inlying refls """
     from scipy.linalg import orthogonal_procrustes
     misset, _ = orthogonal_procrustes(
         self.qobs,
         self.qpred * self.wav[:, None],
     )
     self.R = misset @ self.R
Esempio n. 15
0
def compute_rotated_similarity(early, later):
    R,_ = orthogonal_procrustes(early, later, check_finite=False)
    rotated = early @ R
    sims = cosine_similarity(rotated.to_numpy(), later.to_numpy())
    ret = list()
    for i in range(0, len(sims)):
        ret.append(sims[i][i])
    return ret
Esempio n. 16
0
    def _check_fit_on_synthetic_example(self, latent_dim: int, n_samples: int,
                                        n_variables: int, lr: float,
                                        n_batch_size: int, patience: int,
                                        n_epochs: int) -> None:
        # create a random ground-truth for W and b
        W = np.random.randn(latent_dim, n_variables)
        b = np.random.randn(n_variables)

        # generate data from the ground-truth model

        # step 1: sample the latent variables
        zs = np.random.randn(n_samples, latent_dim)
        # step 2: use the latent variables to generate the observations
        data = (
            # evaluate the probability vectors
            1. / (1. + np.exp(-(np.matmul(zs, W) + b)))
            # compare the probabilities to uniform random noise to
            # create the observations
            > np.random.rand(n_samples, n_variables)).astype(int)

        # create and fit the model
        model = traits.LatentTraitModel(latent_dim=latent_dim)
        model.fit(data,
                  lr=lr,
                  n_batch_size=n_batch_size,
                  patience=patience,
                  n_epochs=n_epochs,
                  device=th.device('cuda')
                  if th.cuda.is_available() else th.device('cpu'))

        # evaluate the parameter estimates

        W_hat = model.W_.numpy()
        # Since the parameters in a latent trait / factor analysis model
        # are only determined up to a rotation, we must align the
        # learned parameters with the ground-truth with a rotation.
        R, _ = orthogonal_procrustes(W_hat, W)
        W_hat = np.matmul(W_hat, R)

        b_hat = model.b_.numpy()

        # check that self.n_samples_ and self.n_variables_ were set
        # correctly
        self.assertEqual(model.n_samples_, n_samples)
        self.assertEqual(model.n_variables_, n_variables)

        # sanity-check that the learned weights give a better estimate
        # than the origin
        if latent_dim > 0:
            self.assertLess(np.mean((W - W_hat)**2), np.mean(W**2))
        self.assertLess(np.mean((b - b_hat)**2), np.mean(b**2))

        # check that the learned weights give good estimates for this
        # easy problem
        if latent_dim > 0:
            self.assertLess(np.mean((W - W_hat)**2), 7.5e-2)
        self.assertLess(np.mean((b - b_hat)**2), 7.5e-2)
Esempio n. 17
0
def test_scaled_procrustes_algorithmic():
    '''Test Scaled procrustes'''
    X = np.random.randn(10, 20)
    Y = np.zeros_like(X)
    R = np.eye(X.shape[1])
    R_test, _ = scaled_procrustes(X, Y)
    assert_array_almost_equal(R, R_test.toarray())

    '''Test if scaled_procrustes basis is orthogonal'''
    X = np.random.rand(3, 4)
    X = X - X.mean(axis=1, keepdims=True)

    Y = np.random.rand(3, 4)
    Y = Y - Y.mean(axis=1, keepdims=True)

    R, _ = scaled_procrustes(X.T, Y.T)
    assert_array_almost_equal(R.dot(R.T), np.eye(R.shape[0]))
    assert_array_almost_equal(R.T.dot(R), np.eye(R.shape[0]))

    ''' Test if it sticks to scipy scaled procrustes in a simple case'''
    X = np.random.rand(4, 4)
    Y = np.random.rand(4, 4)

    R, _ = scaled_procrustes(X, Y)
    R_s, _ = orthogonal_procrustes(Y, X)
    assert_array_almost_equal(R.T, R_s)

    '''Test that primal and dual give same results'''
    # number of samples n , number of voxels p
    n, p = 100, 20
    X = np.random.randn(n, p)
    Y = np.random.randn(n, p)
    R1, s1 = scaled_procrustes(X, Y, scaling=True, primal=True)
    R_s, _ = orthogonal_procrustes(Y, X)
    R2, s2 = scaled_procrustes(X, Y, scaling=True, primal=False)
    assert_array_almost_equal(R1, R2)
    assert_array_almost_equal(R2, R_s.T)
    n, p = 20, 100
    X = np.random.randn(n, p)
    Y = np.random.randn(n, p)
    R1, s1 = scaled_procrustes(X, Y, scaling=True, primal=True)
    R_s, _ = orthogonal_procrustes(Y, X)
    R2, s2 = scaled_procrustes(X, Y, scaling=True, primal=False)
    assert_array_almost_equal(s1 * X.dot(R1), s2 * X.dot(R2))
Esempio n. 18
0
def test_orthogonal_procrustes_stretched_example():
    # Try again with a target with a stretched y axis.
    A_orig = np.array([[-3, 3], [-2, 3], [-2, 2], [-3, 2]], dtype=float)
    B_orig = np.array([[3, 40], [1, 0], [3, -40], [5, 0]], dtype=float)
    A, A_mu = _centered(A_orig)
    B, B_mu = _centered(B_orig)
    R, s = orthogonal_procrustes(A, B)
    scale = s / np.square(norm(A))
    B_approx = scale * np.dot(A, R) + B_mu
    expected = np.array([[3, 21], [-18, 0], [3, -21], [24, 0]], dtype=float)
    assert_allclose(B_approx, expected, atol=1e-8)
    # Check disparity symmetry.
    expected_disparity = 0.4501246882793018
    AB_disparity = np.square(norm(B_approx - B_orig) / norm(B))
    assert_allclose(AB_disparity, expected_disparity)
    R, s = orthogonal_procrustes(B, A)
    scale = s / np.square(norm(B))
    A_approx = scale * np.dot(B, R) + A_mu
    BA_disparity = np.square(norm(A_approx - A_orig) / norm(A))
    assert_allclose(BA_disparity, expected_disparity)
Esempio n. 19
0
 def _optimize_rigid_pos_3d(self, recon_verts, tar_verts):
     tar_center = np.mean(tar_verts, axis=0)
     recon_center = np.mean(recon_verts, axis=0)
     tar_verts_centered = tar_verts - tar_center
     recon_verts_centered = recon_verts - recon_center
     scale_recon = np.linalg.norm(recon_verts_centered) / np.linalg.norm(
         tar_verts_centered)
     recon_verts_centered = recon_verts / scale_recon
     translate = tar_center
     rotation, _ = orthogonal_procrustes(tar_verts_centered,
                                         recon_verts_centered)
     return 1 / scale_recon, translate, rotation
Esempio n. 20
0
def test_orthogonal_procrustes_exact_example():
    # Check a small application.
    # It uses translation, scaling, reflection, and rotation.
    #
    #         |
    #   a  b  |
    #         |
    #   d  c  |        w
    #         |
    # --------+--- x ----- z ---
    #         |
    #         |        y
    #         |
    #
    A_orig = np.array([[-3, 3], [-2, 3], [-2, 2], [-3, 2]], dtype=float)
    B_orig = np.array([[3, 2], [1, 0], [3, -2], [5, 0]], dtype=float)
    A, A_mu = _centered(A_orig)
    B, B_mu = _centered(B_orig)
    R, s = orthogonal_procrustes(A, B)
    scale = s / np.square(norm(A))
    B_approx = scale * np.dot(A, R) + B_mu
    assert_allclose(B_approx, B_orig, atol=1e-8)
Esempio n. 21
0
def compute_optimal_rotation(L, L_true, scale=True):
        """
        Find a rotation matrix R such that F_inf.dot(R) ~= F_true
        :return:
        """
        from scipy.linalg import orthogonal_procrustes
        R = orthogonal_procrustes(L, L_true)[0]

        # Given R, find a scale such that Lp' = Lp*s is such that,
        # s = argmin_s y = (Lp * s - L)^T (Lp*s - L)
        #     d/ds y = 2 * (Lp * s - L)^T Lp = 0
        #            =>     Lp^T Lp *s - L^T Lp = 0
        #            =>     s = (L^T Lp) / (Lp^T Lp)
        #
        # Then roll s into R such that Lp' = Lp*s = L.dot(R)*s = L.dot(R')
        # for R' = R*s

        if scale:
            Lp = L.dot(R)
            s = (L_true*Lp).sum() / (Lp*Lp).sum()
            return R*s
        else:
            return R
Esempio n. 22
0
 def compute_optimal_rotation(self, F_true, lmbda_true):
     """
     Find a rotation matrix R such that F_inf * R ~= F_true
     :return:
     """
     # from sklearn.linear_model import LinearRegression
     # assert F_true.shape == (self.N, self.D), "F_true must be NxD"
     # F_inf = self.F
     #
     # # TODO: Scale by lambda in order to get the scaled rotation
     #
     # R = np.zeros((self.D, self.D))
     # for d in xrange(self.D):
     #     lr = LinearRegression(fit_intercept=False)
     #     R[:,d] = lr.fit(F_inf, F_true[:,d]).coef_
     #
     #     # TODO: Normalize this column of the rotation matrix
     #     R[:,d] /= np.linalg.norm(R[:,d])
     #
     from scipy.linalg import orthogonal_procrustes
     R = orthogonal_procrustes(self.F / np.sqrt(abs(self.lmbda[None, :])),
                               F_true / np.sqrt(abs(lmbda_true[None,:])))[0]
     return R
Esempio n. 23
0
def procrustes(data1, data2):
    r"""Procrustes analysis, a similarity test for two data sets.

    Each input matrix is a set of points or vectors (the rows of the matrix).
    The dimension of the space is the number of columns of each matrix. Given
    two identically sized matrices, procrustes standardizes both such that:

    - :math:`tr(AA^{T}) = 1`.

    - Both sets of points are centered around the origin.

    Procrustes ([1]_, [2]_) then applies the optimal transform to the second
    matrix (including scaling/dilation, rotations, and reflections) to minimize
    :math:`M^{2}=\sum(data1-data2)^{2}`, or the sum of the squares of the
    pointwise differences between the two input datasets.

    This function was not designed to handle datasets with different numbers of
    datapoints (rows).  If two data sets have different dimensionality
    (different number of columns), simply add columns of zeros to the smaller
    of the two.

    Parameters
    ----------
    data1 : array_like
        Matrix, n rows represent points in k (columns) space `data1` is the
        reference data, after it is standardised, the data from `data2` will be
        transformed to fit the pattern in `data1` (must have >1 unique points).
    data2 : array_like
        n rows of data in k space to be fit to `data1`.  Must be the  same
        shape ``(numrows, numcols)`` as data1 (must have >1 unique points).

    Returns
    -------
    mtx1 : array_like
        A standardized version of `data1`.
    mtx2 : array_like
        The orientation of `data2` that best fits `data1`. Centered, but not
        necessarily :math:`tr(AA^{T}) = 1`.
    disparity : float
        :math:`M^{2}` as defined above.

    Raises
    ------
    ValueError
        If the input arrays are not two-dimensional.
        If the shape of the input arrays is different.
        If the input arrays have zero columns or zero rows.

    See Also
    --------
    scipy.linalg.orthogonal_procrustes
    scipy.spatial.distance.directed_hausdorff : Another similarity test
      for two data sets

    Notes
    -----
    - The disparity should not depend on the order of the input matrices, but
      the output matrices will, as only the first output matrix is guaranteed
      to be scaled such that :math:`tr(AA^{T}) = 1`.

    - Duplicate data points are generally ok, duplicating a data point will
      increase its effect on the procrustes fit.

    - The disparity scales as the number of points per input matrix.

    References
    ----------
    .. [1] Krzanowski, W. J. (2000). "Principles of Multivariate analysis".
    .. [2] Gower, J. C. (1975). "Generalized procrustes analysis".

    Examples
    --------
    >>> from scipy.spatial import procrustes

    The matrix ``b`` is a rotated, shifted, scaled and mirrored version of
    ``a`` here:

    >>> a = np.array([[1, 3], [1, 2], [1, 1], [2, 1]], 'd')
    >>> b = np.array([[4, -2], [4, -4], [4, -6], [2, -6]], 'd')
    >>> mtx1, mtx2, disparity = procrustes(a, b)
    >>> round(disparity)
    0.0

    """
    mtx1 = np.array(data1, dtype=np.double, copy=True)
    mtx2 = np.array(data2, dtype=np.double, copy=True)

    if mtx1.ndim != 2 or mtx2.ndim != 2:
        raise ValueError("Input matrices must be two-dimensional")
    if mtx1.shape != mtx2.shape:
        raise ValueError("Input matrices must be of same shape")
    if mtx1.size == 0:
        raise ValueError("Input matrices must be >0 rows and >0 cols")

    # translate all the data to the origin
    mtx1 -= np.mean(mtx1, 0)
    mtx2 -= np.mean(mtx2, 0)

    norm1 = np.linalg.norm(mtx1)
    norm2 = np.linalg.norm(mtx2)

    if norm1 == 0 or norm2 == 0:
        raise ValueError("Input matrices must contain >1 unique points")

    # change scaling of data (in rows) such that trace(mtx*mtx') = 1
    mtx1 /= norm1
    mtx2 /= norm2

    # transform mtx2 to minimize disparity
    R, s = orthogonal_procrustes(mtx1, mtx2)
    mtx2 = np.dot(mtx2, R.T) * s

    # measure the dissimilarity between the two datasets
    disparity = np.sum(np.square(mtx1 - mtx2))

    return mtx1, mtx2, disparity