diff options
author | Ian Langmore <langmore@google.com> | 2017-04-06 10:23:44 -0800 |
---|---|---|
committer | TensorFlower Gardener <gardener@tensorflow.org> | 2017-04-06 11:46:17 -0700 |
commit | cf2d4ce2f861a1729cc7376107cbfd11b7bf8911 (patch) | |
tree | 1cdaa775f093a03923748f422777fa9dc797c29a | |
parent | b3ce6f3df62452fb2f19478076e1648b5862c758 (diff) |
matrix_adjoint added to contrib/linalg/linear_operator_util
Change: 152404828
4 files changed, 82 insertions, 1 deletions
diff --git a/tensorflow/contrib/linalg/python/kernel_tests/linear_operator_util_test.py b/tensorflow/contrib/linalg/python/kernel_tests/linear_operator_util_test.py index a06af336e7..f047f4b978 100644 --- a/tensorflow/contrib/linalg/python/kernel_tests/linear_operator_util_test.py +++ b/tensorflow/contrib/linalg/python/kernel_tests/linear_operator_util_test.py @@ -229,6 +229,29 @@ class MatmulWithBroadcastTest(test.TestCase): self.assertAllEqual(expected, result) +class MatrixAdjointTest(test.TestCase): + + def testNonBatchMatrix(self): + a = [[1, 2, 3j], [4, 5, -6j]] # Shape (2, 3) + expected = [[1, 4], [2, 5], [-3j, 6j]] # Shape (3, 2) + with self.test_session(): + a_adj = linear_operator_util.matrix_adjoint(a) + self.assertEqual((3, 2), a_adj.get_shape()) + self.assertAllClose(expected, a_adj.eval()) + + def testBatchMatrix(self): + matrix_0 = [[1j, 2, 3], [4, 5, 6]] + matrix_0_a = [[-1j, 4], [2, 5], [3, 6]] + matrix_1 = [[11, 22, 33], [44, 55, 66j]] + matrix_1_a = [[11, 44], [22, 55], [33, -66j]] + batch_matrix = [matrix_0, matrix_1] # Shape (2, 2, 3) + expected_adj = [matrix_0_a, matrix_1_a] # Shape (2, 3, 2) + with self.test_session(): + matrix_adj = linear_operator_util.matrix_adjoint(batch_matrix) + self.assertEqual((2, 3, 2), matrix_adj.get_shape()) + self.assertAllEqual(expected_adj, matrix_adj.eval()) + + class DomainDimensionStubOperator(object): def __init__(self, domain_dimension): diff --git a/tensorflow/contrib/linalg/python/ops/linear_operator_util.py b/tensorflow/contrib/linalg/python/ops/linear_operator_util.py index a52a235677..9f8cb23169 100644 --- a/tensorflow/contrib/linalg/python/ops/linear_operator_util.py +++ b/tensorflow/contrib/linalg/python/ops/linear_operator_util.py @@ -289,6 +289,53 @@ def matmul_with_broadcast(a, b_is_sparse=b_is_sparse) +def matrix_adjoint(a, name="matrix_adjoint"): + """Transposes last two dimensions of tensor `a`, and takes complex conjugate. + + If `a` is real valued, the result is equivalent to `matrix_transpose`. + + For example: + + ```python + # Matrix with no batch dimension. + # 'x' is [[1 2 3j] + # [4 5 -6j]] + tf.matrix_adjoint(x) ==> [[1 4] + [2 5] + [-3j 6j]] + + # Matrix with two batch dimensions. + # x.shape is [1, 2, 3, 4] + # tf.matrix_adjoint(x) is shape [1, 2, 4, 3] + ``` + + Note that `tf.matmul` provides kwargs allowing for adjoint of arguments. This + is done with minimal cost, and is preferable to using this function. E.g. + + ``` + # Good! Adjoint is taken at minimal additional cost. + tf.matmul(matrix, b, adjoint_b=True) + + # Inefficient! + tf.matmul(matrix, tf.matrix_adjoint(b)) + ``` + + Args: + a: A `Tensor` with `rank >= 2`. + name: A name for the operation (optional). + + Returns: + A batch matrix `Tensor` with same `dtype` as `a`. + + Raises: + ValueError: If `a` is determined statically to have `rank < 2`. + """ + with ops.name_scope(name, values=[a]): + a = ops.convert_to_tensor(a, name="a") + a_transpose = array_ops.matrix_transpose(a) + return math_ops.conj(a_transpose) + + def shape_tensor(shape, name=None): """Convert Tensor using default type, unless empty list or tuple.""" # Works just like random_ops._ShapeTensor. diff --git a/tensorflow/python/kernel_tests/linalg_ops_test.py b/tensorflow/python/kernel_tests/linalg_ops_test.py index ff299e6511..153d4ab662 100644 --- a/tensorflow/python/kernel_tests/linalg_ops_test.py +++ b/tensorflow/python/kernel_tests/linalg_ops_test.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== -"""Tests for tensorflow.python.ops.special_math_ops.""" +"""Tests for tensorflow.python.ops.linalg_ops.""" from __future__ import absolute_import from __future__ import division diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py index 60057b9ab1..5ebfe5b89f 100644 --- a/tensorflow/python/ops/array_ops.py +++ b/tensorflow/python/ops/array_ops.py @@ -1292,6 +1292,17 @@ def matrix_transpose(a, name="matrix_transpose"): # tf.matrix_transpose(x) is shape [1, 2, 4, 3] ``` + Note that `tf.matmul` provides kwargs allowing for transpose of arguments. + This is done with minimal cost, and is preferable to using this function. E.g. + + ``` + # Good! Transpose is taken at minimal additional cost. + tf.matmul(matrix, b, transpose_b=True) + + # Inefficient! + tf.matmul(matrix, tf.matrix_transpose(b)) + ``` + Args: a: A `Tensor` with `rank >= 2`. name: A name for the operation (optional). |