From b7ccf3bc9ab05973b98c04966594daed85dd4b1f Mon Sep 17 00:00:00 2001 From: Eli Belash Date: Sun, 1 Sep 2019 22:45:22 +0300 Subject: [PATCH 1/5] dtypes.cs: Added missing type conversion --- src/TensorFlowNET.Core/Tensors/dtypes.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/TensorFlowNET.Core/Tensors/dtypes.cs b/src/TensorFlowNET.Core/Tensors/dtypes.cs index 37f1ca61..69ce7d79 100644 --- a/src/TensorFlowNET.Core/Tensors/dtypes.cs +++ b/src/TensorFlowNET.Core/Tensors/dtypes.cs @@ -45,6 +45,8 @@ namespace Tensorflow return typeof(bool); case TF_DataType.TF_UINT8: return typeof(byte); + case TF_DataType.TF_INT8: + return typeof(sbyte); case TF_DataType.TF_INT64: return typeof(long); case TF_DataType.TF_UINT64: From 94c8c6b5ada03da321f7c402ba79e60211e9e76f Mon Sep 17 00:00:00 2001 From: Eli Belash Date: Sun, 1 Sep 2019 23:16:34 +0300 Subject: [PATCH 2/5] Created TensorConverter --- .../Tensors/TensorConverter.cs | 285 ++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 src/TensorFlowNET.Core/Tensors/TensorConverter.cs diff --git a/src/TensorFlowNET.Core/Tensors/TensorConverter.cs b/src/TensorFlowNET.Core/Tensors/TensorConverter.cs new file mode 100644 index 00000000..dad051c6 --- /dev/null +++ b/src/TensorFlowNET.Core/Tensors/TensorConverter.cs @@ -0,0 +1,285 @@ +using System; +using System.Threading.Tasks; +using NumSharp; +using NumSharp.Backends; +using NumSharp.Utilities; + +namespace Tensorflow +{ + /// + /// Provides various methods to conversion between types and . + /// + public static class TensorConverter + { + /// + /// Convert given to . + /// + /// The ndarray to convert, can be regular, jagged or multi-dim array. + /// Convert to given before inserting it into a . + /// + public static Tensor ToTensor(NDArray nd, TF_DataType? astype = null) + { + return new Tensor(astype == null ? nd : nd.astype(astype.Value.as_numpy_typecode(), false)); + } + + /// + /// Convert given to . + /// + /// The ndarray to convert. + /// Convert to given before inserting it into a . + /// + public static Tensor ToTensor(NDArray nd, NPTypeCode? astype = null) + { + return new Tensor(astype == null ? nd : nd.astype(astype.Value, false)); + } + + /// + /// Convert given to . + /// + /// The array to convert, can be regular, jagged or multi-dim array. + /// Convert to given before inserting it into a . + /// + public static Tensor ToTensor(Array array, TF_DataType? astype = null) + { + if (array == null) throw new ArgumentNullException(nameof(array)); + var arrtype = array.ResolveElementType(); + + var astype_type = astype?.as_numpy_dtype() ?? arrtype; + if (astype_type == arrtype) + { + //no conversion required + if (astype == TF_DataType.TF_STRING) + { + throw new NotSupportedException(); //TODO! when string is fully implemented. + } + + if (astype == TF_DataType.TF_INT8) + { + if (array.Rank != 1 || array.GetType().GetElementType()?.IsArray == true) //is multidim or jagged + array = Arrays.Flatten(array); + + return new Tensor((sbyte[]) array); + } + + //is multidim or jagged, if so - use NDArrays constructor as it records shape. + if (array.Rank != 1 || array.GetType().GetElementType().IsArray) + return new Tensor(new NDArray(array)); + +#if _REGEN + #region Compute + switch (arrtype) + { + %foreach supported_dtypes,supported_dtypes_lowercase% + case NPTypeCode.#1: return new Tensor((#2[])arr); + % + default: + throw new NotSupportedException(); + } + #endregion +#else + + #region Compute + + switch (arrtype.GetTypeCode()) + { + case NPTypeCode.Boolean: return new Tensor((bool[]) array); + case NPTypeCode.Byte: return new Tensor((byte[]) array); + case NPTypeCode.Int16: return new Tensor((short[]) array); + case NPTypeCode.UInt16: return new Tensor((ushort[]) array); + case NPTypeCode.Int32: return new Tensor((int[]) array); + case NPTypeCode.UInt32: return new Tensor((uint[]) array); + case NPTypeCode.Int64: return new Tensor((long[]) array); + case NPTypeCode.UInt64: return new Tensor((ulong[]) array); + case NPTypeCode.Char: return new Tensor((char[]) array); + case NPTypeCode.Double: return new Tensor((double[]) array); + case NPTypeCode.Single: return new Tensor((float[]) array); + default: + throw new NotSupportedException(); + } + + #endregion + +#endif + } else + { + //conversion is required. + //by this point astype is not null. + + //flatten if required + if (array.Rank != 1 || array.GetType().GetElementType()?.IsArray == true) //is multidim or jagged + array = Arrays.Flatten(array); + + try + { + return ToTensor( + ArrayConvert.To(array, astype.Value.as_numpy_typecode()), + null + ); + } catch (NotSupportedException) + { + //handle dtypes not supported by ArrayConvert + var ret = Array.CreateInstance(astype_type, array.LongLength); + Parallel.For(0, ret.LongLength, i => ret.SetValue(Convert.ChangeType(array.GetValue(i), astype_type), i)); + return ToTensor(ret, null); + } + } + } + + /// + /// Convert given to . + /// + /// The constant scalar to convert + /// Convert to given before inserting it into a . + /// + public static Tensor ToTensor(T constant, TF_DataType? astype = null) where T : unmanaged + { + //was conversion requested? + if (astype == null) + { + //No conversion required + var constantType = typeof(T).as_dtype(); + if (constantType == TF_DataType.TF_INT8) + return new Tensor((sbyte) (object) constant); + + if (constantType == TF_DataType.TF_STRING) + return new Tensor((string) (object) constant); + +#if _REGEN + #region Compute + switch (InfoOf.NPTypeCode) + { + %foreach supported_dtypes,supported_dtypes_lowercase% + case NPTypeCode.#1: return new Tensor((#2)(object)constant); + % + default: + throw new NotSupportedException(); + } + #endregion +#else + + #region Compute + + switch (InfoOf.NPTypeCode) + { + case NPTypeCode.Boolean: return new Tensor((bool) (object) constant); + case NPTypeCode.Byte: return new Tensor((byte) (object) constant); + case NPTypeCode.Int16: return new Tensor((short) (object) constant); + case NPTypeCode.UInt16: return new Tensor((ushort) (object) constant); + case NPTypeCode.Int32: return new Tensor((int) (object) constant); + case NPTypeCode.UInt32: return new Tensor((uint) (object) constant); + case NPTypeCode.Int64: return new Tensor((long) (object) constant); + case NPTypeCode.UInt64: return new Tensor((ulong) (object) constant); + case NPTypeCode.Char: return new Tensor(Converts.ToByte(constant)); + case NPTypeCode.Double: return new Tensor((double) (object) constant); + case NPTypeCode.Single: return new Tensor((float) (object) constant); + default: + throw new NotSupportedException(); + } + + #endregion +#endif + } + + //conversion required + + if (astype == TF_DataType.TF_INT8) + return new Tensor(Converts.ToSByte(constant)); + + if (astype == TF_DataType.TF_STRING) + return new Tensor(Converts.ToString(constant)); + + var astype_np = astype?.as_numpy_typecode(); + +#if _REGEN + #region Compute + switch (astype_np) + { + %foreach supported_dtypes,supported_dtypes_lowercase% + case NPTypeCode.#1: return new Tensor(Converts.To#1(constant)); + % + default: + throw new NotSupportedException(); + } + #endregion +#else + + #region Compute + switch (astype_np) + { + case NPTypeCode.Boolean: return new Tensor(Converts.ToBoolean(constant)); + case NPTypeCode.Byte: return new Tensor(Converts.ToByte(constant)); + case NPTypeCode.Int16: return new Tensor(Converts.ToInt16(constant)); + case NPTypeCode.UInt16: return new Tensor(Converts.ToUInt16(constant)); + case NPTypeCode.Int32: return new Tensor(Converts.ToInt32(constant)); + case NPTypeCode.UInt32: return new Tensor(Converts.ToUInt32(constant)); + case NPTypeCode.Int64: return new Tensor(Converts.ToInt64(constant)); + case NPTypeCode.UInt64: return new Tensor(Converts.ToUInt64(constant)); + case NPTypeCode.Char: return new Tensor(Converts.ToByte(constant)); + case NPTypeCode.Double: return new Tensor(Converts.ToDouble(constant)); + case NPTypeCode.Single: return new Tensor(Converts.ToSingle(constant)); + default: + throw new NotSupportedException(); + } + #endregion +#endif + } + + /// + /// Convert given to . + /// + /// The constant scalar to convert + /// Convert to given before inserting it into a . + /// + public static Tensor ToTensor(string constant, TF_DataType? astype = null) + { + switch (astype) + { + //was conversion requested? + case null: + case TF_DataType.TF_STRING: + return new Tensor(constant); + //conversion required + case TF_DataType.TF_INT8: + return new Tensor(Converts.ToSByte(constant)); + default: + { + var astype_np = astype?.as_numpy_typecode(); + +#if _REGEN + #region Compute + switch (astype_np) + { + %foreach supported_dtypes,supported_dtypes_lowercase% + case NPTypeCode.#1: return new Tensor(Converts.To#1(constant)); + % + default: + throw new NotSupportedException(); + } + #endregion +#else + + #region Compute + switch (astype_np) + { + case NPTypeCode.Boolean: return new Tensor(Converts.ToBoolean(constant)); + case NPTypeCode.Byte: return new Tensor(Converts.ToByte(constant)); + case NPTypeCode.Int16: return new Tensor(Converts.ToInt16(constant)); + case NPTypeCode.UInt16: return new Tensor(Converts.ToUInt16(constant)); + case NPTypeCode.Int32: return new Tensor(Converts.ToInt32(constant)); + case NPTypeCode.UInt32: return new Tensor(Converts.ToUInt32(constant)); + case NPTypeCode.Int64: return new Tensor(Converts.ToInt64(constant)); + case NPTypeCode.UInt64: return new Tensor(Converts.ToUInt64(constant)); + case NPTypeCode.Char: return new Tensor(Converts.ToByte(constant)); + case NPTypeCode.Double: return new Tensor(Converts.ToDouble(constant)); + case NPTypeCode.Single: return new Tensor(Converts.ToSingle(constant)); + default: + throw new NotSupportedException(); + } + #endregion +#endif + } + } + } + + } +} \ No newline at end of file From b252a07d29489d69b42e2a378ab586e8cc5974d6 Mon Sep 17 00:00:00 2001 From: Eli Belash Date: Sun, 1 Sep 2019 23:17:49 +0300 Subject: [PATCH 3/5] BaseSession: Added transparent dtype conversion to feed_dict --- .../Sessions/BaseSession.cs | 79 ++++++++++--------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/src/TensorFlowNET.Core/Sessions/BaseSession.cs b/src/TensorFlowNET.Core/Sessions/BaseSession.cs index 4066c1df..1701c625 100644 --- a/src/TensorFlowNET.Core/Sessions/BaseSession.cs +++ b/src/TensorFlowNET.Core/Sessions/BaseSession.cs @@ -107,7 +107,7 @@ namespace Tensorflow foreach (var subfeed in feed_dict) { var subfeed_t = _graph.as_graph_element(subfeed.Key, allow_tensor: true, allow_operation: false); - //var subfeed_dtype = subfeed_t.dtype.as_numpy_datatype(); // subfeed_dtype was never used + //var target_dtype = subfeed_t.dtype.as_numpy_typecode(); // subfeed_dtype was never used feed_dict_tensor[subfeed_t] = subfeed.Value; //feed_map[subfeed_t.name] = (subfeed_t, subfeed.Value); } @@ -150,58 +150,64 @@ namespace Tensorflow int i = 0; foreach (var x in feed_dict) { - if (x.Key is Tensor tensor) + if (x.Key is Tensor key) { switch (x.Value) { case Tensor v: - feeds[i++] = new KeyValuePair(tensor._as_tf_output(), v); + if (v.dtype != key.dtype) + throw new ValueError($"Tensor {v} does not match the expected dtype {key.dtype}, actual dtype: {v.dtype}"); + feeds[i++] = new KeyValuePair(key._as_tf_output(), v); break; case NDArray v: - feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v, tensor.dtype)); + feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; case IntPtr v: - feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); + var tensor = new Tensor(v); + if (tensor.dtype != key.dtype) + throw new ValueError($"Tensor {v} does not match the expected dtype {key.dtype}, actual dtype: {tensor.dtype}"); + + feeds[i++] = new KeyValuePair(key._as_tf_output(), tensor); break; #if _REGEN // @formatter:off — disable formatter after this line - %types = ["sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "double", "Complex"] - %foreach types% - case #1 v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case #1[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - % + %types = ["bool", "sbyte", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "double", "Complex"] + %foreach types% + case #1 v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case #1[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + % // @formatter:on — enable formatter after this line #else // @formatter:off — disable formatter after this line - case sbyte v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case sbyte[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case byte v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case byte[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case short v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case short[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case ushort v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case ushort[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case int v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case int[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case uint v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case uint[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case long v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case long[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case ulong v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case ulong[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case float v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case float[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case double v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case double[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case Complex v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; - case Complex[] v: feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); break; + case bool v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case bool[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case sbyte v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case sbyte[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case byte v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case byte[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case short v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case short[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case ushort v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case ushort[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case int v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case int[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case uint v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case uint[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case long v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case long[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case ulong v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case ulong[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case float v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case float[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case double v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case double[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case Complex v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; + case Complex[] v: feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; // @formatter:on — enable formatter after this line #endif - case bool v: - feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor((byte) (v ? 1 : 0), TF_DataType.TF_BOOL)); - break; + case string v: - feeds[i++] = new KeyValuePair(tensor._as_tf_output(), new Tensor(v)); + feeds[i++] = new KeyValuePair(key._as_tf_output(), TensorConverter.ToTensor(v, key.dtype)); break; default: throw new NotImplementedException($"feed_dict data type {x.Value?.GetType().Name ?? ""}"); @@ -214,6 +220,7 @@ namespace Tensorflow return _call_tf_sessionrun(feeds, fetches, target_list); } + private unsafe NDArray[] _call_tf_sessionrun(KeyValuePair[] feed_dict, TF_Output[] fetch_list, List target_list) { // Ensure any changes to the graph are reflected in the runtime. From 00830b8e0bfb07cf8a394cb8af6e2656b2899350 Mon Sep 17 00:00:00 2001 From: Eli Belash Date: Sun, 1 Sep 2019 23:29:52 +0300 Subject: [PATCH 4/5] TensorFlowNET.UnitTest: Added FluentExtensions from NumSharp --- .../Utilities/FluentExtension.cs | 1206 +++++++++++++++++ 1 file changed, 1206 insertions(+) create mode 100644 test/TensorFlowNET.UnitTest/Utilities/FluentExtension.cs diff --git a/test/TensorFlowNET.UnitTest/Utilities/FluentExtension.cs b/test/TensorFlowNET.UnitTest/Utilities/FluentExtension.cs new file mode 100644 index 00000000..7bd16888 --- /dev/null +++ b/test/TensorFlowNET.UnitTest/Utilities/FluentExtension.cs @@ -0,0 +1,1206 @@ +using System; +using System.Diagnostics; +using System.Linq; +using System.Runtime.CompilerServices; +using FluentAssertions; +using FluentAssertions.Execution; +using FluentAssertions.Primitives; +using NumSharp; +using NumSharp.Backends; +using NumSharp.Utilities; + +namespace TensorFlowNET.UnitTest +{ + [DebuggerStepThrough] + public static class FluentExtension + { + public static ShapeAssertions Should(this Shape shape) + { + return new ShapeAssertions(shape); + } + + public static NDArrayAssertions Should(this NDArray arr) + { + return new NDArrayAssertions(arr); + } + + public static NDArrayAssertions Should(this UnmanagedStorage arr) + { + return new NDArrayAssertions(arr); + } + + public static string ToString(this Array arr, bool flat) + { + return new NDArray(arr).ToString(flat); + } + } + + [DebuggerStepThrough] + public class ShapeAssertions : ReferenceTypeAssertions + { + public ShapeAssertions(Shape instance) + { + Subject = instance; + } + + protected override string Identifier => "shape"; + + public AndConstraint BeOfSize(int size, string because = null, params object[] becauseArgs) + { + Subject.Size.Should().Be(size, because, becauseArgs); + return new AndConstraint(this); + } + + public AndConstraint NotBeOfSize(int size, string because = null, params object[] becauseArgs) + { + Subject.Size.Should().NotBe(size, because, becauseArgs); + return new AndConstraint(this); + } + + public AndConstraint BeShaped(params int[] dimensions) + { + if (dimensions == null) + throw new ArgumentNullException(nameof(dimensions)); + + if (dimensions.Length == 0) + throw new ArgumentException("Value cannot be an empty collection.", nameof(dimensions)); + + Subject.Dimensions.Should().BeEquivalentTo(dimensions); + return new AndConstraint(this); + } + + public AndConstraint Be(Shape shape, string because = null, params object[] becauseArgs) + { + Execute.Assertion + .BecauseOf(because, becauseArgs) + .ForCondition(Subject.Equals(shape)) + .FailWith($"Expected shape to be {shape.ToString()} but got {Subject.ToString()}"); + + return new AndConstraint(this); + } + + public AndConstraint BeEquivalentTo(int? size = null, int? ndim = null, ITuple shape = null) + { + if (size.HasValue) + { + BeOfSize(size.Value, null); + } + + if (ndim.HasValue) + HaveNDim(ndim.Value); + + if (shape != null) + for (int i = 0; i < shape.Length; i++) + { + Subject.Dimensions[i].Should().Be((int) shape[i]); + } + + return new AndConstraint(this); + } + + public AndConstraint NotBe(Shape shape, string because = null, params object[] becauseArgs) + { + Execute.Assertion + .BecauseOf(because, becauseArgs) + .ForCondition(!Subject.Equals(shape)) + .FailWith($"Expected shape to be {shape.ToString()} but got {Subject.ToString()}"); + + return new AndConstraint(this); + } + + public AndConstraint HaveNDim(int ndim) + { + Subject.Dimensions.Length.Should().Be(ndim); + return new AndConstraint(this); + } + + public AndConstraint BeSliced() + { + Subject.IsSliced.Should().BeTrue(); + return new AndConstraint(this); + } + + public AndConstraint BeScalar() + { + Subject.IsScalar.Should().BeTrue(); + return new AndConstraint(this); + } + + public AndConstraint BeBroadcasted() + { + Subject.IsBroadcasted.Should().BeTrue(); + return new AndConstraint(this); + } + + + public AndConstraint NotBeSliced() + { + Subject.IsSliced.Should().BeFalse(); + return new AndConstraint(this); + } + + public AndConstraint NotBeScalar() + { + Subject.IsScalar.Should().BeFalse(); + return new AndConstraint(this); + } + + public AndConstraint NotBeBroadcasted() + { + Subject.IsBroadcasted.Should().BeFalse(); + return new AndConstraint(this); + } + + public AndConstraint BeNDim(int ndim) + { + Subject.Dimensions.Length.Should().Be(ndim); + return new AndConstraint(this); + } + } + + //[DebuggerStepThrough] + public class NDArrayAssertions : ReferenceTypeAssertions + { + public NDArrayAssertions(NDArray instance) + { + Subject = instance; + } + + public NDArrayAssertions(UnmanagedStorage instance) + { + Subject = new NDArray(instance); + } + + protected override string Identifier => "shape"; + + public AndConstraint BeOfSize(int size, string because = null, params object[] becauseArgs) + { + Subject.size.Should().Be(size, because, becauseArgs); + return new AndConstraint(this); + } + + public AndConstraint BeShaped(params int[] dimensions) + { + if (dimensions == null) + throw new ArgumentNullException(nameof(dimensions)); + + if (dimensions.Length == 0) + throw new ArgumentException("Value cannot be an empty collection.", nameof(dimensions)); + + Subject.Unsafe.Storage.Shape.Dimensions.Should().BeEquivalentTo(dimensions); + return new AndConstraint(this); + } + + public AndConstraint BeShaped(int? size = null, int? ndim = null, ITuple shape = null) + { + if (size.HasValue) + { + BeOfSize(size.Value, null); + } + + if (ndim.HasValue) + HaveNDim(ndim.Value); + + if (shape != null) + for (int i = 0; i < shape.Length; i++) + { + Subject.Unsafe.Storage.Shape.Dimensions[i].Should().Be((int) shape[i]); + } + + return new AndConstraint(this); + } + + public AndConstraint NotBeShaped(Shape shape, string because = null, params object[] becauseArgs) + { + Execute.Assertion + .BecauseOf(because, becauseArgs) + .ForCondition(!Subject.Unsafe.Storage.Shape.Equals(shape)) + .FailWith($"Expected shape to be {shape.ToString()} but got {Subject.ToString()}"); + + return new AndConstraint(this); + } + + public AndConstraint HaveNDim(int ndim) + { + Subject.Unsafe.Storage.Shape.Dimensions.Length.Should().Be(ndim); + return new AndConstraint(this); + } + + public AndConstraint BeBroadcasted() + { + Subject.Unsafe.Storage.Shape.IsBroadcasted.Should().BeTrue(); + return new AndConstraint(this); + } + + public AndConstraint NotBeBroadcasted() + { + Subject.Unsafe.Storage.Shape.IsBroadcasted.Should().BeFalse(); + return new AndConstraint(this); + } + + public AndConstraint BeSliced() + { + Subject.Unsafe.Storage.Shape.IsSliced.Should().BeTrue(); + return new AndConstraint(this); + } + + public AndConstraint BeScalar() + { + Subject.Unsafe.Storage.Shape.IsScalar.Should().BeTrue(); + return new AndConstraint(this); + } + + public AndConstraint BeScalar(object value) + { + Subject.Unsafe.Storage.Shape.IsScalar.Should().BeTrue(); + Subject.GetValue().Should().Be(value); + return new AndConstraint(this); + } + + public AndConstraint BeOfType(NPTypeCode typeCode) + { + Subject.typecode.Should().Be(typeCode); + return new AndConstraint(this); + } + + public AndConstraint BeOfType(Type typeCode) + { + Subject.dtype.Should().Be(typeCode); + return new AndConstraint(this); + } + + public AndConstraint BeOfType() + { + Subject.typecode.Should().Be(InfoOf.NPTypeCode); + return new AndConstraint(this); + } + + public AndConstraint NotBeSliced() + { + Subject.Unsafe.Storage.Shape.IsSliced.Should().BeFalse(); + return new AndConstraint(this); + } + + public AndConstraint NotBeScalar() + { + Subject.Unsafe.Storage.Shape.IsScalar.Should().BeFalse(); + return new AndConstraint(this); + } + + + public AndConstraint BeNDim(int ndim) + { + Subject.Unsafe.Storage.Shape.Dimensions.Length.Should().Be(ndim); + return new AndConstraint(this); + } + + public AndConstraint Be(NDArray expected) + { + Execute.Assertion + .ForCondition(np.array_equal(Subject, expected)) + .FailWith($"Expected the subject and other ndarray to be equals.\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{expected.ToString(false)}"); + + return new AndConstraint(this); + } + + public AndConstraint BeOfValues(params object[] values) + { + if (values == null) + throw new ArgumentNullException(nameof(values)); + + Subject.size.Should().Be(values.Length, "the method BeOfValues also confirms the sizes are matching with given values."); + +#if _REGEN + #region Compute + switch (Subject.typecode) + { + %foreach supported_dtypes,supported_dtypes_lowercase% + case NPTypeCode.#1: + { + var iter = Subject.AsIterator<#2>(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.To#1(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: #1).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + break; + } + % + default: + throw new NotSupportedException(); + } + #endregion +#else + + #region Compute + + switch (Subject.typecode) + { + case NPTypeCode.Boolean: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToBoolean(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Byte: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToByte(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Byte).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Int16: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToInt16(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Int16).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.UInt16: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToUInt16(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: UInt16).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Int32: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToInt32(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Int32).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.UInt32: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToUInt32(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: UInt32).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Int64: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToInt64(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Int64).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.UInt64: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToUInt64(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: UInt64).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Char: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToChar(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Char).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Double: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToDouble(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Double).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Single: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToSingle(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Single).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Decimal: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToDecimal(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Decimal).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + default: + throw new NotSupportedException(); + } + + #endregion + +#endif + + + return new AndConstraint(this); + } + + public AndConstraint AllValuesBe(object val) + { +#if _REGEN + #region Compute + switch (Subject.typecode) + { + %foreach supported_dtypes,supported_dtypes_lowercase% + case NPTypeCode.#1: + { + var iter = Subject.AsIterator<#2>(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.To#1(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: #1).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + break; + } + % + default: + throw new NotSupportedException(); + } + #endregion +#else + + #region Compute + + switch (Subject.typecode) + { + case NPTypeCode.Boolean: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToBoolean(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Byte: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToByte(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: Byte).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Int16: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToInt16(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: Int16).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + case NPTypeCode.UInt16: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToUInt16(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: UInt16).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Int32: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToInt32(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: Int32).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + case NPTypeCode.UInt32: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToUInt32(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: UInt32).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Int64: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToInt64(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: Int64).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + case NPTypeCode.UInt64: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToUInt64(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: UInt64).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Char: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToChar(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: Char).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Double: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToDouble(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: Double).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Single: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToSingle(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: Single).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Decimal: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + var expected = Convert.ToDecimal(val); + for (int i = 0; hasnext(); i++) + { + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {2}th value to be {0}, but found {1} (dtype: Decimal).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n{val}", expected, nextval, i); + } + + break; + } + + default: + throw new NotSupportedException(); + } + + #endregion + +#endif + + + return new AndConstraint(this); + } + + public AndConstraint BeOfValuesApproximately(double sensitivity, params object[] values) + { + if (values == null) + throw new ArgumentNullException(nameof(values)); + + Subject.size.Should().Be(values.Length, "the method BeOfValuesApproximately also confirms the sizes are matching with given values."); + +#if _REGEN + #region Compute + switch (Subject.typecode) + { + %foreach supported_dtypes,supported_dtypes_lowercase% + case NPTypeCode.#1: + { + var iter = Subject.AsIterator<#2>(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.To#1(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs(expected - nextval) <= sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + break; + } + % + default: + throw new NotSupportedException(); + } + #endregion +#else + + #region Compute + + switch (Subject.typecode) + { + case NPTypeCode.Boolean: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToBoolean(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(expected == nextval) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Byte: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToByte(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs(expected - nextval) <= sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Int16: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToInt16(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs(expected - nextval) <= sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.UInt16: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToUInt16(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs(expected - nextval) <= sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Int32: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToInt32(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs(expected - nextval) <= sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.UInt32: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToUInt32(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs(expected - nextval) <= sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Int64: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToInt64(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs(expected - nextval) <= sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.UInt64: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToUInt64(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs((double) (expected - nextval)) <= sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Char: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToChar(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs(expected - nextval) <= sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Double: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToDouble(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs(expected - nextval) <= sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Single: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToSingle(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs(expected - nextval) <= sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + case NPTypeCode.Decimal: + { + var iter = Subject.AsIterator(); + var next = iter.MoveNext; + var hasnext = iter.HasNext; + for (int i = 0; i < values.Length; i++) + { + Execute.Assertion + .ForCondition(hasnext()) + .FailWith($"Expected the NDArray to have atleast {values.Length} but in fact it has size of {i}."); + + var expected = Convert.ToDecimal(values[i]); + var nextval = next(); + + Execute.Assertion + .ForCondition(Math.Abs(expected - nextval) <= (decimal) sensitivity) + .FailWith($"Expected NDArray's {{2}}th value to be {{0}}, but found {{1}} (dtype: Boolean).\n------- Subject -------\n{Subject.ToString(false)}\n------- Expected -------\n[{string.Join(", ", values.Select(v => v.ToString()))}]", expected, nextval, i); + } + + break; + } + + default: + throw new NotSupportedException(); + } + + #endregion + +#endif + + + return new AndConstraint(this); + } + } +} \ No newline at end of file From 4d8ae9a396c83ae09a1c525e267642a5935a7c19 Mon Sep 17 00:00:00 2001 From: Eli Belash Date: Sun, 1 Sep 2019 23:32:38 +0300 Subject: [PATCH 5/5] Added unit-tests for autocasting mechanism. --- test/TensorFlowNET.UnitTest/SessionTest.cs | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/test/TensorFlowNET.UnitTest/SessionTest.cs b/test/TensorFlowNET.UnitTest/SessionTest.cs index d2295166..f1453c0e 100644 --- a/test/TensorFlowNET.UnitTest/SessionTest.cs +++ b/test/TensorFlowNET.UnitTest/SessionTest.cs @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using System.Text; using FluentAssertions; using Google.Protobuf; +using NumSharp.Backends; using Tensorflow; using Tensorflow.Util; using static Tensorflow.Binding; @@ -131,5 +132,61 @@ namespace TensorFlowNET.UnitTest } } } + + [TestMethod] + public void Autocast_Case1() + { + var sess = tf.Session().as_default(); + var input = tf.placeholder(tf.float64, shape: new TensorShape(6)); + var op = tf.reshape(input, new int[] {2, 3}); + sess.run(tf.global_variables_initializer()); + var ret = sess.run(op, feed_dict: (input, np.array(1, 2, 3, 4, 5, 6))); + + ret.Should().BeOfType().And.BeShaped(2, 3).And.BeOfValues(1, 2, 3, 4, 5, 6); + print(ret.dtype); + print(ret); + } + + [TestMethod] + public void Autocast_Case2() + { + var sess = tf.Session().as_default(); + var input = tf.placeholder(tf.float64, shape: new TensorShape(6)); + var op = tf.reshape(input, new int[] {2, 3}); + sess.run(tf.global_variables_initializer()); + var ret = sess.run(op, feed_dict: (input, np.array(1, 2, 3, 4, 5, 6).astype(NPTypeCode.Single) + 0.1f)); + + ret.Should().BeOfType().And.BeShaped(2, 3).And.BeOfValuesApproximately(0.001d, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1); + print(ret.dtype); + print(ret); + } + + [TestMethod] + public void Autocast_Case3() + { + var sess = tf.Session().as_default(); + var input = tf.placeholder(tf.int16, shape: new TensorShape(6)); + var op = tf.reshape(input, new int[] {2, 3}); + sess.run(tf.global_variables_initializer()); + var ret = sess.run(op, feed_dict: (input, np.array(1, 2, 3, 4, 5, 6).astype(NPTypeCode.Single) + 0.1f)); + + ret.Should().BeOfType().And.BeShaped(2, 3).And.BeOfValues(1, 2, 3, 4, 5, 6); + print(ret.dtype); + print(ret); + } + + [TestMethod] + public void Autocast_Case4() + { + var sess = tf.Session().as_default(); + var input = tf.placeholder(tf.@byte, shape: new TensorShape(6)); + var op = tf.reshape(input, new int[] {2, 3}); + sess.run(tf.global_variables_initializer()); + var ret = sess.run(op, feed_dict: (input, np.array(1, 2, 3, 4, 5, 6).astype(NPTypeCode.Single) + 0.1f)); + + ret.Should().BeOfType().And.BeShaped(2, 3).And.BeOfValues(1, 2, 3, 4, 5, 6); + print(ret.dtype); + print(ret); + } } } \ No newline at end of file