diff --git a/src/Bonsai.ML.Design/MultidimensionalArrayVisualizer.cs b/src/Bonsai.ML.Design/MultidimensionalArrayVisualizer.cs index 397d947e..a2ea15ab 100644 --- a/src/Bonsai.ML.Design/MultidimensionalArrayVisualizer.cs +++ b/src/Bonsai.ML.Design/MultidimensionalArrayVisualizer.cs @@ -1,13 +1,16 @@ using System; using System.Windows.Forms; +using Bonsai; using Bonsai.Design; +[assembly: TypeVisualizer(typeof(Bonsai.ML.Design.MultidimensionalArrayVisualizer), + Target = typeof(double[,]))] + namespace Bonsai.ML.Design { /// /// Provides a type visualizer to display multi dimensional array data as a heatmap. /// - [TypeVisualizer(typeof(MultidimensionalArrayVisualizer), Target = typeof(double[,]))] public class MultidimensionalArrayVisualizer : DialogTypeVisualizer { /// diff --git a/src/Bonsai.ML.HiddenMarkovModels/Bonsai.ML.HiddenMarkovModels.csproj b/src/Bonsai.ML.HiddenMarkovModels/Bonsai.ML.HiddenMarkovModels.csproj index 8dac151d..4b0ef857 100644 --- a/src/Bonsai.ML.HiddenMarkovModels/Bonsai.ML.HiddenMarkovModels.csproj +++ b/src/Bonsai.ML.HiddenMarkovModels/Bonsai.ML.HiddenMarkovModels.csproj @@ -6,7 +6,6 @@ net472;netstandard2.0 - diff --git a/src/Bonsai.ML.LinearDynamicalSystems/Bonsai.ML.LinearDynamicalSystems.csproj b/src/Bonsai.ML.LinearDynamicalSystems/Bonsai.ML.LinearDynamicalSystems.csproj index 8110c215..9955b561 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/Bonsai.ML.LinearDynamicalSystems.csproj +++ b/src/Bonsai.ML.LinearDynamicalSystems/Bonsai.ML.LinearDynamicalSystems.csproj @@ -5,13 +5,13 @@ Bonsai Rx ML KalmanFilter LinearDynamicalSystems net472;netstandard2.0 - - - - - + + + + + \ No newline at end of file diff --git a/src/Bonsai.ML.LinearDynamicalSystems/CreateModelReference.cs b/src/Bonsai.ML.LinearDynamicalSystems/CreateModelReference.cs deleted file mode 100644 index cfc1d0f3..00000000 --- a/src/Bonsai.ML.LinearDynamicalSystems/CreateModelReference.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.ComponentModel; -using System; -using System.Reactive.Linq; - -namespace Bonsai.ML.LinearDynamicalSystems -{ - /// - /// Represents an operator that creates a reference for a named model. - /// - [Combinator] - [Description("Creates a reference for a named model.")] - [WorkflowElementCategory(ElementCategory.Source)] - public class CreateModelReference : INamedElement - { - /// - /// Gets or sets the name of the model to reference. - /// - [Description("The name of the model to reference.")] - public string Name { get ; set; } - - /// - /// Generates an observable sequence that contains the model reference object. - /// - /// - /// A sequence containing a single instance of the - /// class. - /// - public IObservable Process() - { - return Observable.Defer(() => Observable.Return(new ModelReference(Name))); - } - } -} diff --git a/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/CreateKFModel.bonsai b/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/CreateKFModel.bonsai index 5566b6ba..863927ef 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/CreateKFModel.bonsai +++ b/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/CreateKFModel.bonsai @@ -1,7 +1,7 @@  - - model - + model diff --git a/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/Forecast.cs b/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/Forecast.cs index 368607f7..7b4b6df9 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/Forecast.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/Forecast.cs @@ -1,12 +1,11 @@ using System; -using System.Reactive; using System.Reactive.Linq; -using System.Collections.ObjectModel; using System.Xml.Serialization; using System.ComponentModel; using Newtonsoft.Json; using Python.Runtime; using System.Collections.Generic; +using Bonsai.ML.Python; namespace Bonsai.ML.LinearDynamicalSystems.Kinematics { diff --git a/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/KFModelParameters.cs b/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/KFModelParameters.cs index 19f9122c..32a80d31 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/KFModelParameters.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/KFModelParameters.cs @@ -3,6 +3,7 @@ using System.Reactive.Linq; using Python.Runtime; using Newtonsoft.Json; +using Bonsai.ML.Python; namespace Bonsai.ML.LinearDynamicalSystems.Kinematics { diff --git a/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/PerformForecasting.bonsai b/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/PerformForecasting.bonsai index 2a54115a..d20e379e 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/PerformForecasting.bonsai +++ b/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/PerformForecasting.bonsai @@ -2,7 +2,7 @@ diff --git a/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/PerformInference.bonsai b/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/PerformInference.bonsai index 1250e7c2..56d7c108 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/PerformInference.bonsai +++ b/src/Bonsai.ML.LinearDynamicalSystems/Kinematics/PerformInference.bonsai @@ -2,9 +2,10 @@ @@ -127,10 +128,10 @@ - + - + diff --git a/src/Bonsai.ML.LinearDynamicalSystems/Learning/RunOptimizationAsync.bonsai b/src/Bonsai.ML.LinearDynamicalSystems/Learning/RunOptimizationAsync.bonsai index a6eee35a..e64f1f22 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/Learning/RunOptimizationAsync.bonsai +++ b/src/Bonsai.ML.LinearDynamicalSystems/Learning/RunOptimizationAsync.bonsai @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rx="clr-namespace:Bonsai.Reactive;assembly=Bonsai.Core" xmlns:py="clr-namespace:Bonsai.Scripting.Python;assembly=Bonsai.Scripting.Python" - xmlns:p1="clr-namespace:Bonsai.ML.LinearDynamicalSystems;assembly=Bonsai.ML.LinearDynamicalSystems" + xmlns:p1="clr-namespace:Bonsai.ML;assembly=Bonsai.ML" xmlns:scr="clr-namespace:Bonsai.Scripting.Expressions;assembly=Bonsai.Scripting.Expressions" xmlns="https://bonsai-rx.org/2018/workflow"> diff --git a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/CreateKFModel.bonsai b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/CreateKFModel.bonsai index e04b18e0..5c476c65 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/CreateKFModel.bonsai +++ b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/CreateKFModel.bonsai @@ -2,7 +2,7 @@ @@ -31,9 +31,7 @@ - - model - + model diff --git a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/CreateMultivariatePDF.bonsai b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/CreateMultivariatePDF.bonsai index ad6b361f..41e2ad52 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/CreateMultivariatePDF.bonsai +++ b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/CreateMultivariatePDF.bonsai @@ -2,7 +2,7 @@ diff --git a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/GridParameters.cs b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/GridParameters.cs index eeec392b..1cf1e9db 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/GridParameters.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/GridParameters.cs @@ -3,6 +3,7 @@ using System.Reactive.Linq; using Newtonsoft.Json; using Python.Runtime; +using Bonsai.ML.Python; namespace Bonsai.ML.LinearDynamicalSystems.LinearRegression { diff --git a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/KFModelParameters.cs b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/KFModelParameters.cs index 46f8ae9a..589aaba9 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/KFModelParameters.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/KFModelParameters.cs @@ -2,6 +2,7 @@ using Newtonsoft.Json; using System; using System.Reactive.Linq; +using Bonsai.ML.Python; using Python.Runtime; using System.Xml.Serialization; @@ -105,7 +106,7 @@ public int NumFeatures set { _x = value; - _xString = _x == null ? "None" : NumpyHelper.NumpyParser.ParseArray(_x); + _xString = _x == null ? "None" : StringFormatter.FormatToPython(_x); } } @@ -125,7 +126,7 @@ public int NumFeatures set { _p = value; - _pString = _p == null ? "None" : NumpyHelper.NumpyParser.ParseArray(_p); + _pString = _p == null ? "None" : StringFormatter.FormatToPython(_p); } } @@ -188,10 +189,10 @@ public IObservable Process(IObservable sour P = _p }); } - + + /// public override string ToString() { - return $"likelihood_precision_coef={_likelihood_precision_coefString}, prior_precision_coef={_prior_precision_coefString}, n_features={_n_featuresString}, x={_xString}, P={_pString}"; } } diff --git a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/MultivariatePDF.cs b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/MultivariatePDF.cs index 6fc92c6c..c03449f0 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/MultivariatePDF.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/MultivariatePDF.cs @@ -3,6 +3,7 @@ using System.Reactive.Linq; using Python.Runtime; using System.Xml.Serialization; +using Bonsai.ML.Python; namespace Bonsai.ML.LinearDynamicalSystems.LinearRegression { @@ -35,7 +36,7 @@ public IObservable Process(IObservable source) return Observable.Select(source, pyObject => { var gridParameters = GridParameters.ConvertPyObject(pyObject); - var values = (double[,])pyObject.GetArrayAttribute("pdf_values"); + var values = (double[,])pyObject.GetArrayAttr("pdf_values"); return new MultivariatePDF { GridParameters = gridParameters, Values = values diff --git a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/PerformInference.bonsai b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/PerformInference.bonsai index 75aa6fea..e3fa230b 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/PerformInference.bonsai +++ b/src/Bonsai.ML.LinearDynamicalSystems/LinearRegression/PerformInference.bonsai @@ -1,9 +1,10 @@  - @@ -126,7 +127,7 @@ - + diff --git a/src/Bonsai.ML.LinearDynamicalSystems/ModelReference.cs b/src/Bonsai.ML.LinearDynamicalSystems/ModelReference.cs deleted file mode 100644 index 1c098c7a..00000000 --- a/src/Bonsai.ML.LinearDynamicalSystems/ModelReference.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.ComponentModel; - -namespace Bonsai.ML.LinearDynamicalSystems -{ - - /// - /// Bonsai LDS model reference base class - /// - public class ModelReference - { - /// - /// Gets or sets the name of the referenced model. - /// - public string Name { get ; set; } - - /// - /// Initializes a new instance of the class - /// with the specified name. - /// - /// The name of the referenced model. - public ModelReference(string name) - { - Name = name; - } - } -} diff --git a/src/Bonsai.ML.LinearDynamicalSystems/NumpyHelper.cs b/src/Bonsai.ML.LinearDynamicalSystems/NumpyHelper.cs deleted file mode 100644 index 145b19c9..00000000 --- a/src/Bonsai.ML.LinearDynamicalSystems/NumpyHelper.cs +++ /dev/null @@ -1,338 +0,0 @@ -using System; -using Python.Runtime; -using System.Collections.Generic; -using System.ComponentModel; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System.Text; -using System.Linq; -using System.Runtime.InteropServices; - -namespace Bonsai.ML.LinearDynamicalSystems -{ - static class NumpyHelper - { - public class NumpyArrayInterface - { - public NumpyArrayInterface(PyObject obj) - { - if (!IsNumPyArray(obj)) - { - throw new Exception("object is not a numpy array"); - } - var meta = obj.GetAttr("__array_interface__"); - IsCStyleContiguous = meta["strides"] == null; - Address = new IntPtr(meta["data"][0].As()); - - var typestr = meta["typestr"].As(); - var dtype = typestr.Substring(1); - switch (dtype) - { - case "b1": - DataType = typeof(bool); - break; - case "f4": - DataType = typeof(float); - break; - case "f8": - DataType = typeof(double); - break; - case "i2": - DataType = typeof(short); - break; - case "i4": - DataType = typeof(int); - break; - case "i8": - DataType = typeof(long); - break; - case "u1": - DataType = typeof(byte); - break; - case "u2": - DataType = typeof(ushort); - break; - case "u4": - DataType = typeof(uint); - break; - case "u8": - DataType = typeof(ulong); - break; - default: - throw new Exception($"Type '{dtype}' not supported"); - } - Shape = obj.GetAttr("shape").As(); - NBytes = obj.GetAttr("nbytes").As(); - } - - public readonly IntPtr Address; - - public readonly Type DataType; - - public readonly long[] Shape; - - public readonly int NBytes; - - public readonly bool IsCStyleContiguous; - } - - public static Array PyObjectToArray(PyObject array) - { - var info = new NumpyArrayInterface(array); - byte[] data = new byte[info.NBytes]; - Marshal.Copy(info.Address, data, 0, info.NBytes); - if (info.DataType == typeof(byte) && info.Shape.Length == 1) - { - return data; - } - var result = Array.CreateInstance(info.DataType, info.Shape); - Buffer.BlockCopy(data, 0, result, 0, info.NBytes); - return result; - } - - private static PyObject deepcopy; - - private static readonly Lazy np = new(InitializeNumpy); - - private static readonly Dictionary np_dtypes = new(); - - private static readonly Dictionary csharp_dtypes = new() - { - { "uint8", typeof(byte) }, - { "uint16", typeof(ushort) }, - { "uint32", typeof(uint) }, - { "uint64", typeof(ulong) }, - { "int16", typeof(short) }, - { "int32", typeof(int) }, - { "int64", typeof(long) }, - { "float32", typeof(float) }, - { "float64", typeof(double) }, - }; - - public static PyObject InitializeNumpy() - { - var np = Py.Import("numpy"); - np_dtypes.Add(typeof(byte), np.GetAttr("uint8")); - np_dtypes.Add(typeof(ushort), np.GetAttr("uint16")); - np_dtypes.Add(typeof(uint), np.GetAttr("uint32")); - np_dtypes.Add(typeof(ulong), np.GetAttr("uint64")); - np_dtypes.Add(typeof(short), np.GetAttr("int16")); - np_dtypes.Add(typeof(int), np.GetAttr("int32")); - np_dtypes.Add(typeof(long), np.GetAttr("int64")); - np_dtypes.Add(typeof(float), np.GetAttr("float32")); - np_dtypes.Add(typeof(double), np.GetAttr("float64")); - var copy = Py.Import("copy"); - deepcopy = copy.GetAttr("deepcopy"); - return np; - } - - public static bool IsNumPyArray(PyObject obj) - { - dynamic numpy = np.Value; - return numpy.ndarray.__instancecheck__(obj); - } - - public static PyObject GetNumpyDataType(Type type) - { - PyObject dtype; - np_dtypes.TryGetValue(type, out dtype); - if (dtype == null) - { - throw new Exception($"type '{type}' not supported."); - } - return dtype; - } - - public static Type GetCSharpDataType(string str) - { - Type type; - csharp_dtypes.TryGetValue(str, out type); - if (type == null) - { - throw new Exception($"type '{type}' not supported."); - } - return type; - } - - public class NumpyDataTypes : StringConverter - { - public override bool GetStandardValuesSupported(ITypeDescriptorContext context) - { - return true; - } - - public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) - { - var dtypes = new List - { - "int16", - "int32", - "int64", - "uint8", - "uint16", - "uint32", - "uint64", - "float32", - "float64" - }; - return new StandardValuesCollection(dtypes); - } - } - - public class NumpyParser - { - public static string ParseArray(Array array) - { - StringBuilder sb = new StringBuilder(); - ParseArrayToStringRecursive(array, sb, new int[0]); - return sb.ToString(); - } - - private static void ParseArrayToStringRecursive(Array array, StringBuilder sb, int[] indices) - { - if (indices.Length < array.Rank) - { - sb.Append("["); - int length = array.GetLength(indices.Length); - for (int i = 0; i < length; i++) - { - int[] newIndices = new int[indices.Length + 1]; - indices.CopyTo(newIndices, 0); - newIndices[indices.Length] = i; - ParseArrayToStringRecursive(array, sb, newIndices); - if (i < length - 1) - { - sb.Append(", "); - } - } - sb.Append("]"); - } - else - { - object value = array.GetValue(indices); - sb.Append(value.ToString()); - } - } - - private static bool IsValidJson(string input) - { - int squareBrackets = 0; - foreach (char c in input) - { - if (c == '[') squareBrackets++; - else if (c == ']') squareBrackets--; - } - return squareBrackets == 0; - } - - public static Array ParseString(string input, Type dtype) - { - try - { - if (!IsValidJson(input)) - { - throw new ArgumentException("JSON is invalid."); - } - var obj = JsonConvert.DeserializeObject(input); - int depth = ParseDepth(obj); - int[] dimensions = ParseDimensions(obj, depth); - var resultArray = Array.CreateInstance(dtype, dimensions); - PopulateArray(obj, resultArray, new int[0], dtype); - return resultArray; - } - catch (Exception ex) - { - throw new Exception("Error parsing input string.", ex); - } - } - - private static int ParseDepth(JToken token, int currentDepth = 0) - { - if (token is JArray arr && arr.Count > 0) - { - return ParseDepth(arr[0], currentDepth + 1); - } - return currentDepth; - } - - private static int[] ParseDimensions(JToken token, int depth, int currentLevel = 0) - { - if (depth == 0 || !(token is JArray)) - { - return new int[0]; - } - - List dimensions = new List(); - JToken current = token; - - while (current != null && current is JArray) - { - JArray currentArray = current as JArray; - dimensions.Add(currentArray.Count); - if (currentArray.Count > 0) - { - if (currentArray.Any(item => !(item is JArray)) && currentArray.Any(item => item is JArray) || currentArray.All(item => item is JArray) && currentArray.Any(item => ((JArray)item).Count != ((JArray)currentArray.First()).Count)) - { - throw new Exception("Error parsing input string."); - } - - if (!(currentArray.First() is JArray) && !currentArray.All(item => double.TryParse(item.ToString(), out _))) - { - throw new Exception("Error parsing non numeric types."); - } - } - - current = currentArray.Count > 0 ? currentArray[0] : null; - } - - if (currentLevel > 0 && token is JArray arr && arr.All(x => x is JArray)) - { - var subArrayDimensions = new HashSet(); - foreach (JArray subArr in arr) - { - int[] subDims = ParseDimensions(subArr, depth - currentLevel, currentLevel + 1); - subArrayDimensions.Add(string.Join(",", subDims)); - } - - if (subArrayDimensions.Count > 1) - { - throw new ArgumentException("Inconsistent array dimensions."); - } - } - - return dimensions.ToArray(); - } - - private static void PopulateArray(JToken token, Array array, int[] indices, Type dtype) - { - if (token is JArray arr) - { - for (int i = 0; i < arr.Count; i++) - { - int[] newIndices = new int[indices.Length + 1]; - Array.Copy(indices, newIndices, indices.Length); - newIndices[newIndices.Length - 1] = i; - PopulateArray(arr[i], array, newIndices, dtype); - } - } - else - { - var values = ParseType(token, dtype); - array.SetValue(values, indices); - } - } - - private static object ParseType(object value, Type targetType) - { - try - { - return Convert.ChangeType(value, targetType); - } - catch (Exception ex) - { - throw new Exception("Error parsing type: ", ex); - } - } - } - } -} diff --git a/src/Bonsai.ML.LinearDynamicalSystems/PythonHelper.cs b/src/Bonsai.ML.LinearDynamicalSystems/PythonHelper.cs deleted file mode 100644 index 30f5bf63..00000000 --- a/src/Bonsai.ML.LinearDynamicalSystems/PythonHelper.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Python.Runtime; -using System; -using System.Collections.Generic; - -namespace Bonsai.ML.LinearDynamicalSystems -{ - static class PythonHelper - { - public static object GetArrayAttribute(this PyObject pyObject, string attributeName) - { - using var attr = pyObject.GetAttr(attributeName); - return ConvertPythonObjectToCSharp(attr); - } - - public static T GetAttr(this PyObject pyObject, string attributeName) - { - using var attr = pyObject.GetAttr(attributeName); - return attr.As(); - } - - public static object ConvertPythonObjectToCSharp(PyObject pyObject) - { - if (PyInt.IsIntType(pyObject)) - { - return pyObject.As(); - } - - if (PyFloat.IsFloatType(pyObject)) - { - return pyObject.As(); - } - - if (PyString.IsStringType(pyObject)) - { - return pyObject.As(); - } - - if (PyList.IsListType(pyObject)) - { - var pyList = new PyList(pyObject); - var resultList = new List(); - foreach (PyObject item in pyList) - resultList.Add(ConvertPythonObjectToCSharp(item)); - return resultList; - } - - if (PyDict.IsDictType(pyObject)) - { - var pyDict = new PyDict(pyObject); - var resultDict = new Dictionary(); - foreach (PyObject key in pyDict.Keys()) - { - var value = pyDict[key]; - resultDict.Add(ConvertPythonObjectToCSharp(key), ConvertPythonObjectToCSharp(value)); - } - return resultDict; - } - - if (NumpyHelper.IsNumPyArray(pyObject)) - { - return NumpyHelper.PyObjectToArray(pyObject); - } - - throw new InvalidOperationException("Unable to convert python data type to C#. Allowed data types include: integer, float, string, list, dictionary, and numpy arrays"); - } - } -} diff --git a/src/Bonsai.ML.LinearDynamicalSystems/SerializeToJson.cs b/src/Bonsai.ML.LinearDynamicalSystems/SerializeToJson.cs index 1cbf5a64..ae78ea0e 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/SerializeToJson.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems/SerializeToJson.cs @@ -115,6 +115,17 @@ public IObservable Process(IObservable source) return Process(source); } + /// + /// Serializes each object in the sequence to + /// a JSON string. + /// + /// + /// A sequence of objects. + /// + /// + /// A sequence of JSON strings representing the corresponding + /// object. + /// public IObservable Process(IObservable source) { return Process(source); diff --git a/src/Bonsai.ML.LinearDynamicalSystems/State.cs b/src/Bonsai.ML.LinearDynamicalSystems/State.cs index 0cb3eba7..53d155db 100644 --- a/src/Bonsai.ML.LinearDynamicalSystems/State.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems/State.cs @@ -4,6 +4,7 @@ using Python.Runtime; using System.Xml.Serialization; using Newtonsoft.Json; +using Bonsai.ML.Python; namespace Bonsai.ML.LinearDynamicalSystems { @@ -65,8 +66,8 @@ public IObservable Process(IObservable source) { return Observable.Select(source, pyObject => { - var xPyObj = (double[,])pyObject.GetArrayAttribute("x"); - var PPyObj = (double[,])pyObject.GetArrayAttribute("P"); + var xPyObj = (double[,])pyObject.GetArrayAttr("x"); + var PPyObj = (double[,])pyObject.GetArrayAttr("P"); return new State { X = xPyObj, diff --git a/src/Bonsai.ML.Python/Bonsai.ML.Python.csproj b/src/Bonsai.ML.Python/Bonsai.ML.Python.csproj index 2015f856..4276d89c 100644 --- a/src/Bonsai.ML.Python/Bonsai.ML.Python.csproj +++ b/src/Bonsai.ML.Python/Bonsai.ML.Python.csproj @@ -6,8 +6,9 @@ net472;netstandard2.0 - - - + + + + diff --git a/src/Bonsai.ML.Python/NumpyHelper.cs b/src/Bonsai.ML.Python/NumpyHelper.cs index 9ea3dfa7..a0f87357 100644 --- a/src/Bonsai.ML.Python/NumpyHelper.cs +++ b/src/Bonsai.ML.Python/NumpyHelper.cs @@ -2,10 +2,6 @@ using Python.Runtime; using System.Collections.Generic; using System.ComponentModel; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System.Text; -using System.Linq; using System.Runtime.InteropServices; namespace Bonsai.ML.Python diff --git a/tests/Bonsai.ML.LinearDynamicalSystems.Tests/ReceptiveFieldSimpleCell/ReceptiveFieldSimpleCellTest.cs b/tests/Bonsai.ML.LinearDynamicalSystems.Tests/ReceptiveFieldSimpleCell/ReceptiveFieldSimpleCellTest.cs index 3ad8a955..79caa9eb 100644 --- a/tests/Bonsai.ML.LinearDynamicalSystems.Tests/ReceptiveFieldSimpleCell/ReceptiveFieldSimpleCellTest.cs +++ b/tests/Bonsai.ML.LinearDynamicalSystems.Tests/ReceptiveFieldSimpleCell/ReceptiveFieldSimpleCellTest.cs @@ -7,6 +7,9 @@ namespace Bonsai.ML.LinearDynamicalSystems.Tests.ReceptiveFieldSimpleCell; +/// +/// Tests for the ReceptiveFieldSimpleCell workflow. +/// [TestClass] public class ReceptiveFieldSimpleCellTest { @@ -107,18 +110,10 @@ await WorkflowHelper.RunWorkflow( finally { Environment.CurrentDirectory = currentDirectory; } } - private string GetJsonData(string jsonFileName) - { - string jsonString = File.ReadAllText(jsonFileName); - State state = JsonConvert.DeserializeObject(jsonString); - string jsonState = JsonConvert.SerializeObject(state); - return jsonState; - } - private State GetStateFromJson(string jsonFileName) { string jsonString = File.ReadAllText(jsonFileName); - State state = JsonConvert.DeserializeObject(jsonString); + State state = JsonConvert.DeserializeObject(jsonString) ?? new State(); return state; } @@ -164,6 +159,9 @@ private bool CompareJSONData(string basePath, double tolerance = 1e-9) return true; } + /// + /// Setup for the test. + /// [TestInitialize] [DeploymentItem("run_python_test.py")] [DeploymentItem("receptive_field.py")] @@ -177,6 +175,9 @@ public async Task TestSetup() await RunBonsaiWorkflow(basePath); } + /// + /// Compares the results from the Python script and the Bonsai workflow. + /// [TestMethod] public void CompareResults() { @@ -184,6 +185,9 @@ public void CompareResults() Assert.IsTrue(result); } + /// + /// Cleanup after the test. + /// [TestCleanup] public void Cleanup() {