Exemplo n.º 1
0
 def testWrongDimensions(self):
     # The input to self_adjoint_eig should be a tensor of
     # at least rank 2.
     scalar = constant_op.constant(1.)
     with self.assertRaises(ValueError):
         linalg_ops.eig(scalar)
     vector = constant_op.constant([1., 2.])
     with self.assertRaises(ValueError):
         linalg_ops.eig(vector)
Exemplo n.º 2
0
 def testConcurrentExecutesWithoutError(self):
     all_ops = []
     with self.session(use_gpu=True) as sess:
         for compute_v_ in True, False:
             matrix1 = random_ops.random_normal([5, 5], seed=42)
             matrix2 = random_ops.random_normal([5, 5], seed=42)
             if compute_v_:
                 e1, v1 = linalg_ops.eig(matrix1)
                 e2, v2 = linalg_ops.eig(matrix2)
                 all_ops += [e1, v1, e2, v2]
             else:
                 e1 = linalg_ops.eigvals(matrix1)
                 e2 = linalg_ops.eigvals(matrix2)
                 all_ops += [e1, e2]
         val = self.evaluate(all_ops)
         self.assertAllEqual(val[0], val[2])
         # The algorithm is slightly different for compute_v being True and False,
         # so require approximate equality only here.
         self.assertAllClose(val[2], val[4])
         self.assertAllEqual(val[4], val[5])
         self.assertAllEqual(val[1], val[3])
Exemplo n.º 3
0
def _EigGrad(op, grad_e, grad_v):
    """Gradient for Eig.

  Based on eq. 4.77 from paper by
  Christoph Boeddeker et al.
  https://arxiv.org/abs/1701.00392
  See also
  "Computation of eigenvalue and eigenvector derivatives
  for a general complex-valued eigensystem" by Nico van der Aa.
  As for now only distinct eigenvalue case is considered.
  """
    e = op.outputs[0]
    compute_v = op.get_attr("compute_v")
    # a = op.inputs[0], which satisfies
    # a[...,:,:] * v[...,:,i] = e[...,i] * v[...,i]
    with ops.control_dependencies([grad_e, grad_v]):
        if compute_v:
            v = op.outputs[1]
            vt = _linalg.adjoint(v)
            # Construct the matrix f(i,j) = (i != j ? 1 / (e_i - e_j) : 0).
            # Notice that because of the term involving f, the gradient becomes
            # infinite (or NaN in practice) when eigenvalues are not unique.
            # Mathematically this should not be surprising, since for (k-fold)
            # degenerate eigenvalues, the corresponding eigenvectors are only defined
            # up to arbitrary rotation in a (k-dimensional) subspace.
            f = array_ops.matrix_set_diag(
                _SafeReciprocal(
                    array_ops.expand_dims(e, -2) -
                    array_ops.expand_dims(e, -1)), array_ops.zeros_like(e))
            f = math_ops.conj(f)
            vgv = math_ops.matmul(vt, grad_v)
            mid = array_ops.matrix_diag(grad_e)
            diag_grad_part = array_ops.matrix_diag(
                array_ops.matrix_diag_part(
                    math_ops.cast(math_ops.real(vgv), vgv.dtype)))
            mid += f * (
                vgv - math_ops.matmul(math_ops.matmul(vt, v), diag_grad_part))
            # vt is formally invertible as long as the original matrix is
            # diagonalizable. However, in practice, vt may
            # be ill-conditioned when matrix original matrix is close to
            # non-diagonalizable one
            grad_a = linalg_ops.matrix_solve(vt, math_ops.matmul(mid, vt))
        else:
            _, v = linalg_ops.eig(op.inputs[0])
            vt = _linalg.adjoint(v)
            # vt is formally invertible as long as the original matrix is
            # diagonalizable. However, in practice, vt may
            # be ill-conditioned when matrix original matrix is close to
            # non-diagonalizable one
            grad_a = linalg_ops.matrix_solve(
                vt, math_ops.matmul(array_ops.matrix_diag(grad_e), vt))
        return math_ops.cast(grad_a, op.inputs[0].dtype)
Exemplo n.º 4
0
      def Compute(x):
        e, v = linalg_ops.eig(x)

        # We sort eigenvalues by e.real+e.imag to have consistent
        # order between runs
        b_dims = len(e.shape) - 1
        idx = sort_ops.argsort(math_ops.real(e) + math_ops.imag(e), axis=-1)
        e = array_ops.gather(e, idx, batch_dims=b_dims)
        v = array_ops.gather(v, idx, batch_dims=b_dims)

        # (complex) Eigenvectors are only unique up to an arbitrary phase
        # We normalize the vectors such that the first component has phase 0.
        top_rows = v[..., 0:1, :]
        angle = -math_ops.angle(top_rows)
        phase = math_ops.complex(math_ops.cos(angle), math_ops.sin(angle))
        v *= phase
        return e, v
Exemplo n.º 5
0
    def Test(self):
        np.random.seed(1)
        n = shape_[-1]
        batch_shape = shape_[:-2]
        np_dtype = dtype_.as_numpy_dtype

        def RandomInput():
            # Most matrices are diagonalizable
            a = np.random.uniform(low=-1.0, high=1.0,
                                  size=n * n).reshape([n, n]).astype(np_dtype)
            if dtype_.is_complex:
                a += 1j * np.random.uniform(low=-1.0, high=1.0, size=n *
                                            n).reshape([n, n]).astype(np_dtype)
            a = np.tile(a, batch_shape + (1, 1))
            return a

        if dtype_ in (dtypes_lib.float32, dtypes_lib.complex64):
            atol = 1e-4
        else:
            atol = 1e-12

        a = RandomInput()
        np_e, np_v = np.linalg.eig(a)
        with self.session():
            if compute_v_:
                tf_e, tf_v = linalg_ops.eig(constant_op.constant(a))

                # Check that V*diag(E)*V^(-1) is close to A.
                a_ev = math_ops.matmul(
                    math_ops.matmul(tf_v, array_ops.matrix_diag(tf_e)),
                    linalg_ops.matrix_inverse(tf_v))
                self.assertAllClose(self.evaluate(a_ev), a, atol=atol)

                # Compare to numpy.linalg.eig.
                CompareEigenDecompositions(self, np_e, np_v,
                                           self.evaluate(tf_e),
                                           self.evaluate(tf_v), atol)
            else:
                tf_e = linalg_ops.eigvals(constant_op.constant(a))
                self.assertAllClose(SortEigenValues(np_e),
                                    SortEigenValues(self.evaluate(tf_e)),
                                    atol=atol)