From 0f49232b0f3e30815bf9952d66ebb735f5568c5b Mon Sep 17 00:00:00 2001
From: Carl Philipp Klemm <philipp@uvos.xyz>
Date: Thu, 2 May 2024 16:49:51 +0200
Subject: [PATCH] Add Utils.CheckEnvThrow(), Utils.CheckEnv() and
 Utils.FloatEq() These functions check if the lib is able to service requests
 as currently loaded Also use these functions to check if everything is ok at
 entry points to the various other classes add Utils.FloatEq() that uses the
 same logic as libeisgenerator to compare float values

---
 kissinferencesharp.csproj |  2 +-
 src/capi.cs               |  3 ++
 src/exceptions.cs         | 38 +++++++++++++++++++++++
 src/inferenceexception.cs | 16 ----------
 src/network.cs            |  4 +++
 src/spectra.cs            |  4 +++
 src/utils.cs              | 64 +++++++++++++++++++++++++++++++++++++++
 src/versionfixed.cs       | 16 +++++++++-
 8 files changed, 129 insertions(+), 18 deletions(-)
 create mode 100644 src/exceptions.cs
 delete mode 100644 src/inferenceexception.cs

diff --git a/kissinferencesharp.csproj b/kissinferencesharp.csproj
index 88cf2a4..7f3a147 100644
--- a/kissinferencesharp.csproj
+++ b/kissinferencesharp.csproj
@@ -14,7 +14,7 @@
 <ItemGroup>
 	<Compile Include="src/capi.cs" />
 	<Compile Include="src/network.cs"/>
-	<Compile Include="src/inferenceexception.cs" />
+	<Compile Include="src/exceptions.cs" />
 	<Compile Include="src/utils.cs" />
 	<Compile Include="src/spectra.cs" />
 	<Compile Include="src/versionfixed.cs" />
