aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Ian Langmore <langmore@google.com>2017-04-06 10:23:44 -0800
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2017-04-06 11:46:17 -0700
commitcf2d4ce2f861a1729cc7376107cbfd11b7bf8911 (patch)
tree1cdaa775f093a03923748f422777fa9dc797c29a
parentb3ce6f3df62452fb2f19478076e1648b5862c758 (diff)
matrix_adjoint added to contrib/linalg/linear_operator_util
Change: 152404828
-rw-r--r--tensorflow/contrib/linalg/python/kernel_tests/linear_operator_util_test.py23
-rw-r--r--tensorflow/contrib/linalg/python/ops/linear_operator_util.py47
-rw-r--r--tensorflow/python/kernel_tests/linalg_ops_test.py2
-rw-r--r--tensorflow/python/ops/array_ops.py11
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).