From f9409ed8f32b9595c3c542b2d2a12415604b2ec5 Mon Sep 17 00:00:00 2001 From: BalashovK Date: Sat, 25 Mar 2023 19:55:28 -0700 Subject: [PATCH 1/3] Added: complex, real, imag, angle --- src/TensorFlowNET.Core/APIs/tf.complex.cs | 26 ++++ src/TensorFlowNET.Core/APIs/tf.math.cs | 14 +- src/TensorFlowNET.Core/Operations/gen_ops.cs | 43 ++---- src/TensorFlowNET.Core/Operations/math_ops.cs | 6 +- .../ComplexTest.cs | 133 ++++++++++++++++++ .../TensorFlowNET.Graph.UnitTest.csproj | 1 + 6 files changed, 184 insertions(+), 39 deletions(-) create mode 100644 src/TensorFlowNET.Core/APIs/tf.complex.cs create mode 100644 test/TensorFlowNET.Graph.UnitTest/ComplexTest.cs diff --git a/src/TensorFlowNET.Core/APIs/tf.complex.cs b/src/TensorFlowNET.Core/APIs/tf.complex.cs new file mode 100644 index 000000000..7a816cce5 --- /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 c7aa46704..73de70a6e 100644 --- a/src/TensorFlowNET.Core/APIs/tf.math.cs +++ b/src/TensorFlowNET.Core/APIs/tf.math.cs @@ -57,7 +57,7 @@ public Tensor softplus(Tensor features, string name = null) 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 @@ public Tensor in_top_k(Tensor predictions, Tensor targets, int k, string name = 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 @@ public Tensor reduce_prod(Tensor input_tensor, Axis? axis = null, bool keepdims 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 26a9b5be8..c0d0c5a61 100644 --- a/src/TensorFlowNET.Core/Operations/gen_ops.cs +++ b/src/TensorFlowNET.Core/Operations/gen_ops.cs @@ -730,12 +730,7 @@ public static (Tensor sampled_candidates, Tensor true_expected_count, Tensor sam /// 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 @@ public static Tensor compare_and_bitpack(Tensor input, Tensor threshold, string /// 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 @@ public static Tensor complex(Tensor real, Tensor imag, TF_DataType? Tout = null, /// 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 @@ public static Tensor configure_distributed_t_p_u(string embedding_config = null, /// 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 @@ public static Tensor igammac(Tensor a, Tensor x, string name = "Igammac") /// 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 @@ public static Tensor reader_serialize_state_v2(Tensor reader_handle, string name /// 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 36f7db794..a89e7a22c 100644 --- a/src/TensorFlowNET.Core/Operations/math_ops.cs +++ b/src/TensorFlowNET.Core/Operations/math_ops.cs @@ -20,6 +20,7 @@ using System.Linq; using Tensorflow.Framework; using static Tensorflow.Binding; +using Tensorflow.Operations; namespace Tensorflow { @@ -35,8 +36,9 @@ public static Tensor abs(Tensor x, string name = null) 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 000000000..c9b05e614 --- /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 7f6f3c670..6762e6035 100644 --- a/test/TensorFlowNET.Graph.UnitTest/TensorFlowNET.Graph.UnitTest.csproj +++ b/test/TensorFlowNET.Graph.UnitTest/TensorFlowNET.Graph.UnitTest.csproj @@ -36,6 +36,7 @@ + From 1a62163257042aa628e5f8f55ca59c33a4aff1ef Mon Sep 17 00:00:00 2001 From: BalashovK Date: Mon, 27 Mar 2023 12:51:57 -0700 Subject: [PATCH 2/3] Complex moved into tf.math --- src/TensorFlowNET.Core/APIs/tf.complex.cs | 26 ----------------------- src/TensorFlowNET.Core/APIs/tf.math.cs | 4 +++- 2 files changed, 3 insertions(+), 27 deletions(-) delete mode 100644 src/TensorFlowNET.Core/APIs/tf.complex.cs diff --git a/src/TensorFlowNET.Core/APIs/tf.complex.cs b/src/TensorFlowNET.Core/APIs/tf.complex.cs deleted file mode 100644 index 7a816cce5..000000000 --- a/src/TensorFlowNET.Core/APIs/tf.complex.cs +++ /dev/null @@ -1,26 +0,0 @@ -/***************************************************************************** - 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 73de70a6e..83653c8bb 100644 --- a/src/TensorFlowNET.Core/APIs/tf.math.cs +++ b/src/TensorFlowNET.Core/APIs/tf.math.cs @@ -1,5 +1,5 @@ /***************************************************************************** - Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. + Copyright 2023 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. @@ -595,5 +595,7 @@ public Tensor square(Tensor x, string name = null) => gen_math_ops.square(x, name: name); public Tensor squared_difference(Tensor x, Tensor y, string name = null) => gen_math_ops.squared_difference(x: x, y: y, name: name); + public Tensor complex(Tensor real, Tensor imag, Tensorflow.TF_DataType? dtype = null, + string name = null) => gen_ops.complex(real, imag, dtype, name); } } From febba7b354f2024526349f53f9525abb06b3c985 Mon Sep 17 00:00:00 2001 From: BalashovK Date: Sat, 1 Apr 2023 14:08:37 -0700 Subject: [PATCH 3/3] Added support for Complex128 and unit tests for it. --- src/TensorFlowNET.Core/Operations/gen_ops.cs | 29 ++++--- .../ComplexTest.cs | 79 +++++++++++++++++-- 2 files changed, 93 insertions(+), 15 deletions(-) diff --git a/src/TensorFlowNET.Core/Operations/gen_ops.cs b/src/TensorFlowNET.Core/Operations/gen_ops.cs index c0d0c5a61..c9693f055 100644 --- a/src/TensorFlowNET.Core/Operations/gen_ops.cs +++ b/src/TensorFlowNET.Core/Operations/gen_ops.cs @@ -730,7 +730,7 @@ public static (Tensor sampled_candidates, Tensor true_expected_count, Tensor sam /// public static Tensor angle(Tensor input, TF_DataType? Tout = null, string name = "Angle") { - return tf.Context.ExecuteOp("Angle", name, new ExecuteOpArgs(new object[] { input })); + return tf.Context.ExecuteOp("Angle", name, new ExecuteOpArgs(input).SetAttributes(new { Tout = Tout })); } /// @@ -4971,13 +4971,16 @@ public static Tensor compare_and_bitpack(Tensor input, Tensor threshold, string /// tf.complex(real, imag) ==> [[2.25 + 4.75j], [3.25 + 5.75j]] /// /// - public static Tensor complex(Tensor real, Tensor imag, TF_DataType? Tout = null, string name = "Complex") + public static Tensor complex(Tensor real, Tensor imag, TF_DataType? a_Tout = null, string name = "Complex") { - 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 + TF_DataType Tin = real.GetDataType(); + if (a_Tout is null) + { + a_Tout = (Tin == TF_DataType.TF_DOUBLE)? TF_DataType.TF_COMPLEX128: TF_DataType.TF_COMPLEX64; + } + return tf.Context.ExecuteOp("Complex", name, new ExecuteOpArgs(real, imag).SetAttributes(new { T=Tin, Tout=a_Tout })); } - - /// /// Computes the complex absolute value of a tensor. /// @@ -4999,7 +5002,7 @@ public static Tensor complex(Tensor real, Tensor imag, TF_DataType? Tout = null, /// public static Tensor complex_abs(Tensor x, TF_DataType? Tout = null, string name = "ComplexAbs") { - return tf.Context.ExecuteOp("ComplexAbs", name, new ExecuteOpArgs(new object[] { x })); + return tf.Context.ExecuteOp("ComplexAbs", name, new ExecuteOpArgs(x).SetAttributes(new { Tout = Tout })); } /// @@ -13308,9 +13311,12 @@ public static Tensor igammac(Tensor a, Tensor x, string name = "Igammac") /// tf.imag(input) ==> [4.75, 5.75] /// /// - public static Tensor imag(Tensor input, TF_DataType? Tout = null, string name = "Imag") + public static Tensor imag(Tensor input, TF_DataType? a_Tout = null, string name = "Imag") { - return tf.Context.ExecuteOp("Imag", name, new ExecuteOpArgs(new object[] { input })); + TF_DataType Tin = input.GetDataType(); + return tf.Context.ExecuteOp("Imag", name, new ExecuteOpArgs(input).SetAttributes(new { T = Tin, Tout = a_Tout })); + + // return tf.Context.ExecuteOp("Imag", name, new ExecuteOpArgs(new object[] { input })); } /// @@ -23841,9 +23847,12 @@ public static Tensor reader_serialize_state_v2(Tensor reader_handle, string name /// tf.real(input) ==> [-2.25, 3.25] /// /// - public static Tensor real(Tensor input, TF_DataType? Tout = null, string name = "Real") + public static Tensor real(Tensor input, TF_DataType? a_Tout = null, string name = "Real") { - return tf.Context.ExecuteOp("Real", name, new ExecuteOpArgs(new object[] {input})); + TF_DataType Tin = input.GetDataType(); + return tf.Context.ExecuteOp("Real", name, new ExecuteOpArgs(input).SetAttributes(new { T = Tin, Tout = a_Tout })); + +// return tf.Context.ExecuteOp("Real", name, new ExecuteOpArgs(new object[] {input})); } /// diff --git a/test/TensorFlowNET.Graph.UnitTest/ComplexTest.cs b/test/TensorFlowNET.Graph.UnitTest/ComplexTest.cs index c9b05e614..a57ec9291 100644 --- a/test/TensorFlowNET.Graph.UnitTest/ComplexTest.cs +++ b/test/TensorFlowNET.Graph.UnitTest/ComplexTest.cs @@ -13,7 +13,8 @@ namespace TensorFlowNET.UnitTest.Basics [TestClass] public class ComplexTest : EagerModeTestBase { - [Ignore("Not working")] + // Tests for Complex128 + [TestMethod] public void complex128_basic() { @@ -23,7 +24,7 @@ public void complex128_basic() 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_complex = tf.complex(t_real, t_imag); Tensor t_real_result = tf.math.real(t_complex); Tensor t_imag_result = tf.math.imag(t_complex); @@ -34,9 +35,77 @@ public void complex128_basic() 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); + Assert.IsTrue(base.Equal(d_real_result, d_real)); + Assert.IsTrue(base.Equal(d_imag_result, d_imag)); + } + [TestMethod] + public void complex128_abs() + { + tf.enable_eager_execution(); + + double[] d_real = new double[] { -3.0, -5.0, 8.0, 7.0 }; + double[] d_imag = new double[] { -4.0, 12.0, -15.0, 24.0 }; + + double[] d_abs = new double[] { 5.0, 13.0, 17.0, 25.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); + + Tensor t_abs_result = tf.abs(t_complex); + + double[] d_abs_result = t_abs_result.numpy().ToArray(); + Assert.IsTrue(base.Equal(d_abs_result, d_abs)); + } + [TestMethod] + public void complex128_conj() + { + double[] d_real = new double[] { -3.0, -5.0, 8.0, 7.0 }; + double[] d_imag = new double[] { -4.0, 12.0, -15.0, 24.0 }; + + double[] d_real_expected = new double[] { -3.0, -5.0, 8.0, 7.0 }; + double[] d_imag_expected = new double[] { 4.0, -12.0, 15.0, -24.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_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(); + + double[] d_real_result = n_real_result.ToArray(); + double[] 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 complex128_angle() + { + double[] d_real = new double[] { 0.0, 1.0, -1.0, 0.0 }; + double[] d_imag = new double[] { 1.0, 0.0, -2.0, -3.0 }; + + double[] d_expected = new double[] { 1.5707963267948966, 0, -2.0344439357957027, -1.5707963267948966 }; + + 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_result = tf.math.angle(t_complex); + + NDArray n_result = t_result.numpy(); + + double[] d_result = n_result.ToArray(); + + Assert.IsTrue(base.Equal(d_result, d_expected)); } + + // Tests for Complex64 [TestMethod] public void complex64_basic() { @@ -47,7 +116,7 @@ public void complex64_basic() 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_complex = tf.complex(t_real, t_imag); Tensor t_real_result = tf.math.real(t_complex); Tensor t_imag_result = tf.math.imag(t_complex);