diff --git a/src/capi.cs b/src/capi.cs
index ec8c346..d799382 100644
--- a/src/capi.cs
+++ b/src/capi.cs
@@ -75,6 +75,9 @@ internal class Capi
 	[DllImport("kissinference", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
 	public static extern IntPtr kiss_get_strerror(ref CNetwork net);
 
+	[DllImport("kissinference", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention=CallingConvention.StdCall)]
+	public static extern byte kiss_float_eq(float a, float b, uint ulp);
+
 	public static string[] IntPtrToUtf8Array(IntPtr array)
 	{
 		var pointers = new List<IntPtr>();
diff --git a/src/exceptions.cs b/src/exceptions.cs
new file mode 100644
index 0000000..1d41a30
--- /dev/null
+++ b/src/exceptions.cs
@@ -0,0 +1,38 @@
+using System;
+
+namespace Kiss
+{
+
+	/// <summary>
+	/// This exception not directly used by libkissinferencesharp, but all exeptions used inherit from this type.
+	/// </summary>
+	public class KissException : Exception
+	{
+		public KissException(){}
+		public KissException(string message): base(message){}
+		public KissException(string message, Exception inner): base(message, inner){}
+	}
+
+	/// <summary>
+	/// This exception is thrown when an error occures during inference, usually due to running out of memory.
+	/// </summary>
+	public class InferenceException : KissException
+	{
+		public InferenceException(){}
+		public InferenceException(string message): base(message){}
+		public InferenceException(string message, Exception inner): base(message, inner){}
+	}
+
+	/// <summary>
+	/// This exception is thrown a user of this libary attempts to instantate an object in an enviroment that is unsupported.
+	/// </summary>
+	public class EnviromentException : KissException
+	{
+		public EnviromentException(){}
+		public EnviromentException(string message): base(message){}
+		public EnviromentException(string message, Exception inner): base(message, inner){}
+	}
+
+}
+
+
diff --git a/src/inferenceexception.cs b/src/inferenceexception.cs
deleted file mode 100644
index dc95710..0000000
--- a/src/inferenceexception.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System;
-
-namespace Kiss
-{
-
-/// <summary>
-/// This exception is thrown when an error occures during inference, usually due to running out of memory.
-/// </summary>
-public class InferenceException : Exception
-{
-	public InferenceException(){}
-	public InferenceException(string message): base(message){}
-	public InferenceException(string message, Exception inner): base(message, inner){}
-}
-
-}
diff --git a/src/network.cs b/src/network.cs
index 746f8b4..d06d866 100644
--- a/src/network.cs
+++ b/src/network.cs
@@ -47,8 +47,12 @@ public class Network: System.IDisposable
 	/// <exception cref="System.IO.FileLoadException">
 	/// Thrown when the network file could not be loaded
 	/// </exception>
+	/// <exception cref="Kiss.EnviromentException">
+	/// Thrown if the enviroment is unacceptable for the operation of this libaray
+	/// </exception>
 	public Network(string path, bool verbose = false)
 	{
+		Utils.CheckEnvThrow();
 		byte ret = Capi.kiss_load_network_prealloc(ref net, path, CResultCb, Convert.ToByte(verbose));
 		Console.WriteLine("ret: {0:D}", ret);
 		if(ret == 0)
diff --git a/src/spectra.cs b/src/spectra.cs
index cde143b..561fb35 100644
--- a/src/spectra.cs
+++ b/src/spectra.cs
@@ -36,8 +36,12 @@ public class Spectra
 	/// <param name="Omega">
 	/// The frequency values in rad/s of eatch datapoint, its lenght must be the same as <paramref name="Real"/>
 	/// </param>
+	/// <exception cref="Kiss.EnviromentException">
+	/// Thrown if the enviroment is unacceptable for the operation of this libaray
+	/// </exception>
 	public Spectra(float[] Real, float[] Imaginary, float[] Omega)
 	{
+		Utils.CheckEnvThrow();
 		if(Real.Length != Imaginary.Length || Real.Length != Omega.Length)
 			throw new ArgumentException("the real, imaginary and omega parts of the spectra have to be of the same size");
 		this.Real = Real;
diff --git a/src/utils.cs b/src/utils.cs
index f379313..554447a 100644
--- a/src/utils.cs
+++ b/src/utils.cs
@@ -9,6 +9,8 @@ namespace Kiss
 /// </summary>
 public class Utils
 {
+	static private bool EnviromentChecked = false;
+
 	/// <summary>
 	/// Converts an array containing a linear or log range.
 	/// </summary>
@@ -29,6 +31,7 @@ public class Utils
 	/// </returns>
 	public static float[] CreateRange(float start, float end, int size, bool log)
 	{
+		CheckEnvThrow();
 		IntPtr ptr = Capi.kiss_create_range(start, end, (UIntPtr)size, Convert.ToByte(log));
 		var ret = new float[size];
 		Marshal.Copy(ptr, ret, 0, size);
@@ -53,6 +56,7 @@ public class Utils
 	/// </returns>
 	public static float Grad(float[] data, float[] omegas, int index)
 	{
+		CheckEnvThrow();
 		if(data.Length != omegas.Length)
 			throw new ArgumentException("the data and omegas must be the same length");
 		return Capi.kiss_grad(data, omegas, (UIntPtr)data.Length, (UIntPtr)index);
@@ -69,8 +73,68 @@ public class Utils
 	/// </returns>
 	public static float Median(float[] data)
 	{
+		CheckEnvThrow();
 		return Capi.kiss_median(data, (UIntPtr)data.Length);
 	}
+
+	/// <summary>
+	/// Checks the given floats for equality with a tollerance of ulp epsilons around the sum of the inputs.
+	/// </summary>
+	/// <param name="a">
+	/// The first paramter for the comperasin
+	/// </param>
+	/// <param name="b">
+	/// b The second input to be compared with the first.
+	/// </param>
+	/// <param name="ulp">
+	/// lp number of epsilons of tollerance..
+	/// </param>
+	/// <returns>
+	/// True if the value of b is within ulp epsilons of a, false otherwise.
+	/// </returns>
+	public static bool FloatEq(float a, float b, uint ulp)
+	{
+		CheckEnvThrow();
+		return Capi.kiss_float_eq(a, b, ulp) != 0;
+	}
+
+	/// <summary>
+	/// Checks the envirment to see if this libary can work correctly
+	/// </summary>
+	/// <returns>
+	/// string.Empty if the environment is acceptable and an error message if it is not.
+	/// </returns>
+	public static string CheckEnv()
+	{
+		if(EnviromentChecked)
+			return string.Empty;
+
+		if(System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture != Architecture.X86 &&
+			System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture != Architecture.X64)
+			return "libkissinferencesharp only works on X86 or X64 cpu architecture";
+
+		var version = VersionFixed.GetVersionNoCheck();
+		if(version.Major != 1 || version.Minor != 1)
+			return "This version of libkissinferencesharp only supports native code backends of version 1.1.x, but the loaded libary is " + version;
+
+		EnviromentChecked = true;
+		return string.Empty;
+	}
+
+	/// <summary>
+	/// Checks the envirment to see if this libary can work correctly and throws a EnviromentException if its not.
+	/// </summary>
+	/// <exception cref="Kiss.EnviromentException">
+	/// Thown if the environment is unacceptable.
+	/// </exception>
+	public static void CheckEnvThrow()
+	{
+		var res = CheckEnv();
+		if(res.Length == 0)
+			return;
+
+		throw new EnviromentException(res);
+	}
 }
 
 }
diff --git a/src/versionfixed.cs b/src/versionfixed.cs
index f2c175d..4f6bae2 100644
--- a/src/versionfixed.cs
+++ b/src/versionfixed.cs
@@ -13,11 +13,25 @@ public struct VersionFixed
 	public int Minor;
 	public int Patch;
 
+	/// <summary>
+	/// This Method returns the version of the currently loaded kissinference instance.
+	/// </summary>
+	public static VersionFixed GetVersion()
+	{
+		Utils.CheckEnvThrow();
+		return GetVersionNoCheck();
+	}
+
 	/// <summary>
 	/// This Method returns the version of the currently loaded kissinference instance.
 	/// </summary>
 	[DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, EntryPoint = "kiss_get_version", CallingConvention=CallingConvention.StdCall)]
-	public static extern VersionFixed GetVersion();
+	public static extern VersionFixed GetVersionNoCheck();
+
+	public override string ToString()
+	{
+		return Major.ToString() + "." + Minor.ToString() + "." + Patch.ToString();
+	}
 }
 
 }
-- 
GitLab