diff --git a/src/TensorFlowNET.Core/APIs/tf.complex.cs b/src/TensorFlowNET.Core/APIs/tf.complex.cs
new file mode 100644
index 00000000..7a816cce
--- /dev/null
+++ b/src/TensorFlowNET.Core/APIs/tf.complex.cs
@@ -0,0 +1,26 @@
+/*****************************************************************************
+ Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+******************************************************************************/
+
+using Tensorflow.Operations;
+
+namespace Tensorflow
+{
+ public partial class tensorflow
+ {
+ public Tensor complex(Tensor real, Tensor imag, Tensorflow.TF_DataType? dtype = null,
+ string name = null) => gen_ops.complex(real, imag, dtype, name);
+ }
+}
diff --git a/src/TensorFlowNET.Core/APIs/tf.math.cs b/src/TensorFlowNET.Core/APIs/tf.math.cs
index c7aa4670..73de70a6 100644
--- a/src/TensorFlowNET.Core/APIs/tf.math.cs
+++ b/src/TensorFlowNET.Core/APIs/tf.math.cs
@@ -57,7 +57,7 @@ namespace Tensorflow
public Tensor tanh(Tensor x, string name = null)
=> math_ops.tanh(x, name: name);
-
+
///
/// Finds values and indices of the `k` largest entries for the last dimension.
///
@@ -93,6 +93,16 @@ namespace Tensorflow
bool binary_output = false)
=> math_ops.bincount(arr, weights: weights, minlength: minlength, maxlength: maxlength,
dtype: dtype, name: name, axis: axis, binary_output: binary_output);
+
+ public Tensor real(Tensor x, string name = null)
+ => gen_ops.real(x, x.dtype.real_dtype(), name);
+ public Tensor imag(Tensor x, string name = null)
+ => gen_ops.imag(x, x.dtype.real_dtype(), name);
+
+ public Tensor conj(Tensor x, string name = null)
+ => gen_ops.conj(x, name);
+ public Tensor angle(Tensor x, string name = null)
+ => gen_ops.angle(x, x.dtype.real_dtype(), name);
}
public Tensor abs(Tensor x, string name = null)
@@ -537,7 +547,7 @@ namespace Tensorflow
public Tensor reduce_sum(Tensor input, Axis? axis = null, Axis? reduction_indices = null,
bool keepdims = false, string name = null)
{
- if(keepdims)
+ if (keepdims)
return math_ops.reduce_sum(input, axis: constant_op.constant(axis ?? reduction_indices), keepdims: keepdims, name: name);
else
return math_ops.reduce_sum(input, axis: constant_op.constant(axis ?? reduction_indices));
diff --git a/src/TensorFlowNET.Core/Operations/gen_ops.cs b/src/TensorFlowNET.Core/Operations/gen_ops.cs
index 26a9b5be..c0d0c5a6 100644
--- a/src/TensorFlowNET.Core/Operations/gen_ops.cs
+++ b/src/TensorFlowNET.Core/Operations/gen_ops.cs
@@ -730,12 +730,7 @@ namespace Tensorflow.Operations
///
public static Tensor angle(Tensor input, TF_DataType? Tout = null, string name = "Angle")
{
- var dict = new Dictionary();
- dict["input"] = input;
- if (Tout.HasValue)
- dict["Tout"] = Tout.Value;
- var op = tf.OpDefLib._apply_op_helper("Angle", name: name, keywords: dict);
- return op.output;
+ return tf.Context.ExecuteOp("Angle", name, new ExecuteOpArgs(new object[] { input }));
}
///
@@ -4978,15 +4973,11 @@ namespace Tensorflow.Operations
///
public static Tensor complex(Tensor real, Tensor imag, TF_DataType? Tout = null, string name = "Complex")
{
- var dict = new Dictionary();
- dict["real"] = real;
- dict["imag"] = imag;
- if (Tout.HasValue)
- dict["Tout"] = Tout.Value;
- var op = tf.OpDefLib._apply_op_helper("Complex", name: name, keywords: dict);
- return op.output;
+ return tf.Context.ExecuteOp("Complex", name, new ExecuteOpArgs(new object[] { real, imag })); // sorry, cannot pass Tout, so it only works with complex64. complex128 is not supported yet
}
+
+
///
/// Computes the complex absolute value of a tensor.
///
@@ -5008,12 +4999,7 @@ namespace Tensorflow.Operations
///
public static Tensor complex_abs(Tensor x, TF_DataType? Tout = null, string name = "ComplexAbs")
{
- var dict = new Dictionary();
- dict["x"] = x;
- if (Tout.HasValue)
- dict["Tout"] = Tout.Value;
- var op = tf.OpDefLib._apply_op_helper("ComplexAbs", name: name, keywords: dict);
- return op.output;
+ return tf.Context.ExecuteOp("ComplexAbs", name, new ExecuteOpArgs(new object[] { x }));
}
///
@@ -5313,10 +5299,7 @@ namespace Tensorflow.Operations
///
public static Tensor conj(Tensor input, string name = "Conj")
{
- var dict = new Dictionary();
- dict["input"] = input;
- var op = tf.OpDefLib._apply_op_helper("Conj", name: name, keywords: dict);
- return op.output;
+ return tf.Context.ExecuteOp("Conj", name, new ExecuteOpArgs(new object[] { input }));
}
///
@@ -13327,12 +13310,7 @@ namespace Tensorflow.Operations
///
public static Tensor imag(Tensor input, TF_DataType? Tout = null, string name = "Imag")
{
- var dict = new Dictionary();
- dict["input"] = input;
- if (Tout.HasValue)
- dict["Tout"] = Tout.Value;
- var op = tf.OpDefLib._apply_op_helper("Imag", name: name, keywords: dict);
- return op.output;
+ return tf.Context.ExecuteOp("Imag", name, new ExecuteOpArgs(new object[] { input }));
}
///
@@ -23865,12 +23843,7 @@ namespace Tensorflow.Operations
///
public static Tensor real(Tensor input, TF_DataType? Tout = null, string name = "Real")
{
- var dict = new Dictionary();
- dict["input"] = input;
- if (Tout.HasValue)
- dict["Tout"] = Tout.Value;
- var op = tf.OpDefLib._apply_op_helper("Real", name: name, keywords: dict);
- return op.output;
+ return tf.Context.ExecuteOp("Real", name, new ExecuteOpArgs(new object[] {input}));
}
///
diff --git a/src/TensorFlowNET.Core/Operations/math_ops.cs b/src/TensorFlowNET.Core/Operations/math_ops.cs
index 36f7db79..a89e7a22 100644
--- a/src/TensorFlowNET.Core/Operations/math_ops.cs
+++ b/src/TensorFlowNET.Core/Operations/math_ops.cs
@@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.Linq;
using Tensorflow.Framework;
using static Tensorflow.Binding;
+using Tensorflow.Operations;
namespace Tensorflow
{
@@ -35,8 +36,9 @@ namespace Tensorflow
name = scope;
x = ops.convert_to_tensor(x, name: "x");
if (x.dtype.is_complex())
- throw new NotImplementedException("math_ops.abs for dtype.is_complex");
- //return gen_math_ops.complex_abs(x, Tout: x.dtype.real_dtype, name: name);
+ {
+ return gen_ops.complex_abs(x, Tout: x.dtype.real_dtype(), name: name);
+ }
return gen_math_ops._abs(x, name: name);
});
}
diff --git a/test/TensorFlowNET.Graph.UnitTest/ComplexTest.cs b/test/TensorFlowNET.Graph.UnitTest/ComplexTest.cs
new file mode 100644
index 00000000..c9b05e61
--- /dev/null
+++ b/test/TensorFlowNET.Graph.UnitTest/ComplexTest.cs
@@ -0,0 +1,133 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using Tensorflow.NumPy;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Tensorflow;
+using static Tensorflow.Binding;
+using Buffer = Tensorflow.Buffer;
+using TensorFlowNET.Keras.UnitTest;
+
+namespace TensorFlowNET.UnitTest.Basics
+{
+ [TestClass]
+ public class ComplexTest : EagerModeTestBase
+ {
+ [Ignore("Not working")]
+ [TestMethod]
+ public void complex128_basic()
+ {
+ double[] d_real = new double[] { 1.0, 2.0, 3.0, 4.0 };
+ double[] d_imag = new double[] { -1.0, -3.0, 5.0, 7.0 };
+
+ Tensor t_real = tf.constant(d_real, dtype:TF_DataType.TF_DOUBLE);
+ Tensor t_imag = tf.constant(d_imag, dtype: TF_DataType.TF_DOUBLE);
+
+ Tensor t_complex = tf.complex(t_real, t_imag, TF_DataType.TF_COMPLEX128);
+
+ Tensor t_real_result = tf.math.real(t_complex);
+ Tensor t_imag_result = tf.math.imag(t_complex);
+
+ NDArray n_real_result = t_real_result.numpy();
+ NDArray n_imag_result = t_imag_result.numpy();
+
+ double[] d_real_result =n_real_result.ToArray();
+ double[] d_imag_result = n_imag_result.ToArray();
+
+ Assert.AreEqual(d_real_result, d_real);
+ Assert.AreEqual(d_imag_result, d_imag);
+ }
+ [TestMethod]
+ public void complex64_basic()
+ {
+ tf.init_scope();
+ float[] d_real = new float[] { 1.0f, 2.0f, 3.0f, 4.0f };
+ float[] d_imag = new float[] { -1.0f, -3.0f, 5.0f, 7.0f };
+
+ Tensor t_real = tf.constant(d_real, dtype: TF_DataType.TF_FLOAT);
+ Tensor t_imag = tf.constant(d_imag, dtype: TF_DataType.TF_FLOAT);
+
+ Tensor t_complex = tf.complex(t_real, t_imag, TF_DataType.TF_COMPLEX64);
+
+ Tensor t_real_result = tf.math.real(t_complex);
+ Tensor t_imag_result = tf.math.imag(t_complex);
+
+ // Convert the EagerTensors to NumPy arrays directly
+ float[] d_real_result = t_real_result.numpy().ToArray();
+ float[] d_imag_result = t_imag_result.numpy().ToArray();
+
+ Assert.IsTrue(base.Equal(d_real_result, d_real));
+ Assert.IsTrue(base.Equal(d_imag_result, d_imag));
+ }
+ [TestMethod]
+ public void complex64_abs()
+ {
+ tf.enable_eager_execution();
+
+ float[] d_real = new float[] { -3.0f, -5.0f, 8.0f, 7.0f };
+ float[] d_imag = new float[] { -4.0f, 12.0f, -15.0f, 24.0f };
+
+ float[] d_abs = new float[] { 5.0f, 13.0f, 17.0f, 25.0f };
+
+ Tensor t_real = tf.constant(d_real, dtype: TF_DataType.TF_FLOAT);
+ Tensor t_imag = tf.constant(d_imag, dtype: TF_DataType.TF_FLOAT);
+
+ Tensor t_complex = tf.complex(t_real, t_imag, TF_DataType.TF_COMPLEX64);
+
+ Tensor t_abs_result = tf.abs(t_complex);
+
+ NDArray n_abs_result = t_abs_result.numpy();
+
+ float[] d_abs_result = n_abs_result.ToArray();
+ Assert.IsTrue(base.Equal(d_abs_result, d_abs));
+
+ }
+ [TestMethod]
+ public void complex64_conj()
+ {
+ float[] d_real = new float[] { -3.0f, -5.0f, 8.0f, 7.0f };
+ float[] d_imag = new float[] { -4.0f, 12.0f, -15.0f, 24.0f };
+
+ float[] d_real_expected = new float[] { -3.0f, -5.0f, 8.0f, 7.0f };
+ float[] d_imag_expected = new float[] { 4.0f, -12.0f, 15.0f, -24.0f };
+
+ Tensor t_real = tf.constant(d_real, dtype: TF_DataType.TF_FLOAT);
+ Tensor t_imag = tf.constant(d_imag, dtype: TF_DataType.TF_FLOAT);
+
+ Tensor t_complex = tf.complex(t_real, t_imag, TF_DataType.TF_COMPLEX64);
+
+ Tensor t_result = tf.math.conj(t_complex);
+
+ NDArray n_real_result = tf.math.real(t_result).numpy();
+ NDArray n_imag_result = tf.math.imag(t_result).numpy();
+
+ float[] d_real_result = n_real_result.ToArray();
+ float[] d_imag_result = n_imag_result.ToArray();
+
+ Assert.IsTrue(base.Equal(d_real_result, d_real_expected));
+ Assert.IsTrue(base.Equal(d_imag_result, d_imag_expected));
+
+ }
+ [TestMethod]
+ public void complex64_angle()
+ {
+ float[] d_real = new float[] { 0.0f, 1.0f, -1.0f, 0.0f };
+ float[] d_imag = new float[] { 1.0f, 0.0f, -2.0f, -3.0f };
+
+ float[] d_expected = new float[] { 1.5707964f, 0f, -2.0344439f, -1.5707964f };
+
+ Tensor t_real = tf.constant(d_real, dtype: TF_DataType.TF_FLOAT);
+ Tensor t_imag = tf.constant(d_imag, dtype: TF_DataType.TF_FLOAT);
+
+ Tensor t_complex = tf.complex(t_real, t_imag, TF_DataType.TF_COMPLEX64);
+
+ Tensor t_result = tf.math.angle(t_complex);
+
+ NDArray n_result = t_result.numpy();
+
+ float[] d_result = n_result.ToArray();
+
+ Assert.IsTrue(base.Equal(d_result, d_expected));
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/TensorFlowNET.Graph.UnitTest/TensorFlowNET.Graph.UnitTest.csproj b/test/TensorFlowNET.Graph.UnitTest/TensorFlowNET.Graph.UnitTest.csproj
index 7f6f3c67..6762e603 100644
--- a/test/TensorFlowNET.Graph.UnitTest/TensorFlowNET.Graph.UnitTest.csproj
+++ b/test/TensorFlowNET.Graph.UnitTest/TensorFlowNET.Graph.UnitTest.csproj
@@ -36,6 +36,7 @@
+