diff --git a/.gitignore b/.gitignore
index 3e759b7..9ee9bbb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -328,3 +328,4 @@ ASALocalRun/
# MFractors (Xamarin productivity tool) working folder
.mfractor/
+*.key
diff --git a/Numpy.NET.sln b/Numpy.NET.sln
index a11bc36..a0a1c92 100644
--- a/Numpy.NET.sln
+++ b/Numpy.NET.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.28307.645
+# Visual Studio Version 17
+VisualStudioVersion = 17.4.33103.184
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Numpy", "src\Numpy\Numpy.csproj", "{D527C885-AD64-4499-9E92-F9A543C0D14B}"
EndProject
@@ -15,6 +15,30 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Numpy.Bare", "src\Numpy.Bar
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Numpy.Bare.UnitTest", "test\Numpy.UnitTest\Numpy.Bare.UnitTest.csproj", "{3E69A902-0C8F-4FF4-BA27-EAB9D2E08FEA}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReleaseBot", "src\ReleaseBot\ReleaseBot.csproj", "{2BAEA60C-88A2-45DC-8044-2C9571E1B8CF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeMinion.ApiGenerator", "src\CodeMinion.ApiGenerator\CodeMinion.ApiGenerator.csproj", "{FDE7E8A2-011A-47D5-B35B-F52ABFE5D5A8}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeMinion.Core", "src\CodeMinion.Core\CodeMinion.Core.csproj", "{72369115-A8B9-4BD6-BF55-CAB06A575EE0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeMinion.Parser", "src\CodeMinion.DocsParser\CodeMinion.Parser.csproj", "{C7768F3C-7218-409A-8626-009D5C448C0C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NeuralNetworkExample", "src\Examples\NeuralNetworkExample\NeuralNetworkExample.csproj", "{53CD5C07-7902-4761-B00B-0171AB6C7620}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApiExample_netcore2.2", "src\Examples\WebApiExample\WebApiExample_netcore2.2.csproj", "{445655A8-E4FC-4257-9CA2-63D67D84F2A2}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCoreTest", "src\Examples\NetCoreTest\NetCoreTest.csproj", "{84BCB8CA-6B29-48D8-BEEE-751C7547419E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Numpy.Bare.Dotnet", "src\Numpy.Bare.Dotnet\Numpy.Bare.Dotnet.csproj", "{8E1BD94E-6AE4-46D9-B0BA-6AC0515AF0D0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApiExample_netcore3.1", "src\Examples\WebApiExample_netcore3.1\WebApiExample_netcore3.1.csproj", "{53C73261-DD84-47D1-A9BA-E553D34FF0A3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomInstallLocationExample", "src\Examples\CustomInstallLocationExample\CustomInstallLocationExample.csproj", "{BB0A367A-8A36-454F-9F92-2FD6DA665A39}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SlicingExample", "src\Examples\SlicingExample\SlicingExample.csproj", "{FB116716-8C1F-4926-86F9-03AE46C7FA58}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfExample", "WpfExample\WpfExample.csproj", "{BF447620-877B-4000-BF75-527AEF94F347}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -41,12 +65,67 @@ Global
{3E69A902-0C8F-4FF4-BA27-EAB9D2E08FEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E69A902-0C8F-4FF4-BA27-EAB9D2E08FEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E69A902-0C8F-4FF4-BA27-EAB9D2E08FEA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2BAEA60C-88A2-45DC-8044-2C9571E1B8CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2BAEA60C-88A2-45DC-8044-2C9571E1B8CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2BAEA60C-88A2-45DC-8044-2C9571E1B8CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2BAEA60C-88A2-45DC-8044-2C9571E1B8CF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FDE7E8A2-011A-47D5-B35B-F52ABFE5D5A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FDE7E8A2-011A-47D5-B35B-F52ABFE5D5A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FDE7E8A2-011A-47D5-B35B-F52ABFE5D5A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FDE7E8A2-011A-47D5-B35B-F52ABFE5D5A8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {72369115-A8B9-4BD6-BF55-CAB06A575EE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {72369115-A8B9-4BD6-BF55-CAB06A575EE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {72369115-A8B9-4BD6-BF55-CAB06A575EE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {72369115-A8B9-4BD6-BF55-CAB06A575EE0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C7768F3C-7218-409A-8626-009D5C448C0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C7768F3C-7218-409A-8626-009D5C448C0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C7768F3C-7218-409A-8626-009D5C448C0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C7768F3C-7218-409A-8626-009D5C448C0C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {53CD5C07-7902-4761-B00B-0171AB6C7620}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53CD5C07-7902-4761-B00B-0171AB6C7620}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53CD5C07-7902-4761-B00B-0171AB6C7620}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {53CD5C07-7902-4761-B00B-0171AB6C7620}.Release|Any CPU.Build.0 = Release|Any CPU
+ {445655A8-E4FC-4257-9CA2-63D67D84F2A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {445655A8-E4FC-4257-9CA2-63D67D84F2A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {445655A8-E4FC-4257-9CA2-63D67D84F2A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {445655A8-E4FC-4257-9CA2-63D67D84F2A2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {84BCB8CA-6B29-48D8-BEEE-751C7547419E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {84BCB8CA-6B29-48D8-BEEE-751C7547419E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {84BCB8CA-6B29-48D8-BEEE-751C7547419E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {84BCB8CA-6B29-48D8-BEEE-751C7547419E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8E1BD94E-6AE4-46D9-B0BA-6AC0515AF0D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8E1BD94E-6AE4-46D9-B0BA-6AC0515AF0D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8E1BD94E-6AE4-46D9-B0BA-6AC0515AF0D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8E1BD94E-6AE4-46D9-B0BA-6AC0515AF0D0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {53C73261-DD84-47D1-A9BA-E553D34FF0A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53C73261-DD84-47D1-A9BA-E553D34FF0A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53C73261-DD84-47D1-A9BA-E553D34FF0A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {53C73261-DD84-47D1-A9BA-E553D34FF0A3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BB0A367A-8A36-454F-9F92-2FD6DA665A39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BB0A367A-8A36-454F-9F92-2FD6DA665A39}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BB0A367A-8A36-454F-9F92-2FD6DA665A39}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BB0A367A-8A36-454F-9F92-2FD6DA665A39}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FB116716-8C1F-4926-86F9-03AE46C7FA58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FB116716-8C1F-4926-86F9-03AE46C7FA58}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FB116716-8C1F-4926-86F9-03AE46C7FA58}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FB116716-8C1F-4926-86F9-03AE46C7FA58}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BF447620-877B-4000-BF75-527AEF94F347}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BF447620-877B-4000-BF75-527AEF94F347}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BF447620-877B-4000-BF75-527AEF94F347}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BF447620-877B-4000-BF75-527AEF94F347}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{A92C1287-BF2B-4FDC-8BBA-A17F410CD41F} = {25D84E98-E107-45C9-A0EC-0B25E24DA607}
+ {53CD5C07-7902-4761-B00B-0171AB6C7620} = {25D84E98-E107-45C9-A0EC-0B25E24DA607}
+ {445655A8-E4FC-4257-9CA2-63D67D84F2A2} = {25D84E98-E107-45C9-A0EC-0B25E24DA607}
+ {84BCB8CA-6B29-48D8-BEEE-751C7547419E} = {25D84E98-E107-45C9-A0EC-0B25E24DA607}
+ {53C73261-DD84-47D1-A9BA-E553D34FF0A3} = {25D84E98-E107-45C9-A0EC-0B25E24DA607}
+ {BB0A367A-8A36-454F-9F92-2FD6DA665A39} = {25D84E98-E107-45C9-A0EC-0B25E24DA607}
+ {FB116716-8C1F-4926-86F9-03AE46C7FA58} = {25D84E98-E107-45C9-A0EC-0B25E24DA607}
+ {BF447620-877B-4000-BF75-527AEF94F347} = {25D84E98-E107-45C9-A0EC-0B25E24DA607}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5EB08541-5168-443C-B524-A5CB7E7C613D}
diff --git a/README.md b/README.md
index 1983b67..9fb44ef 100644
--- a/README.md
+++ b/README.md
@@ -1,24 +1,12 @@
-# Numpy.NET
-Numpy.NET brings the awesome Python package [NumPy](https://www.numpy.org/) to the .NET world. NumPy is THE fundamental library for scientific computing, machine learning and AI in Python. Numpy.NET empowers .NET developers to leverage NumPy's extensive functionality including multi-dimensional arrays and matrices, linear algebra, FFT and many more via a compatible strong typed API.
+
+
+**Numpy.NET** is the most complete .NET binding for [NumPy](https://www.numpy.org/), which is a fundamental library for scientific computing, machine learning and AI in Python. Numpy.NET empowers .NET developers with extensive functionality including multi-dimensional arrays and matrices, linear algebra, FFT and many more via a compatible strong typed API. Several other SciSharp projects like [Keras.NET](https://github.com/SciSharp/Keras.NET) and [Torch.NET](https://github.com/SciSharp/Torch.NET) depend on Numpy.NET.
## Example
-Python:
-```python
-import numpy as np
-a1=np.arange(60000).reshape(300, 200)
-a2=np.arange(80000).reshape(200, 400)
-result=np.matmul(a1, a2)
-```
+Check out this example which uses `numpy` operations to fit a two-layer neural network to random data by manually implementing the forward and backward passes through the network.
-C#:
-```csharp
-using Numpy;
-// ...
-var a1 = np.arange(60000).reshape(300, 200);
-var a2 = np.arange(80000).reshape(200, 400);
-var result = np.matmul(a1, a2);
-```
+
Numpy and Intellisense: a developer-friendly combination:
@@ -28,37 +16,24 @@ Numpy and Intellisense: a developer-friendly combination:
If you want to use Numpy.NET you have two options:
### Numpy.dll
-Just reference [Numpy](https://www.nuget.org/packages/Numpy/1.0.0) via Nuget and you are good to go. Thanks to [Python.Included](https://github.com/henon/Python.Included) it doesn't require a local Python installation or will not clash with existing installations.
+Just reference [Numpy.dll](https://www.nuget.org/packages/Numpy/) via Nuget, set your **build configuration to x64** and you are good to go. Thanks to [Python.Included](https://github.com/henon/Python.Included) it doesn't require a local Python installation or will not clash with existing installations.
### Numpy.Bare.dll
-In certain use cases you might not want the packaged Python and NumPy packages. In that case you reference [Numpy.Bare](https://www.nuget.org/packages/Numpy.Bare/1.0.0) via Nuget. You will need Python 3.7 and Numpy 1.16 installed for it to work.
+In certain use cases you might not want the packaged Python and NumPy packages. In that case you reference [Numpy.Bare.dll](https://www.nuget.org/packages/Numpy.Bare/) via Nuget. Depending on the Numpy.Bare nuget version will need Python 3.5, 3.6 or 3.7 and Numpy 1.16 installed for it to work. The first two digits of the Numpy.Bare version indicate which Python version is needed for it to run (i.e. Numpy.Bare v3.6.1.1 needs Python 3.6 installed). If you are getting BadImageFormatException switch between x86 and x64 build settings.
+
+In other cases, you might want to control the install location of the Python installation or even set it up yourself instead of having the Numpy library do it. For those cases Numpy.Bare is also great. Check out the [custom installation example](https://github.com/SciSharp/Numpy.NET/tree/master/src/Examples/CustomInstallLocationExample) if you want to know how.
## How does it work?
-Numpy.NET uses [Python for .NET](http://pythonnet.github.io/) to call into the Python module `numpy`. However, this does not mean that it depends on a local Python installation! Numpy.NET.dll uses [Python.Included](https://github.com/henon/Python.Included) which packages embedded Python 3.7 and automatically deploys it in the user's home directory upon first execution. On subsequent runs, it will find Python already deployed and therefor doesn't install it again. Numpy.NET also packages the NumPy wheel and installs it into the embedded Python installation when not yet installed.
+Numpy.NET uses [Python for .NET](http://pythonnet.github.io/) to call into the Python module `numpy`. However, this does not mean that it depends on a local Python installation! Numpy.NET.dll uses [Python.Included](https://github.com/henon/Python.Included) which packages embedded Python 3.7 and automatically deploys it in the user's home directory upon first execution. On subsequent runs, it will find Python already deployed and therefore doesn't install it again. Numpy.NET also packages the NumPy wheel and installs it into the embedded Python installation when not yet installed.
Long story short: as a .NET Developer **you don't need to worry about Python** at all. You just reference Numpy.NET, use it and **it will just work**, no matter if you have local Python installations or not.
-## Performance considerations
+## Multi-threading (Must read!)
-You might ask how calling into Python affects performance. As always, it depends on your usage. Don't forget that `numpy`'s number crunching algorithms are written in `C` so the thin `pythonnet` and `Python` layers on top won't have a significant impact if you are working with larger amounds of data.
+**Beware: Not following these steps can result in deadlocks or access violation exceptions!**
-In my experience, calling `numpy` from C# is about 4 times slower than calling it directly in `Python` while the execution time of the called operation is of course equal. So if you have an algorithm that needs to call into `numpy` in a nested loop, Numpy.NET may not be for you due to the call overhead.
-
-All of `numpy` is centered around the `ndarray` class which allows you to pass a huge chunk of data into the `C` routines and let them execute all kinds of operations on the elements efficiently without the need for looping over the data. So if you are manipulating arrays or matrices with thousands or hundreds of thousands of elements, the call overhead will be neglegible.
-
-The most performance sensitive aspect is creating an `NDarray` from a `C#` array, since the data has to be moved from the `CLR` into the `Python` interpreter. `pythonnet` does not optimize for passing large arrays from `C#` to `Python` but we still found a way to do that very efficiently. When creating an array with `np.array( ... )` we internally use `Marshal.Copy` to copy the entiry `C#`-array's memory into the `numpy`-array's storage. And to efficiently retrieve computation results from `numpy` there is a method called `GetData` which will copy the data back to `C#` in the same way:
-
-```csharp
-// create a 2D-shaped NDarray from an int[]
-var m = np.array(new int[] {1, 2, 3, 4});
-// calculate the cosine of each element
-var result = np.cos(m);
-// get the floating point data of the result NDarray back to C#
-var data = result.GetData(); // double[] { 0.54030231, -0.41614684, -0.9899925 , -0.65364362 }
-```
-## Multi-threading
-Python/NumPy doesn't have real multi-threading support. There is no advantage to calling `numpy` functions from different threads because `pythonnet` requires you to use the Global Interpreter Lock (GIL) when doing so. If you must call Python from a thread other than the main thread you first must release the main thread's mutex by calling `PythonEngine.BeginAllowThreads()` or you'll have a deadlock:
+Python/NumPy doesn't have real multi-threading support. There is no advantage in "simultaneously" executing `numpy` functions on multiple threads because `pythonnet` requires you to use the Global Interpreter Lock (GIL) to lock access to the Python engine exclusively for only one thread at a time. If you have to call Python from a thread other than the main thread you first must release the main thread's mutex by calling `PythonEngine.BeginAllowThreads()` or you'll have a deadlock:
```csharp
var a = np.arange(1000);
@@ -75,23 +50,40 @@ Task.Run(()=> {
}
}).Wait();
```
+Above example only serves as a reference on how to call `numpy` from a different thread than the main thread. As said before, having multiple background threads that call into Python doesn't give you multi-core processing because of the requirement to lock the GIL. Not doing so will result in **access violation exceptions** and/or **deadlocks**.
+
+Note that you must call a method of `np` before calling `PythonEngine.BeginAllowThreads()` in order for the PythonEngine to be initialized. So, for instance, if you want to initialize an inherently multi-threaded .Net Core Web API at startup, do something like this:
+
+```csharp
+np.arange(1);
+PythonEngine.BeginAllowThreads();
+```
+Also, if you do this, be sure to wrap any calls to Numpy in `using (Py.GIL()) { ... }` or else you'll get AccessViolationExceptions.
+
+## Performance considerations
-Above example only serves as a reference how to call `numpy` from a different thread than the main thread. Having multiple background threads that call into Python doesn't give you multi-core processing though because of the requirement to lock the GIL. Not doing so will result in access violation exceptions.
+You might ask how calling into Python affects performance. As always, it depends on your usage. Don't forget that `numpy`'s number crunching algorithms are written in `C` so the thin `pythonnet` and `Python` layers on top won't have a significant impact if you are working with larger amounts of data.
+
+In my experience, calling `numpy` from C# is about 4 times slower than calling it directly in `Python` while the execution time of the called operation is of course equal. So if you have an algorithm that needs to call into `numpy` in a nested loop, Numpy.NET may not be for you due to the call overhead.
+
+All of `numpy` is centered around the `ndarray` class which allows you to pass a huge chunk of data into the `C` routines and let them execute all kinds of operations on the elements efficiently without the need for looping over the data. So if you are manipulating arrays or matrices with thousands or hundreds of thousands of elements, the call overhead will be negligible.
+
+The most performance sensitive aspect is creating an `NDarray` from a `C#` array, since the data has to be moved from the `CLR` into the `Python` interpreter. `pythonnet` does not optimize for passing large arrays from `C#` to `Python` but we still found a way to do that very efficiently. When creating an array with `np.array( ... )` we internally use `Marshal.Copy` to copy the entire `C#`-array's memory into the `numpy`-array's storage. And to efficiently retrieve computation results from `numpy` there is a method called `GetData` which will copy the data back to `C#` in the same way:
+
+```csharp
+// create a 2D-shaped NDarray from an int[]
+var m = np.array(new int[] {1, 2, 3, 4});
+// calculate the cosine of each element
+var result = np.cos(m);
+// get the floating point data of the result NDarray back to C#
+var data = result.GetData(); // double[] { 0.54030231, -0.41614684, -0.9899925 , -0.65364362 }
+```
## Numpy.NET vs NumSharp
-The SciSharp team is also developing a pure C# port of NumPy called [NumSharp](https://github.com/SciSharp/NumSharp) which is quite popular albeit incomplete. To help you decide which one to use we compare the advantages and disadvantages of both libraries here:
+The SciSharp team is also developing a pure C# port of NumPy called [NumSharp](https://github.com/SciSharp/NumSharp) which is quite popular albeit being not quite complete.
-| Aspect | Numpy.NET | NumSharp |
-| ------------- | ------------------------------------- | ------------- |
-| Dependencies | CPython / NumPy | C++ dlls for certain operations |
-| Setup | Reference Nuget-Package | Reference Nuget-Package |
-| Completeness | Large parts are wrapped | A small subset of most important functions is ported |
-| Development | Fast, due to automated API generation | Slow, due to lack of manpower |
-| Correctness | Same results as in Python guaranteed | There are subtle differences |
-| Actuality | Can easily keep up with `numpy` dev | Will trail behind, due to lack of manpower |
-| GPU support | None | Using a GPU backend for calculatons possible, per design |
-| Performance | TODO: measure | TODO: measure |
+There are a couple of other NumPy ports out there featuring subsets of the original library. The only one that matches Numpy.NET in terms of completeness is the IronPython package `numpy` which is out of date though. The SciSharp team is committed to keeping Numpy.NET up to date with the original library and to feature as much of the original functionality as possible.
## Code generation
@@ -141,6 +133,33 @@ Getting more unit tests to run is very easy though, and a good portion have alre
Since we have taken great care to make Numpy.NET as similar to NumPy itself, you can, for the most part, rely on the official [NumPy manual](https://docs.scipy.org/doc/numpy/).
+### Create a Numpy array from a C# array and vice versa
+
+To work with data from C# in Numpy it has to be copied into the Python engine by using `np.array(...)`. You get an NDarray that you can use for further processing of the data. Here we calculate the square root:
+
+```csharp
+// create an NDarray from a C# array
+var a = np.array(new[] { 2, 4, 9, 25 });
+Console.WriteLine("a: "+ a.repr);
+// a: array([ 2, 4, 9, 25])
+// apply the square root to each element
+var roots = np.sqrt(a);
+Console.WriteLine(roots.repr);
+// array([1.41421356, 2. , 3. , 5. ])
+```
+
+After processing the data you can copy it back into a C# array use `a.GetData()`, but be aware of the datatype of the NDarray in order to get correct values back:
+
+```csharp
+// Copy the NDarray roots into a C# array from NDarray (incorrect datatype)
+Console.WriteLine(string.Join(", ", roots.GetData()));
+// 1719614413, 1073127582, 0, 1073741824
+Console.WriteLine("roots.dtype: " + roots.dtype);
+// roots.dtype: float64
+Console.WriteLine(string.Join(", ", roots.GetData()));
+// 1.4142135623731, 2, 3, 5
+```
+
### Creating multi-dimensional NDarrays from C# arrays
Creating an `NDarray` from data is easy. Just pass the C# array into `np.array(...)`. You can pass 1D, 2D and 3D C# arrays into it.
@@ -216,18 +235,28 @@ var roots = np.sqrt(a); // => { 0.0, 1.0, 1.414, ..., 9.899, 9.950 }
```
#### Complex numbers
-Python has native support of complex numbers, something the C# language is lacking as well. Converting complex results to and from NumPy is not implemented at all (yet). Please step forward if you want to work on this.
+Numpy.NET supports complex numbers even though the notation in Python and C# is very different:
+```python
+>>> a = np.array([1+2j, 3+4j, 5+6j])
+```
+looks like this in C#
+```c#
+var a = np.array(new Complex[] { new Complex(1, 2), new Complex(3,4), new Complex(5,6), });
+```
+Access the real and imaginary components of a complex array via `a.real` and `a.imag` or copy the complex values of an ndarray into C# with `Complex[] c=a.GetData();`.
#### Functions clashing with their class name
The function fft(...) in numpy.fft and random(...) in numpy.random had to be renamed because C# doesn't allow a member to have the same name as its enclosing class. That's why in Numpy.NET these functions have been renamed with a trailing underscore like this: `np.fft.fft_(...)`
## Versions and Compatibility
-Currently, Numpy.NET is targeting .NET Standard (on Windows) and packages the following binaries:
+Currently, Numpy.dll is targeting .NET Standard (on Windows) and packages the following binaries:
* Python 3.7: (python-3.7.3-embed-amd64.zip)
* NumPy 1.16 (numpy-1.16.3-cp37-cp37m-win_amd64.whl)
-To make Numpy.NET support Linux a separate version of [Python.Included](https://github.com/henon/Python.Included) packaging linux binaries of Python needs to be made and a version of Numpy.NET that packages a linux-compatible NumPy wheel. If you are interested, you may work on this issue.
+Numpy.Bare.dll is available for the Python versions 2.7, 3.5, 3.6 and 3.7 on Windows, Linux and MacOS on Nuget.
+
+To make Numpy.dll support Linux a separate version of [Python.Included](https://github.com/henon/Python.Included) packaging linux binaries of Python needs to be made and a version of Numpy.dll that packages a linux-compatible NumPy wheel. If you are interested, you may work on this issue.
## License
@@ -238,4 +267,11 @@ Numpy.NET packages and distributes `Python`, `pythonnet` as well as `numpy`. All
* NumPy: [BSD License](https://www.numpy.org/license.html#license)
* Numpy.NET: [MIT License](./LICENSE)
+## Common Mistakes
+* If you check `Prefer 32-bit` in your build config or build with `x86` instead of `Any CPU` Numpy.NET will crash with `BadFormatException`
+* If you have insufficient folder permissions in AppData Numpy.NET might crash. You can specify a different installpath by setting `Installer.INSTALL_PATH = "";`
+* If you get deadlocks (program hangs indefinitely) you should read the secton about multi-threading above!
+* If you get AccessViolationExceptions you should read the secton about multi-threading above!
+## Project Sponsors
+* [JetBrains](https://www.jetbrains.com/?from=Numpy.NET)
diff --git a/WpfExample/App.xaml b/WpfExample/App.xaml
new file mode 100644
index 0000000..8bcbf4d
--- /dev/null
+++ b/WpfExample/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/WpfExample/App.xaml.cs b/WpfExample/App.xaml.cs
new file mode 100644
index 0000000..66421cb
--- /dev/null
+++ b/WpfExample/App.xaml.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace WpfExample
+{
+
+ public partial class App : Application
+ {
+
+ }
+}
diff --git a/WpfExample/AssemblyInfo.cs b/WpfExample/AssemblyInfo.cs
new file mode 100644
index 0000000..74087a1
--- /dev/null
+++ b/WpfExample/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/WpfExample/MainWindow.xaml b/WpfExample/MainWindow.xaml
new file mode 100644
index 0000000..82bf2e4
--- /dev/null
+++ b/WpfExample/MainWindow.xaml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ Run the blocking example first, then the non-blocking example will be activated.
+
+
+
+
diff --git a/WpfExample/MainWindow.xaml.cs b/WpfExample/MainWindow.xaml.cs
new file mode 100644
index 0000000..a5e2290
--- /dev/null
+++ b/WpfExample/MainWindow.xaml.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using Numpy;
+using Python.Runtime;
+
+namespace WpfExample
+{
+
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+
+ private bool _allowThreads = false;
+
+ private void WriteLine(string text)
+ {
+ TextBox.AppendText(text + "\n");
+ TextBox.ScrollToEnd();
+ }
+
+ private void OnBlockingClick(object sender, RoutedEventArgs e)
+ {
+ WriteLine("Example 1: Matrix multiplication with NumPy on the GUI thread (blocking):");
+ // before starting the measurement, let us call numpy once to get the setup checks done.
+ np.arange(1);
+ var stopwatch = Stopwatch.StartNew();
+
+ var a1 = np.arange(60000).reshape(300, 200);
+ var a2 = np.arange(80000).reshape(200, 400);
+
+ var result = np.matmul(a1, a2);
+ stopwatch.Stop();
+
+ WriteLine($"execution time with NumPy: {stopwatch.Elapsed.TotalMilliseconds}ms\n");
+ WriteLine("Result:\n" + result.repr);
+ WriteLine("\nNote: blocking usage is not recommended. ");
+ WriteLine("\nIf you close the program without runnning example 2 it will hang indefinitely. ");
+ Button1.IsEnabled = false;
+ Button2.IsEnabled = true;
+ }
+
+ private async void OnNonBlockingClick(object sender, RoutedEventArgs e)
+ {
+ WriteLine("Example 2: Matrix multiplication with NumPy on a background thread (non-blocking):");
+
+ if (!_allowThreads) {
+ // https://github.com/pythonnet/pythonnet/issues/109
+ PythonEngine.BeginAllowThreads();
+ _allowThreads=true;
+ }
+ var stopwatch = Stopwatch.StartNew();
+ var resultString = "";
+ await Task.Run(() => {
+ using (Py.GIL()) {
+
+
+ var a1 = np.arange(60000).reshape(300, 200);
+ var a2 = np.arange(80000).reshape(200, 400);
+
+ var result = np.matmul(a1, a2);
+ stopwatch.Stop();
+ resultString = result.repr;
+ }
+ });
+ await this.Dispatcher.BeginInvoke(() => {
+ WriteLine($"execution time with NumPy: {stopwatch.Elapsed.TotalMilliseconds}ms\n");
+ WriteLine("Result:\n" + resultString);
+ });
+ WriteLine("\nNote: if you close the program now it will not hang because of PythonEngine.BeginAllowThreads();\nWe only have to make sure to enclose all calculations in using(Py.GIL()) { }");
+ }
+ }
+}
diff --git a/WpfExample/WpfExample.csproj b/WpfExample/WpfExample.csproj
new file mode 100644
index 0000000..475c825
--- /dev/null
+++ b/WpfExample/WpfExample.csproj
@@ -0,0 +1,14 @@
+
+
+
+ WinExe
+ net6.0-windows
+ enable
+ true
+
+
+
+
+
+
+
diff --git a/doc/img/Logo.md b/doc/img/Logo.md
new file mode 100644
index 0000000..10b7a5a
--- /dev/null
+++ b/doc/img/Logo.md
@@ -0,0 +1 @@
+Numpy.NET logo (c) 2019 by Meinrad Recheis.
\ No newline at end of file
diff --git a/doc/img/cs_vs_py.png b/doc/img/cs_vs_py.png
new file mode 100644
index 0000000..a3d5e7f
Binary files /dev/null and b/doc/img/cs_vs_py.png differ
diff --git a/doc/img/cs_vs_py.svg b/doc/img/cs_vs_py.svg
new file mode 100644
index 0000000..53fbad8
--- /dev/null
+++ b/doc/img/cs_vs_py.svg
@@ -0,0 +1,2058 @@
+
+
+
+
diff --git a/doc/img/cs_vs_py2.png b/doc/img/cs_vs_py2.png
new file mode 100644
index 0000000..d2c135f
Binary files /dev/null and b/doc/img/cs_vs_py2.png differ
diff --git a/doc/img/numpy.net.icon.purple.png b/doc/img/numpy.net.icon.purple.png
new file mode 100644
index 0000000..d37713d
Binary files /dev/null and b/doc/img/numpy.net.icon.purple.png differ
diff --git a/doc/img/numpy.net.icon.purple.svg b/doc/img/numpy.net.icon.purple.svg
new file mode 100644
index 0000000..cdd8a23
--- /dev/null
+++ b/doc/img/numpy.net.icon.purple.svg
@@ -0,0 +1,755 @@
+
+
+
+
diff --git a/doc/img/numpy.net.icon.svg b/doc/img/numpy.net.icon.svg
new file mode 100644
index 0000000..9689c37
--- /dev/null
+++ b/doc/img/numpy.net.icon.svg
@@ -0,0 +1,2057 @@
+
+
+
+
diff --git a/doc/img/numpy.net.icon128.png b/doc/img/numpy.net.icon128.png
new file mode 100644
index 0000000..51fe4bd
Binary files /dev/null and b/doc/img/numpy.net.icon128.png differ
diff --git a/doc/img/numpy.net.icon512.png b/doc/img/numpy.net.icon512.png
new file mode 100644
index 0000000..196d2e6
Binary files /dev/null and b/doc/img/numpy.net.icon512.png differ
diff --git a/doc/img/numpy.net.logo.quadratic.svg b/doc/img/numpy.net.logo.quadratic.svg
new file mode 100644
index 0000000..8a8d948
--- /dev/null
+++ b/doc/img/numpy.net.logo.quadratic.svg
@@ -0,0 +1,983 @@
+
+
+
+
diff --git a/doc/img/numpy.net.logo.quadratic512.png b/doc/img/numpy.net.logo.quadratic512.png
new file mode 100644
index 0000000..1ae1dc0
Binary files /dev/null and b/doc/img/numpy.net.logo.quadratic512.png differ
diff --git a/doc/img/numpy.net.logo.svg b/doc/img/numpy.net.logo.svg
new file mode 100644
index 0000000..3493316
--- /dev/null
+++ b/doc/img/numpy.net.logo.svg
@@ -0,0 +1,983 @@
+
+
+
+
diff --git a/doc/img/numpy.net.logo512.png b/doc/img/numpy.net.logo512.png
new file mode 100644
index 0000000..0fb524a
Binary files /dev/null and b/doc/img/numpy.net.logo512.png differ
diff --git a/src/CodeMinion.ApiGenerator/CodeMinion.ApiGenerator.csproj b/src/CodeMinion.ApiGenerator/CodeMinion.ApiGenerator.csproj
new file mode 100644
index 0000000..8515051
--- /dev/null
+++ b/src/CodeMinion.ApiGenerator/CodeMinion.ApiGenerator.csproj
@@ -0,0 +1,44 @@
+
+
+
+ Exe
+ netcoreapp2.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
diff --git a/src/CodeMinion.ApiGenerator/NumPy/ApiGenerator.cs b/src/CodeMinion.ApiGenerator/NumPy/ApiGenerator.cs
new file mode 100644
index 0000000..5709388
--- /dev/null
+++ b/src/CodeMinion.ApiGenerator/NumPy/ApiGenerator.cs
@@ -0,0 +1,1613 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading;
+using CodeMinion.Core;
+using CodeMinion.Core.Helpers;
+using CodeMinion.Core.Models;
+using CodeMinion.Parser;
+using HtmlAgilityPack;
+using Torch.ApiGenerator;
+
+namespace CodeMinion.ApiGenerator.NumPy
+{
+ // Routines: [x] means generated
+ // ====================
+ // [x] Array creation routines
+ // [x] Array manipulation routines
+ // [x] Binary operations
+ // [x] String operations
+ // [x] Datetime Support Functions
+ // [x] Data type routines
+ // [x] Optionally Scipy-accelerated routines(numpy.dual)
+ // [ ] Floating point error handling
+ // [x] Discrete Fourier Transform(numpy.fft)
+ // [x] Financial functions
+ // [ ] Functional programming
+ // [x] Indexing routines
+ // [x] Input and output
+ // [x] Linear algebra(numpy.linalg)
+ // [x] Logic functions
+ // [ ] Masked array operations
+ // [x] Mathematical functions
+ // [ ] Matrix library(numpy.matlib)
+ // [ ] Miscellaneous routines
+ // [x] Padding Arrays
+ // [ ] Polynomials
+ // [x] Random sampling(numpy.random)
+ // [x] Set routines
+ // [x] Sorting, searching, and counting
+ // [x] Statistics
+ // [x] Window functions
+
+
+ public class ApiGenerator : ICodeGenerator
+ {
+ private CodeGenerator _generator;
+ public ApiGenerator()
+ {
+ var dir = Directory.GetCurrentDirectory();
+ var src_dir = dir.Substring(0, dir.LastIndexOf("\\src\\")) + "\\src\\";
+ var test_dir = dir.Substring(0, dir.LastIndexOf("\\src\\")) + "\\test\\";
+
+ _generator = new CodeGenerator
+ {
+ CopyrightNotice = "Copyright (c) 2020 by Meinrad Recheis (Member of SciSharp)",
+ NameSpace = "Numpy",
+ StaticModuleName = "np",
+ PythonModuleName="numpy",
+ TestFilesPath = Path.Combine(test_dir, "Numpy.UnitTest"),
+ Usings = { "using Numpy.Models;" },
+ ToPythonConversions = {
+ "case Axis o: return o.Axes==null ? null : ToTuple(o.Axes);",
+ "case Shape o: return ToTuple(o.Dimensions);",
+ "case Slice o: return o.ToPython();",
+ "case PythonObject o: return o.PyObject;",
+ "case Dictionary o: return ToDict(o);",
+ },
+ ToCsharpConversions =
+ {
+ "case \"Dtype\": return (T)(object)new Dtype(pyobj);",
+ "case \"NDarray\": return (T)(object)new NDarray(pyobj);",
+ "case \"NDarray`1\":",
+ "switch (typeof(T).GenericTypeArguments[0].Name)",
+ "{",
+ " case \"Byte\": return (T)(object)new NDarray(pyobj);",
+ " case \"Short\": return (T)(object)new NDarray(pyobj);",
+ " case \"Boolean\": return (T)(object)new NDarray(pyobj);",
+ " case \"Int32\": return (T)(object)new NDarray(pyobj);",
+ " case \"Int64\": return (T)(object)new NDarray(pyobj); ",
+ " case \"Single\": return (T)(object)new NDarray(pyobj); ",
+ " case \"Double\": return (T)(object)new NDarray(pyobj); ",
+ " default: throw new NotImplementedException($\"Type NDarray<{typeof(T).GenericTypeArguments[0].Name}> missing. Add it to 'ToCsharpConversions'\");",
+ "}",
+ "break;",
+ "case \"NDarray[]\":",
+ " var po = pyobj as PyObject;",
+ " var len = po.Length();",
+ " var rv = new NDarray[len];",
+ " for (int i = 0; i < len; i++)",
+ " rv[i] = ToCsharp(po[i]);",
+ " return (T) (object) rv;",
+ "case \"Matrix\": return (T)(object)new Matrix(pyobj);",
+ },
+ SpecialConversionGenerators = { SpecialGenerators.ConvertArrayToNDarray, SpecialGenerators.ConvertDict },
+ SharpToSharpConversions =
+ {
+ SpecialGenerators.ArrayToNDarrayConversion,
+ },
+ InitializationGenerators = { SpecialGenerators.InitNumpyGenerator },
+ };
+ }
+
+ // use this to avoid duplicates
+ HashSet parsed_api_functions = new HashSet();
+ private DynamicApi ndarray_api;
+
+ public string Generate()
+ {
+ var dir = Directory.GetCurrentDirectory();
+ var src_dir = dir.Substring(0, dir.LastIndexOf("\\src\\")) + "\\src\\";
+ // ----------------------------------------------------
+ // array creation
+ // ----------------------------------------------------
+ var array_creation_api = new StaticApi()
+ {
+ PartialName = "array_creation", // name-part of the partial class file
+ StaticName = "np", // name of the static API class
+ ImplName = "NumPy", // name of the singleton that implements the static API behind the scenes
+ PythonModule = "numpy", // name of the Python module that the static api wraps
+ };
+ _generator.StaticApis.Add(array_creation_api);
+ ParseNumpyApi(array_creation_api, "routines.array-creation.html");
+ // ----------------------------------------------------
+ // ndarray
+ // ----------------------------------------------------
+ ndarray_api = new DynamicApi()
+ {
+ ClassName = "NDarray",
+ };
+ _generator.DynamicApis.Add(ndarray_api);
+ ParseNdarrayApi(ndarray_api);
+ // ----------------------------------------------------
+ // array manipulation
+ // ----------------------------------------------------
+ var array_manipulation_api = new StaticApi() { PartialName = "array_manipulation", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(array_manipulation_api);
+ ParseNumpyApi(array_manipulation_api, "routines.array-manipulation.html");
+ // ----------------------------------------------------
+ // dtype
+ // ----------------------------------------------------
+ var dtype_api = new StaticApi() { PartialName = "dtype", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(dtype_api);
+ ParseDtypeApi(dtype_api);
+ // ----------------------------------------------------
+ // bitwise api
+ // ----------------------------------------------------
+ var bitwise_api = new StaticApi() { PartialName = "bitwise", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(bitwise_api);
+ ParseNumpyApi(bitwise_api, "routines.bitwise.html");
+ // ----------------------------------------------------
+ // String operations
+ // ----------------------------------------------------
+ var string_api = new StaticApi() { PartialName = "string", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(string_api);
+ ParseNumpyApi(string_api, "routines.char.html");
+ // ----------------------------------------------------
+ // Datetime Support Functions
+ // ----------------------------------------------------
+ var datetime_api = new StaticApi() { PartialName = "datetime", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(datetime_api);
+ ParseNumpyApi(datetime_api, "routines.datetime.html");
+ // ----------------------------------------------------
+ // Data type routines
+ // ----------------------------------------------------
+ var dtype_routines_api = new StaticApi() { PartialName = "dtype.routines", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(dtype_routines_api);
+ ParseNumpyApi(dtype_routines_api, "routines.dtype.html");
+ // ----------------------------------------------------
+ // Optionally Scipy-accelerated routines (linalg, fft, ...)
+ // ----------------------------------------------------
+ var linalg_fft_api = new StaticApi() { PartialName = "linalg_fft", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(linalg_fft_api);
+ ParseNumpyApi(linalg_fft_api, "routines.dual.html");
+ // ----------------------------------------------------
+ // Discrete Fourier Transform (numpy.fft)
+ // ----------------------------------------------------
+ var fft_api = new StaticApi() { PartialName = "fft", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(fft_api);
+ ParseNumpyApi(fft_api, "routines.fft.html");
+ // ----------------------------------------------------
+ // Financial functions
+ // ----------------------------------------------------
+ var financial_api = new StaticApi() { PartialName = "financial", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(financial_api);
+ ParseNumpyApi(financial_api, "routines.financial.html");
+ // ----------------------------------------------------
+ // Indexing routines
+ // ----------------------------------------------------
+ var indexing_api = new StaticApi() { PartialName = "indexing", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(indexing_api);
+ ParseNumpyApi(indexing_api, "routines.indexing.html");
+ // ----------------------------------------------------
+ // Input and output
+ // ----------------------------------------------------
+ var io_api = new StaticApi() { PartialName = "io", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(io_api);
+ ParseNumpyApi(io_api, "routines.io.html");
+ // ----------------------------------------------------
+ // Linear Algebra
+ // ----------------------------------------------------
+ var linalg_api = new StaticApi() { PartialName = "linalg", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(linalg_api);
+ ParseNumpyApi(linalg_api, "routines.linalg.html");
+ // ----------------------------------------------------
+ // Logic functions
+ // ----------------------------------------------------
+ var logic_api = new StaticApi() { PartialName = "logic", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(logic_api);
+ ParseNumpyApi(logic_api, "routines.logic.html");
+ // ----------------------------------------------------
+ // Mathematical functions
+ // ----------------------------------------------------
+ var math_api = new StaticApi() { PartialName = "math", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(math_api);
+ ParseNumpyApi(math_api, "routines.math.html");
+ // ----------------------------------------------------
+ // Padding Arrays
+ // ----------------------------------------------------
+ var padding_api = new StaticApi() { PartialName = "padding", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(padding_api);
+ ParseNumpyApi(padding_api, "routines.padding.html");
+ // ----------------------------------------------------
+ // Random sampling
+ // ----------------------------------------------------
+ var random_api = new StaticApi() { PartialName = "random", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(random_api);
+ ParseNumpyApi(random_api, "routines.random.html");
+ // ----------------------------------------------------
+ // Set routines
+ // ----------------------------------------------------
+ var set_api = new StaticApi() { PartialName = "set", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(set_api);
+ ParseNumpyApi(set_api, "routines.set.html");
+ // ----------------------------------------------------
+ // Sorting, searching, and counting
+ // ----------------------------------------------------
+ var sorting_api = new StaticApi() { PartialName = "sorting", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(sorting_api);
+ ParseNumpyApi(sorting_api, "routines.sort.html");
+ // ----------------------------------------------------
+ // Statistics
+ // ----------------------------------------------------
+ var staticstics_api = new StaticApi() { PartialName = "staticstics", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(staticstics_api);
+ ParseNumpyApi(staticstics_api, "routines.statistics.html");
+ // ----------------------------------------------------
+ // Window functions
+ // ----------------------------------------------------
+ var window_api = new StaticApi() { PartialName = "window", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(window_api);
+ ParseNumpyApi(window_api, "routines.window.html");
+ // ----------------------------------------------------
+ // Other functions
+ // ----------------------------------------------------
+ var other_api = new StaticApi() { PartialName = "other", StaticName = "np", ImplName = "NumPy", PythonModule = "numpy", };
+ _generator.StaticApis.Add(other_api);
+ var links = new[]{
+ "numpy.roots.html"
+ };
+ ParseSinglePages(other_api, links);
+
+ // ----------------------------------------------------
+ // generate Numpy
+ // it is based on Python.Included and packs the Numpy wheel
+ // ----------------------------------------------------
+ ndarray_api.OutputPath = Path.Combine(src_dir, "Numpy/Models");
+ _generator.ModelsPath = Path.Combine(src_dir, "Numpy/Models");
+ _generator.StaticApiFilesPath = Path.Combine(src_dir, "Numpy");
+ _generator.DynamicApiFilesPath = Path.Combine(src_dir, "Numpy");
+ _generator.Generate();
+ ApiStatistics();
+ Console.WriteLine($"Number of generated functions: {parsed_api_functions.Count} / {all_api_functions.Count}");
+
+ Thread.Sleep(2000);
+
+ return "DONE";
+ }
+
+ private void ParseNdarrayApi(DynamicApi api)
+ {
+ var docs = LoadDocs("arrays.ndarray.html");
+ foreach (var html_doc in docs)
+ {
+ var doc = html_doc.Doc;
+ // declaration
+ var h1 = doc.DocumentNode.Descendants("h1").FirstOrDefault();
+ if (h1 == null)
+ continue;
+ var dl = doc.DocumentNode.Descendants("dl").FirstOrDefault();
+ if (dl == null || dl.Attributes["class"]?.Value != "method") continue;
+ var class_name = doc.DocumentNode.Descendants("code")
+ .First(x => x.Attributes["class"]?.Value == "descclassname").InnerText;
+ var func_name = doc.DocumentNode.Descendants("code")
+ .First(x => x.Attributes["class"]?.Value == "descname").InnerText;
+ // do not generate the following:
+ switch (func_name)
+ {
+ case "sort":
+ case "partition":
+ case "transpose":
+ continue;
+ }
+ var decl = new Function() { Name = func_name, ClassName = class_name.TrimEnd('.') };
+ // function description
+ var dd = dl.Descendants("dd").FirstOrDefault();
+ decl.Description = ParseDescription(dd);
+ var table = doc.DocumentNode.Descendants("table")
+ .FirstOrDefault(x => x.Attributes["class"]?.Value == "docutils field-list");
+ if (table == null)
+ continue;
+ // arguments
+ ParseArguments(html_doc, table, decl);
+
+ // return type(s)
+ ParseReturnTypes(html_doc, table, decl);
+
+ PostProcess(decl);
+ // if necessary create overloads
+ foreach (var d in InferOverloads(decl))
+ {
+ PostProcessOverloads(d);
+ api.Declarations.Add(d);
+ }
+ }
+ }
+
+ private void PostProcessOverloads(Function function)
+ {
+ foreach (var arg in function.Arguments)
+ {
+ if (arg.Name == "axis")
+ {
+ if (arg.Type!="int[]")
+ continue;
+ if (arg.DefaultValue == null || arg.DefaultValue == "null")
+ arg.Type = "Axis";
+ }
+ }
+ }
+
+ private int _function_count = 0;
+
+ private void ParseDtypeApi(StaticApi api)
+ {
+ var doc = GetHtml("arrays.scalars.html");
+ foreach (var tr in doc.Doc.DocumentNode.Descendants("tr"))
+ {
+ if (tr.Descendants("td").Count() != 3)
+ continue;
+ var span = tr.Descendants("span").FirstOrDefault();
+ if (span == null)
+ continue;
+ var td = tr.Descendants("td").Skip(1).FirstOrDefault();
+ _function_count++;
+ api.Declarations.Add(new Property() { Name = span.InnerText, Description = td?.InnerText, Type = "Dtype", HasSetter = false });
+ }
+ }
+
+ private void ParseNumpyApi(StaticApi api, string link)
+ {
+ var docs = LoadDocs(link);
+ var testfile = new TestFile() { Name = $"{api.ImplName}_{api.PartialName}" };
+ _generator.TestFiles.Add(testfile);
+ foreach (var html_doc in docs)
+ {
+ ParseNumpyDocPage(api, link, html_doc, testfile);
+ }
+ }
+
+ private void ParseSinglePages(StaticApi api, params string[] links)
+ {
+ var docs = links.Select(x=>GetHtml("generated/"+x));
+ var testfile = new TestFile() { Name = $"{api.ImplName}_{api.PartialName}" };
+ _generator.TestFiles.Add(testfile);
+ foreach (var html_doc in docs)
+ {
+ ParseNumpyDocPage(api, "single pages", html_doc, testfile);
+ }
+ }
+
+ private void ParseNumpyDocPage(StaticApi api, string link, HtmlDoc html_doc, TestFile testfile)
+ {
+ var doc = html_doc.Doc;
+ // declaration
+ var h1 = doc.DocumentNode.Descendants("h1").FirstOrDefault();
+ if (h1 == null)
+ return;
+ var dl = doc.DocumentNode.Descendants("dl").FirstOrDefault();
+ //if (dl == null || dl.Attributes["class"]?.Value != "function") continue;
+ var class_name = doc.DocumentNode.Descendants("code")
+ .FirstOrDefault(x => x.Attributes["class"]?.Value == "descclassname")?.InnerText;
+ if (class_name == null)
+ return;
+ var func_name = doc.DocumentNode.Descendants("code")
+ .First(x => x.Attributes["class"]?.Value == "descname").InnerText;
+ if (parsed_api_functions.Contains(class_name + "." + func_name))
+ return;
+ parsed_api_functions.Add(class_name + "." + func_name);
+ var decl = new Function() { Tag = link, Name = func_name, ClassName = class_name.TrimEnd('.') };
+ // function description
+ var dd = dl.Descendants("dd").FirstOrDefault();
+ decl.Description = ParseDescription(dd);
+ var table = doc.DocumentNode.Descendants("table")
+ .FirstOrDefault(x => x.Attributes["class"]?.Value == "docutils field-list");
+ if (table == null)
+ return;
+ //if (decl.Name == "copyto")
+ // Debugger.Break();
+ // arguments
+ ParseArguments(html_doc, table, decl);
+
+ // return type(s)
+ ParseReturnTypes(html_doc, table, decl);
+
+ PostProcess(decl);
+ if (!decl.CommentOut)
+ _function_count++;
+
+ // if necessary create overloads
+ foreach (var d in InferOverloads(decl))
+ {
+ PostProcessOverloads(d);
+ api.Declarations.Add(d);
+ // if this is an ndarray member, add it to the dynamic api also
+ if (ndarray_api != null && d.Arguments.FirstOrDefault()?.Type == "NDarray" && class_name == "numpy.")
+ {
+ switch (decl.Name)
+ {
+ // do not add to NDArray instance methods
+ case "copyto":
+ //case "transpose":
+ //case "amax":
+ //case "amin":
+ //case "real":
+ //case "imag":
+ continue;
+ }
+ decl.IsExtensionFunction = true;
+ //var dc = d.Clone();
+ //dc.Arguments.RemoveAt(0);
+ //ndarray_api.Declarations.Add(dc);
+ }
+ }
+
+ // see if there are any examples which we can convert to test cases
+ var testcase = ParseTests(doc, decl);
+ if (testcase != null)
+ testfile.TestCases.Add(testcase);
+ }
+
+ private TestCase ParseTests(HtmlDocument doc, Function decl)
+ {
+ int i = 0;
+ var dd = doc.DocumentNode.Descendants("dd").FirstOrDefault();
+ if (dd == null)
+ return null;
+ var iter = dd.ChildNodes.SkipWhile(x =>
+ !(x.Name == "p" && x.Attributes["class"]?.Value == "rubric" && x.InnerText == "Examples"));
+ var nodes = iter.Skip(1).ToArray();
+ if (nodes.Length == 0)
+ return null;
+ var testcase = new TestCase() { Name = $"{decl.Name}Test" };
+ foreach (var element in nodes)
+ {
+ if (element.Name == "p")
+ {
+ var text = HtmlEntity.DeEntitize(element.InnerText ?? "").Trim();
+ if (!string.IsNullOrWhiteSpace(text))
+ testcase.TestParts.Add(new Comment() { Text = text });
+ continue;
+ }
+ var pre = element.Descendants("pre").FirstOrDefault();
+ if (pre == null)
+ {
+ //Debugger.Break();
+ continue;
+ }
+ var part = new ExampleCode() { Text = HtmlEntity.DeEntitize(pre.InnerText) };
+ //> > > np.eye(2, dtype = int)
+ //array([[1, 0],
+ // [0, 1]])
+ //>>> np.eye(3, k=1)
+ //array([[ 0., 1., 0.],
+ // [ 0., 0., 1.],
+ // [ 0., 0., 0.]])
+ var lines = new Queue(Regex.Split(part.Text.Trim(), @"\r?\n"));
+ foreach (var line in lines)
+ {
+ if (line.StartsWith(">>>"))
+ {
+ var cmd = line.Replace(">>>", "");
+ if (cmd.Contains("np."))
+ cmd = cmd.Replace('[', '{').Replace(']', '}');
+ part.Lines.Add(new CodeLine() { Text = { cmd }, Type = "cmd" });
+ continue;
+ }
+ if (line.StartsWith("#"))
+ {
+ part.Lines.Add(new CodeLine() { Text = { line.Replace("#", "//") }, Type = "comment" });
+ continue;
+ }
+ if (part.Lines.Count == 0 || part.Lines.Last().Type != "output")
+ part.Lines.Add(new CodeLine() { Text = { line }, Type = "output" });
+ else
+ part.Lines.Last().Text.Add(line);
+ }
+ testcase.TestParts.Add(part);
+ }
+ if (testcase.TestParts.Count == 0)
+ return null;
+ return testcase;
+ }
+
+ private string ParseDescription(HtmlNode dd)
+ {
+ if (dd == null)
+ return null;
+ var desc = string.Join("\r\n\r\n", dd.ChildNodes.Where(n => n.Name == "p").Select(p => p.InnerText).TakeWhile(s => !s.StartsWith("Examples")));
+ return desc;
+ }
+
+ private void ParseArguments(HtmlDoc html_doc, HtmlNode table, Function decl)
+ {
+ var tr = table.Descendants("tr").FirstOrDefault();
+ if (tr == null)
+ return;
+ foreach (var dt in tr.Descendants("dt"))
+ {
+ var arg = new Argument() { Tag = decl.Tag };
+ var strong = dt.Descendants("strong").FirstOrDefault();
+ if (strong == null)
+ continue;
+ arg.Name = strong.InnerText;
+ if (arg.Name.ToLower() == "none")
+ continue; // there are no arguments fro this method
+ string type_description = null;
+ if (arg.Name.Contains(":"))
+ {
+ var tuple = arg.Name.Split(":");
+ arg.Name = tuple[0].Trim();
+ type_description = tuple[1].Trim();
+ }
+ else
+ {
+ type_description = dt.Descendants("span")
+ .FirstOrDefault(span => span.Attributes["class"]?.Value == "classifier")?.InnerText;
+ }
+ if (type_description == null)
+ type_description = "_NoValue";
+ var type = type_description.Split(",").FirstOrDefault();
+ arg.Type = InferType(type, arg);
+ if (type_description.Contains("optional"))
+ {
+ arg.IsNamedArg = true;
+ arg.IsNullable = true;
+ }
+ if (type_description.Contains("default:"))
+ arg.DefaultValue = InferDefaultValue(type_description.Split(",")
+ .First(x => x.Contains("default: ")).Replace("default: ", ""));
+ var dd = dt.NextSibling?.NextSibling;
+ arg.Description = ParseDescription(dd);
+ arg.Position = decl.Arguments.Count;
+ decl.Arguments.Add(arg);
+ }
+ ParseDefaultValues(html_doc, decl);
+ foreach (var arg in decl.Arguments)
+ PostProcess(arg);
+ }
+
+ private void ParseDefaultValues(HtmlDoc htmlDoc, Function decl)
+ {
+ var dl = htmlDoc.Doc.DocumentNode.Descendants("dl").FirstOrDefault(x => x.Attributes["class"]?.Value == "function");
+ if (dl == null)
+ return;
+ foreach (var em in dl.Descendants("em"))
+ {
+ var tokens = em.InnerText.Split("=");
+ if (tokens.Length >= 2)
+ {
+ var (attr_name, default_value) = (tokens[0], tokens[1]);
+ var attr = decl.Arguments.FirstOrDefault(x => x.Name == attr_name);
+ if (attr == null)
+ {
+ Console.WriteLine("ParseDefaultValues: Attr '{attr_name}' not found");
+ continue;
+ }
+ attr.DefaultValue = InferDefaultValue(default_value);
+ }
+ }
+ }
+
+ private void PostProcess(Argument arg)
+ {
+ switch (arg.Name)
+ {
+ case "order":
+ arg.DefaultValue = null;
+ break;
+ case "axes":
+ {
+ arg.Type = "int[]";
+ arg.DefaultValue = "null";
+ return;
+ }
+ case "where":
+ case "out":
+ {
+ arg.IsNullable = true;
+ arg.IsNamedArg = true;
+ arg.DefaultValue = null;
+ break;
+ }
+ case "requirements":
+ case "comments":
+ arg.DefaultValue = "null";
+ break;
+ }
+ if (arg.Name.StartsWith("*"))
+ arg.Name = arg.Name.TrimStart('*');
+ switch (arg.Type)
+ {
+ //case "int[]":
+ //case "Hashtable":
+ // arg.IsValueType = false;
+ // break;
+ case "Dtype":
+ arg.IsValueType = false;
+ if (!string.IsNullOrWhiteSpace(arg.DefaultValue))
+ arg.DefaultValue = "null";
+ break;
+ }
+ }
+
+ private void PostProcess(Function decl)
+ {
+ if (decl.Arguments.Any(a => a.Type == "buffer_like"))
+ decl.CommentOut = true;
+ // iterable object
+ if (decl.Arguments.Any(a => a.Type.Contains("")))
+ {
+ decl.Generics = new string[] { "T" };
+ if (decl.Returns[0].Type == "NDarray") // TODO: this feels like a hack. make it more robust if necessary
+ decl.Returns[0].Type = "NDarray";
+ }
+ if (decl.Returns.Any(a => a.Type == "T" || a.Type.Contains("")))
+ {
+ decl.Generics = new string[] { "T" };
+ }
+ // split combined arguments: NDarray x, y => NDarray x, NDarray y
+ for (int i = decl.Arguments.Count - 1; i >= 0; i--)
+ {
+ var arg = decl.Arguments[i];
+ if (arg.Type == "_NoValue")
+ {
+ decl.Arguments.RemoveAt(i);
+ continue;
+ }
+ if (arg.Name.Contains(","))
+ {
+ var names = arg.Name.Split(',').Select(x => x.Trim()).ToArray();
+ arg.Name = names[0];
+ decl.Arguments.Insert(i + 1, decl.Arguments[i].Clone());
+ decl.Arguments[i].Name = names[1];
+ continue;
+ }
+ }
+ switch (decl.Name)
+ {
+ case "fft":
+ case "random":
+ decl.SharpOnlyPostfix = "_";
+ break;
+ case "array":
+ if (decl.ClassName == "numpy")
+ decl.ManualOverride = true; // do not generate an implementation
+ break;
+ case "itemset":
+ case "tostring":
+ case "tobytes":
+ case "view":
+ case "resize":
+ case "insert":
+ case "einsum":
+ decl.ManualOverride = true; // do not generate an implementation
+ break;
+ case "arange":
+ decl.Arguments[0].IsNullable = false;
+ decl.Arguments[0].DefaultValue = "0";
+ decl.Arguments[2].DefaultValue = "1";
+ decl.Arguments[2].IsNullable = false;
+ decl.Arguments[3].IsNullable = false;
+ decl.Arguments[3].IsNamedArg = true;
+ break;
+ case "logspace":
+ case "geomspace":
+ decl.Arguments.First(a => a.Type == "Dtype").IsNullable = false;
+ decl.Arguments.First(a => a.Type == "Dtype").DefaultValue = "null";
+ decl.Arguments.First(a => a.Type == "Dtype").IsNamedArg = true;
+ break;
+ case "copy":
+ if (decl.Returns.Count==0)
+ decl.Returns.Add(new Argument(){Type = "NDarray"});
+ break;
+ case "mat":
+ case "bmat":
+ case "block":
+ case "interp":
+ case "einsum_path":
+ case "cond":
+ case "get_state":
+ case "set_state":
+ case "genfromtxt":
+ case "array2string":
+ case "tolist":
+ case "format_float_positional":
+ case "format_float_scientific":
+ case "set_printoptions":
+ case "set_string_function":
+ case "ravel_multi_index":
+ case "nditer":
+ case "nested_iters":
+ case "result_type":
+ case "issubclass_":
+ case "find_common_type":
+ case "busdaycalendar":
+ case "is_busday":
+ case "busday_count":
+ case "busday_offset":
+ decl.CommentOut = true;
+ break;
+ case "require":
+ case "tensordot":
+ if (decl.Returns.Count == 0)
+ decl.Returns.Add(new Argument() { Type = "NDarray", Name = "array", IsReturnValue = true });
+ break;
+ case "isfortran":
+ if (decl.Returns.Count == 0)
+ decl.Returns.Add(new Argument() { Type = "bool", Name = "retval", IsReturnValue = true });
+ break;
+ case "matrix_rank":
+ if (decl.Returns.Count == 0)
+ decl.Returns.Add(new Argument() { Type = "int", Name = "retval", IsReturnValue = true });
+ break;
+ case "correlate":
+ decl.Arguments.Remove(decl.Arguments.FirstOrDefault(x => x.Name == "old_behavior"));
+ break;
+ case "rot90":
+ var axes = decl.Arguments.First(x => x.Name == "axes");
+ axes.DefaultValue = "null";
+ axes.DefaultIfNull = "new int[] {0, 1}";
+ break;
+ case "trapz":
+ var dx = decl.Arguments.First(x => x.Name == "dx");
+ dx.Type = "float";
+ break;
+ case "lstsq":
+ {
+ var rcond = decl.Arguments.First(x => x.Name == "rcond");
+ rcond.DefaultValue = "null";
+ break;
+ }
+ case "pinv":
+ {
+ var rcond = decl.Arguments.First(x => x.Name == "rcond");
+ rcond.Type = "float";
+ break;
+ }
+ case "histogram":
+ case "histogram2d":
+ case "histogramdd":
+ case "histogram_bin_edges":
+ {
+ var bins = decl.Arguments.First(x => x.Name == "bins");
+ bins.DefaultValue = "null";
+ break;
+ }
+ case "exponential":
+ decl.Arguments[0].DefaultValue = "null";
+ break;
+ case "gamma":
+ decl.Arguments.First(x => x.Name == "scale").DefaultValue = "null";
+ break;
+ case "gumbel":
+ case "laplace":
+ case "logistic":
+ case "lognormal":
+ case "normal":
+ case "poisson":
+ case "rayleigh":
+ case "uniform":
+ decl.Arguments.ForEach(x =>
+ {
+ x.DefaultValue = "null";
+ x.IsNamedArg = true;
+ });
+ break;
+ case "RandomState":
+ {
+ decl.Arguments[0].Type = "int";
+ decl.Arguments[0].DefaultValue = "null";
+ decl.Arguments[0].IsNullable = true;
+ decl.Arguments[0].IsNamedArg = true;
+ }
+ break;
+ case "fftfreq":
+ case "rfftfreq":
+ decl.Arguments[1].Type = "float";
+ break;
+ case "load":
+ decl.Arguments.First(x => x.Name == "mmap_mode").Type = "MemMapMode";
+ // allow_pickle was changed in Numpy version 1.16.3: Made default False in response to CVE-2019-6446.
+ decl.Arguments.First(x => x.Name == "allow_pickle").DefaultValue = "false";
+ break;
+ case "save":
+ case "savez":
+ case "savez_compressed":
+ // decl.Arguments.First(x => x.Name == "args").Type = "NDarray[]";
+ // decl.Arguments.First(x => x.Name == "kwds").Type = "Dictionary";
+ decl.ManualOverride = true; // do not generate an implementation
+ break;
+ case "savetxt":
+ decl.Arguments.First(x => x.Name == "fmt").DefaultValue = "null";
+ decl.Arguments.First(x => x.Name == "encoding").Type = "string";
+ break;
+ case "mask_indices":
+ decl.Arguments.First(x => x.Name == "k").Type = "int";
+ break;
+ case "select":
+ decl.Arguments.First(x => x.Name == "default").Type = "object";
+ decl.Arguments.First(x => x.Name == "default").DefaultValue = "null";
+ break;
+ case "pv":
+ case "pmt":
+ case "ppmt":
+ case "ipmt":
+ case "nper":
+ decl.Arguments.First(x => x.Name == "fv").DefaultValue = "null";
+ var when = decl.Arguments.FirstOrDefault(x => x.Name == "when");
+ if (when != null)
+ when.IsNamedArg = true;
+ break;
+ case "format_parser":
+ decl.Arguments.First(x => x.Name == "titles").Type = "string[]";
+ break;
+ case "mintypecode":
+ decl.Arguments.First(x => x.Name == "typeset").DefaultValue = "null";
+ break;
+ case "rand":
+ case "randn":
+ decl.Arguments.Clear();
+ decl.Arguments.Add(new Argument(){ Name = "shape", Type = "int[]"});
+ decl.ManualOverride = true;
+ break;
+ case "take_along_axis":
+ decl.Arguments[2].IsNullable = true;
+ decl.Returns.Clear();
+ decl.Returns.Add(new Argument() { Type = "NDarray", Name = "array", IsReturnValue = true });
+ break;
+ case "column_stack":
+ decl.ManualOverride = true;
+ break;
+ case "meshgrid":
+ decl.ReturnType = "NDarray[]";
+ decl.Arguments[0].Type = "NDarray[]";
+ decl.Arguments[0].Name = "xi";
+ decl.Arguments.RemoveAt(1);
+ decl.Arguments[1].DefaultValue = "\"xy\"";
+ break;
+ case "mgrid":
+ decl.ReturnType = "NDarray[]";
+ break;
+ case "ogrid":
+ decl.ReturnType = "NDarray[]";
+ decl.Arguments.Clear();
+ break;
+ case "fromfile":
+ decl.ReturnType = "NDarray";
+ break;
+ }
+ }
+
+ private void ParseReturnTypes(HtmlDoc html_doc, HtmlNode table, Declaration decl)
+ {
+ var tr = table.Descendants("tr").FirstOrDefault(x => x.InnerText.StartsWith("Returns:"));
+ if (tr == null)
+ return;
+ foreach (var dt in tr.Descendants("dt"))
+ {
+ var arg = new Argument() { IsReturnValue = true };
+ var strong = dt.Descendants("strong").FirstOrDefault();
+ if (strong != null)
+ arg.Name = strong.InnerText;
+ if (arg.Name == null || arg.Name.ToLower() == "none")
+ continue;
+ var type_description = dt.Descendants("span")
+ .FirstOrDefault(span => span.Attributes["class"]?.Value == "classifier")?.InnerText;
+ if (type_description == null)
+ continue;
+ var type = type_description.Split(",").FirstOrDefault();
+ arg.Type = InferType(type, arg);
+ var dd = dt.NextSibling?.NextSibling;
+ arg.Description = ParseDescription(dd);
+ decl.Returns.Add(arg);
+ }
+ }
+
+ private IEnumerable InferOverloads(Function decl)
+ {
+ switch (decl.Name)
+ {
+ case "qr":
+ case "norm":
+ case "asscalar":
+ case "normal":
+ case "meshgrid":
+ // don't generate at all
+ yield break;
+ case "all":
+ case "any":
+ {
+ decl.Arguments[0].Type = "NDarray";
+ decl.Returns[0].Type = "NDarray";
+ decl.Arguments.FirstOrDefault(x => x.Name == "axis").IsNullable = false; // make axis mandatory
+ yield return decl;
+ var clone = decl.Clone();
+ clone.Arguments.Remove(clone.Arguments.FirstOrDefault(x => x.Name == "axis"));
+ clone.Arguments.Remove(clone.Arguments.FirstOrDefault(x => x.Name == "out"));
+ clone.Arguments.Remove(clone.Arguments.FirstOrDefault(x => x.Name == "keepdims"));
+ clone.Returns[0].Type = "bool";
+ yield return clone;
+ yield break;
+ }
+ case "count_nonzero":
+ {
+ decl.Arguments[0].Type = "NDarray";
+ decl.Returns[0].Type = "NDarray";
+ decl.Arguments.FirstOrDefault(x => x.Name == "axis").IsNullable = false; // make axis mandatory
+ yield return decl;
+ var clone = decl.Clone();
+ clone.Arguments.Remove(clone.Arguments.FirstOrDefault(x => x.Name == "axis"));
+ clone.Returns[0].Type = "int";
+ yield return clone;
+ yield break;
+ }
+ case "sort":
+ decl.Arguments.FirstOrDefault(x => x.Name == "axis").DefaultValue = "-1";
+ break;
+ case "percentile":
+ case "nanpercentile":
+ case "quantile":
+ case "nanquantile":
+ case "median":
+ case "average":
+ case "mean":
+ case "std":
+ case "var":
+ case "nanmedian":
+ case "nanmean":
+ case "nanstd":
+ case "nanvar":
+ {
+ decl.Arguments[0].Type = "NDarray";
+ decl.Returns[0].Type = "NDarray";
+ var interpol = decl.Arguments.FirstOrDefault(x => x.Name == "interpolation");
+ if (interpol != null)
+ {
+ interpol.DefaultValue = "\"linear\"";
+ interpol.IsNamedArg = true;
+ }
+ var weights = decl.Arguments.FirstOrDefault(x => x.Name == "weights");
+ if (weights != null)
+ {
+ weights.Type = "NDarray";
+ weights.IsNamedArg = true;
+ weights.IsNullable = true;
+ }
+ //decl.Generics=new string[]{"T"};
+ decl.Arguments.FirstOrDefault(x => x.Name == "axis").IsNullable = false; // make axis mandatory
+ yield return decl;
+ var clone = decl.Clone();
+ clone.Arguments.Remove(clone.Arguments.FirstOrDefault(x => x.Name == "axis"));
+ //clone.Arguments.Remove(clone.Arguments.FirstOrDefault(x => x.Name == "out"));
+ clone.Arguments.Remove(clone.Arguments.FirstOrDefault(x => x.Name == "keepdims"));
+ clone.Returns[0].Type = "double";
+ yield return clone;
+ yield break;
+ }
+ break;
+ case "histogram":
+ case "histogram2d":
+ case "histogramdd":
+ case "histogram_bin_edges":
+ {
+ decl.Arguments[0].Type = "NDarray";
+ if (decl.Returns.Count > 1)
+ {
+ decl.Returns[1].Type = "NDarray";
+ decl.Generics = null;
+ }
+ var bins = decl.Arguments.FirstOrDefault(x => x.Name == "bins");
+ if (bins != null)
+ {
+ bins.Type = "int";
+ bins.IsNamedArg = true;
+ }
+ var range = decl.Arguments.FirstOrDefault(x => x.Name == "range");
+ if (range != null)
+ {
+ range.Type = "(float, float)";
+ range.IsNamedArg = true;
+ range.IsValueType = true;
+ range.IsNullable = true;
+ }
+ var weights = decl.Arguments.FirstOrDefault(x => x.Name == "weights");
+ if (weights != null)
+ {
+ weights.Type = "NDarray";
+ weights.IsNamedArg = true;
+ weights.IsNullable = true;
+ }
+ var y = decl.Arguments.FirstOrDefault(x => x.Name == "y");
+ if (y != null)
+ y.Type = "NDarray";
+ yield return decl;
+ var clone1 = decl.Clone();
+ clone1.Arguments.First(x => x.Name == "bins").Type = "NDarray";
+ yield return clone1;
+ var clone2 = decl.Clone();
+ clone2.Arguments.First(x => x.Name == "bins").Type = "List";
+ yield return clone2;
+ yield break;
+ }
+ break;
+ case "choice":
+ case "permutation":
+ case "binomial":
+ {
+ if (!decl.Arguments[0].Type.StartsWith("NDarray"))
+ decl.Arguments[0].Type = "NDarray";
+ yield return decl;
+ var clone = decl.Clone();
+ clone.Arguments[0].Type = "int";
+ yield return clone;
+ yield break;
+ }
+ break;
+ case "seed":
+ case "RandomState":
+ {
+ decl.Arguments[0].Type = "int";
+ decl.Arguments[0].DefaultValue = "null";
+ decl.Arguments[0].IsNullable = true;
+ yield return decl;
+ var clone = decl.Clone();
+ clone.Arguments[0].Type = "NDarray";
+ yield return clone;
+ yield break;
+ }
+ break;
+ case "unique":
+ {
+ decl["ar"].Type = "NDarray";
+ decl.Arguments.ForEach(a =>
+ {
+ if (a.Name != "axis")
+ {
+ a.IsNullable = false;
+ a.DefaultValue = null;
+ }
+ });
+ decl.Returns.RemoveAt(3);
+ decl.Returns.RemoveAt(2);
+ decl.Returns.RemoveAt(1);
+ // without return_index, return_inverse and return_counts we return just an NDarray
+ yield return decl.Clone(f =>
+ {
+ f.Arguments.RemoveAt(3);
+ f.Arguments.RemoveAt(2);
+ f.Arguments.RemoveAt(1);
+ });
+ // if all parameters are specified we return NDarray[]
+ decl.Returns[0].Type = "NDarray[]";
+ yield return decl;
+ }
+ yield break;
+ case "linspace":
+ {
+ decl["retstep"].Ignore = true;
+ decl["start"].Type = "NDarray";
+ decl["stop"].Type = "NDarray";
+ decl["num"].DefaultValue="50";
+ decl["endpoint"].DefaultValue="true";
+ //decl["retstep"].MakeMandatory();
+ yield return decl;
+ yield return decl.Clone(f =>
+ {
+ f.Returns.RemoveAt(1);
+ f["start"].Type = "double";
+ f["stop"].Type = "double";
+ });
+ }
+ yield break;
+ case "rand":
+ case "randn":
+ yield return decl;
+ yield return decl.Clone(f =>
+ {
+ f.Arguments.Clear();
+ f.ManualOverride = false;
+ f.Returns[0].Type = "float";
+ });
+ yield break;
+ case "where":
+ {
+ decl["condition"].Type = "NDarray";
+ decl["x"].Type = "NDarray";
+ decl["y"].Type = "NDarray";
+ yield return decl;
+ yield return decl.Clone(f =>
+ {
+ f.Arguments.RemoveAt(2);
+ f.Arguments.RemoveAt(1);
+ f.ReturnType = "NDarray[]";
+ });
+ }
+ yield break;
+ case "transpose":
+ if (decl.Arguments[0].Type == "array_like")
+ {
+ decl.Arguments[0].Type = "NDarray";
+ yield return decl;
+ yield return decl.Clone(f => { f.Arguments[0].Type = "NDarray[]"; });
+ }
+ else
+ yield return decl;
+ yield break;
+ case "gradient": // don't generate.
+ yield break;
+ case "split":
+ yield return decl;
+ yield return decl.Clone(f => { f.Arguments[1].Type = "int"; });
+ yield break;
+ }
+
+ // without args we don't need to consider possible overloads
+ if (decl.Arguments.Count == 0)
+ {
+ yield return decl;
+ yield break;
+ }
+ if (decl.Name == "arange")
+ {
+ foreach (var d in ExpandArange(decl))
+ yield return d;
+ yield break;
+ }
+ if (decl.Name == "bmat")
+ {
+ decl.Arguments[0].Type = "string";
+ yield return decl;
+ var clone_decl = decl.Clone();
+ clone_decl.Arguments[0].Type = "T[]";
+ clone_decl.Arguments[0].ConvertToSharpType = "NDarray";
+ clone_decl.Generics = new[] { "T" };
+ clone_decl.Returns[0].Type = "Matrix";
+ yield return clone_decl;
+ yield break;
+ }
+ HashSet overloads = new HashSet() { decl };
+ int i = -1;
+ foreach (var arg in decl.Arguments)
+ {
+ i++;
+ // array_like
+ if (arg.Type == "array_like")
+ {
+ arg.Type = "NDarray";
+ if (arg.Tag != "routines.array-creation.html")
+ continue;
+ switch (decl.Name)
+ {
+ case "insert":
+ case "append":
+ case "resize":
+ case "flip":
+ case "flipud":
+ case "fliplr":
+ case "squeeze":
+ case "expand_dims":
+ case "broadcast_to":
+ case "transpose":
+ case "swapaxes":
+ case "ravel":
+ case "reshape":
+ case "copyto":
+ if (i == 0)
+ continue;
+ break;
+ case "logspace":
+ case "linspace":
+ case "geomspace":
+ case "tile":
+ case "delete":
+ case "repeat":
+ case "roll":
+ case "rot90":
+ continue;
+ }
+ foreach (var overload in overloads.ToArray())
+ {
+ foreach (var type in "T[] T[,]".Split())
+ {
+ var clone = overload.Clone();
+ clone.Arguments[i].Type = type;
+ clone.Generics = new string[] { "T" };
+ clone.Arguments[i].ConvertToSharpType = "NDarray";
+ if (clone.Returns.FirstOrDefault()?.Type == "NDarray"
+ ) // TODO: this feels like a hack. make it more robust if necessary
+ clone.Returns[0].Type = "NDarray";
+ overloads.Add(clone);
+ }
+ }
+ }
+ // array_like of bool
+ else if (arg.Type == "array_like of bool")
+ {
+ foreach (var overload in overloads.ToArray())
+ {
+ overload.Arguments[i].Type = "NDarray";
+ var clone = overload.Clone();
+ clone.Arguments[i].Type = "bool[]";
+ clone.Arguments[i].ConvertToSharpType = "NDarray";
+ overloads.Add(clone);
+ }
+ }
+ // number
+ else if (arg.Type == "number")
+ {
+ foreach (var overload in overloads.ToArray())
+ {
+ overload.Arguments[i].Type = "float";
+ foreach (var type in "byte short int long double".Split())
+ {
+ var clone = overload.Clone();
+ clone.Arguments[i].Type = type;
+ overloads.Add(clone);
+ }
+ }
+ }
+ }
+ foreach (var overload in overloads)
+ yield return overload;
+ }
+
+ // special treatment for np.arange which is a "monster"
+ private IEnumerable ExpandArange(Function decl)
+ {
+ // numpy.arange([start, ]stop, [step, ]dtype=None)
+ var dtype = decl.Arguments.Last();
+ dtype.IsNullable = true;
+ dtype.IsNamedArg = true;
+ if (decl.Arguments.Any(a => a.Type == "number"))
+ {
+ foreach (var type in "byte short int long float double".Split())
+ {
+ // start, stop
+ var clone_decl = decl.Clone();
+ clone_decl.Arguments.ForEach(a =>
+ {
+ if (a.Type == "number")
+ a.Type = type;
+ });
+ clone_decl.Arguments[0].IsNamedArg = false;
+ clone_decl.Arguments[0].IsNullable = false;
+ clone_decl.Arguments[0].DefaultValue = null;
+ yield return clone_decl;
+ // [start=0] <-- remove start from arg list
+ clone_decl = clone_decl.Clone(); // <---- clone from the clone, as it has the correct type
+ clone_decl.Arguments.RemoveAt(0);
+ yield return clone_decl;
+ }
+ yield break;
+ }
+ }
+
+ private string InferDefaultValue(string default_value)
+ {
+ switch (default_value)
+ {
+ case "None":
+ case "<class 'float'>":
+ case "<class 'numpy.float64'>":
+ case "<no value>":
+ return null;
+ case "True": return "true";
+ case "False": return "false";
+ case "'C'": return "\"C\"";
+ }
+ if (default_value.StartsWith("'"))
+ return $"\"{default_value.Trim('\'')}\"";
+ if (Regex.IsMatch(default_value, @"[+-]?(\d+\.\d+)|(\d+(\.\d+)?e[+-]\d+)"))
+ return default_value + "f";
+ return default_value;
+ }
+
+ private string InferType(string type, Argument arg)
+ {
+ switch (arg.Name)
+ {
+ case "shape": return "Shape";
+ case "newshape": return "Shape";
+ case "new_shape": return "Shape";
+ case "dtype": return "Dtype";
+ case "order": return "string";
+ case "slice": return "Slice";
+ case "strides": return "int[]";
+ case "arys1, arys2, …":
+ arg.Name = "arys";
+ return "params NDarray[]";
+ case "`*args`":
+ arg.Name = "args";
+ break;
+ case "a1, a2, …":
+ arg.Name = "arys";
+ break;
+ case "norm":
+ if (type == "{None")
+ return "string";
+ break;
+ case "axis":
+ if (type == "{int")
+ return "int[]";
+ break;
+ case "edge_order": return "int";
+ }
+ switch (type)
+ {
+ // Dtype
+ case "dtype":
+ case "data-type":
+ case "dtype or dtype specifier":
+ case "data type code":
+ case "integer type":
+ case "dtype_like":
+ return "Dtype";
+ case "matrix": return "Matrix";
+ // NDarray
+ case "array":
+ case "ndarray":
+ case "np.ndarray":
+ case "2-D array":
+ case "1-D array or sequence":
+ case "(…":
+ case "(…) array_like":
+ case "{(…":
+ case "{ (…":
+ case "(M":
+ case "(N":
+ case "(k":
+ case "{(M":
+ case "{(N":
+ case "{(1":
+ case "(min(M":
+ case "list of scalar or array":
+ case "scalar or array_like or None":
+ case "scalar or array_like":
+ case "float or ndarray":
+ case "(…) array_like of float":
+ case "complex ndarray":
+ case "1-D array_like":
+ case "scalar or ndarray":
+ case "broadcast object":
+ case "array_like or scalar":
+ case "single item or ndarray":
+ case "1-D array-like":
+ case "2-D array_like":
+ case "array_like of rank N":
+ case "{sequence":
+ case "1D or 2D array_like":
+ case "1-D sequence":
+ case "scalar or array_like of shape(M":
+ case "array_like of values":
+ case "array-like":
+ return "NDarray";
+ // NDarray
+ case "array of ints searchsorted(1-D array_like":
+ case "array of ints":
+ case "array of integer type":
+ case "array_like of integer type":
+ case "int or ndarray of ints":
+ case "int or array_like of ints":
+ case "int array":
+ return "NDarray";
+ // NDarray
+ case "array_like of float":
+ case "array of dtype float":
+ case "float or ndarray of floats":
+ case "float or array_like of floats":
+ case "float or array_like of float":
+ case "sequence of floats":
+ return "NDarray";
+ // NDarray
+ case "bool (scalar) or boolean ndarray":
+ case "bool or ndarray of bool":
+ case "1-D array of bools":
+ case "array of bool":
+ return "NDarray";
+ // NDarray[]
+ case "list of bool ndarrays":
+ return "NDarray[]";
+ case "scalar":
+ if (!arg.IsReturnValue)
+ return "ValueType";
+ else
+ return "T";
+ break;
+ // string
+ case "{ ‘warn’":
+ case "file":
+ case "str":
+ case "string or list":
+ case "file or str":
+ case "str or function":
+ case "file-like object":
+ case "str or file":
+ case "filename or file handle":
+ case "str or regexp":
+ case "str or None":
+ case "file-like":
+ case "{{‘begin’":
+ case "str or array_like of bool":
+ case "str or unicode":
+ case "{str":
+ case "str of length 256":
+ return "string";
+ // string[]
+ case "str or sequence of str":
+ case "str or list of str":
+ case "array of str or unicode-like":
+ case "str or sequence of strs":
+ case "sequence of str":
+ case "str or list":
+ case "str or list/tuple of str":
+ case "list of str or array_like":
+ case "array_like of datetime64":
+ case "array_like of datetime64[D]":
+ case "array_like of str or unicode":
+ case "array-like of str or unicode":
+ return "string[]";
+ // Delegate
+ case "callable":
+ case "function":
+ return "Delegate";
+ case "any": return "object";
+ case "iterable object": return "IEnumerable";
+ case "dict": return "Hashtable";
+ // int[]
+ case "int or tuple":
+ case "int or sequence":
+ case "int or sequence of int":
+ case "int or sequence of ints":
+ case "sequence of ints":
+ case "int or array of ints":
+ case "int or tuple of ints":
+ case "None or int or tuple of ints":
+ case "int or 1-D array":
+ case "sequence or int":
+ case "array_like of ints":
+ case "ints":
+ return "int[]";
+ case "boolean": return "bool";
+ case "integer":
+ return "int";
+ case "int or None":
+ arg.IsNullable = true;
+ return "int";
+ case "Standard Python scalar object": return "T";
+ case "Arguments (variable number and type)": return "params int[]";
+ case "list": return "List";
+ // NDarray[]
+ case "list of arrays":
+ case "array_likes":
+ case "sequence of arrays":
+ case "sequence of ndarrays":
+ case "sequence of array_like":
+ case "sequence of 1-D or 2-D arrays.":
+ case "list of ndarrays":
+ case "tuple":
+ case "list of array_like":
+ case "tuple of ndarrays":
+ case "tuple of ndarray":
+ case "1-D sequences":
+ case "tuple of arrays.":
+ case "tuple of arrays":
+ case "array_like (Ni…":
+ case "array_like (Nj…)":
+ return "NDarray[]";
+ case "slice": return "Slice";
+ // double
+ case "Number":
+ return "double";
+ // object
+ case "scalar dtype or object":
+ return "object";
+ }
+ if (arg.IsReturnValue)
+ {
+ switch (type)
+ {
+ case "array": return "NDarray";
+ case "array_like": return "NDarray";
+ }
+ }
+ if (type.StartsWith("ndarray"))
+ return "NDarray";
+ if (type.StartsWith("{‘"))
+ return "string";
+ return type;
+ }
+
+ string BaseUrl = "https://docs.scipy.org/doc/numpy-1.16.1/reference/";
+
+ public List LoadDocs(string overview_url)
+ {
+ var docs = new List();
+ var doc = GetHtml(overview_url);
+ LoadDocsFromOverviewPage(doc.Doc, docs);
+ return docs;
+ }
+
+ private void LoadDocsFromOverviewPage(HtmlDocument doc, List docs)
+ {
+ var nodes = doc.DocumentNode.Descendants("a")
+ .Where(x => x.Attributes["class"]?.Value == "reference internal")
+ .ToList();
+ foreach (var node in nodes)
+ {
+ var relative_link = node.Attributes["href"].Value;
+ if (!relative_link.StartsWith("generated"))
+ continue;
+ var uri = relative_link.Split("#").First();
+ docs.Add(GetHtml(uri));
+ }
+ }
+
+ HtmlDoc GetHtml(string relative_url)
+ {
+ Console.WriteLine("Loading: " + relative_url);
+ var doc = new HtmlDoc();
+ doc.Filename = relative_url.Replace("/", "_");
+ if (File.Exists(doc.Filename))
+ {
+ doc.Doc = new HtmlDocument();
+ doc.Doc.Load(doc.Filename);
+ doc.Text = doc.Doc.Text;
+ if (!doc.Text.Contains("404 Not Found"))
+ return doc;
+ }
+ var web = new HtmlWeb();
+ doc.Doc = web.Load(BaseUrl + relative_url);
+ doc.Text = doc.Doc.Text;
+ File.WriteAllText(doc.Filename, doc.Text);
+ return doc;
+ }
+
+ public void ApiStatistics()
+ {
+ var doc = GetNumpyReference();
+ var li = doc.Doc.DocumentNode.DescendantsOfClass("li", "toctree-l1").FirstOrDefault(x => x.InnerText.StartsWith("NumPy Reference"));
+ var stack = new Stack();
+ CollectApiFunctions(li, stack);
+ }
+
+ HashSet all_api_functions = new HashSet();
+
+ private void CollectApiFunctions(HtmlNode li, Stack stack)
+ {
+ var a = li.ChildNodes.FirstOrDefault(x => x.Name == "a");
+ var ul = li.ChildNodes.FirstOrDefault(x => x.Name == "ul");
+ stack.Push(a.InnerText);
+ if (a.InnerText.StartsWith("numpy"))
+ all_api_functions.Add(a.InnerText);
+ if (ul != null)
+ foreach (var sub_li in ul.ChildNodes.Where(x => x.Name == "li"))
+ CollectApiFunctions(sub_li, stack);
+ stack.Pop();
+ }
+
+ public HtmlDoc GetNumpyReference()
+ {
+ var url = "https://docs.scipy.org/doc/numpy/contents.html";
+ Console.WriteLine("Loading: " + url);
+ var doc = new HtmlDoc();
+ doc.Filename = "contents.html";
+ if (File.Exists(doc.Filename))
+ {
+ doc.Doc = new HtmlDocument();
+ doc.Doc.Load(doc.Filename);
+ doc.Text = doc.Doc.Text;
+ return doc;
+ }
+ var web = new HtmlWeb();
+ doc.Doc = web.Load(url);
+ doc.Text = doc.Doc.Text;
+ File.WriteAllText(doc.Filename, doc.Text);
+ return doc;
+ }
+ }
+}
+
diff --git a/src/CodeMinion.ApiGenerator/NumPy/README.md b/src/CodeMinion.ApiGenerator/NumPy/README.md
new file mode 100644
index 0000000..39a1415
--- /dev/null
+++ b/src/CodeMinion.ApiGenerator/NumPy/README.md
@@ -0,0 +1,4 @@
+# NumPy
+### NumPy is the fundamental package for scientific computing with Python.
+
+https://www.numpy.org
\ No newline at end of file
diff --git a/src/CodeMinion.ApiGenerator/NumPy/SpecialGenerators.cs b/src/CodeMinion.ApiGenerator/NumPy/SpecialGenerators.cs
new file mode 100644
index 0000000..c020112
--- /dev/null
+++ b/src/CodeMinion.ApiGenerator/NumPy/SpecialGenerators.cs
@@ -0,0 +1,52 @@
+using CodeMinion.Core.Helpers;
+
+namespace CodeMinion.ApiGenerator.NumPy
+{
+ public static class SpecialGenerators
+ {
+
+ public static void InitNumpyGenerator(CodeWriter s)
+ {
+ s.Out("#if PYTHON_INCLUDED");
+ s.Out("Installer.InstallWheel(typeof(np).Assembly, \"numpy-1.23.5-cp311-cp311-win_amd64.whl\", force).Wait();");
+ s.Out("#endif");
+ }
+
+ public static void ArrayToNDarrayConversion(CodeWriter s)
+ {
+ s.Out("case Array a:");
+ s.Out("if (typeof(T)==typeof(NDarray)) return (T)(object)ConvertArrayToNDarray(a);");
+ s.Out("break;");
+ }
+
+ public static void ConvertArrayToNDarray(CodeWriter s)
+ {
+ s.Out("private static NDarray ConvertArrayToNDarray(Array a)", () =>
+ {
+ s.Out("switch(a)", () =>
+ {
+ s.Out("case bool[] arr: return np.array(arr);");
+ s.Out("case int[] arr: return np.array(arr);");
+ s.Out("case float[] arr: return np.array(arr);");
+ s.Out("case double[] arr: return np.array(arr);");
+ s.Out("case int[,] arr: return np.array(arr.Cast().ToArray()).reshape(arr.GetLength(0), arr.GetLength(1));");
+ s.Out("case float[,] arr: return np.array(arr.Cast().ToArray()).reshape(arr.GetLength(0), arr.GetLength(1));");
+ s.Out("case double[,] arr: return np.array(arr.Cast().ToArray()).reshape(arr.GetLength(0), arr.GetLength(1));");
+ s.Out("case bool[,] arr: return np.array(arr.Cast().ToArray()).reshape(arr.GetLength(0), arr.GetLength(1));");
+ s.Out("default: throw new NotImplementedException($\"Type {a.GetType()} not supported yet in ConvertArrayToNDarray.\");");
+ });
+ });
+ }
+
+ public static void ConvertDict(CodeWriter s)
+ {
+ s.Out("private static PyDict ToDict(Dictionary d)", () =>
+ {
+ s.Out("var dict = new PyDict();");
+ s.Out("foreach (var pair in d)");
+ s.Out(" dict[new PyString(pair.Key)] = pair.Value.self;");
+ s.Out("return dict;");
+ });
+ }
+ }
+}
diff --git a/src/CodeMinion.ApiGenerator/Program.cs b/src/CodeMinion.ApiGenerator/Program.cs
new file mode 100644
index 0000000..054396b
--- /dev/null
+++ b/src/CodeMinion.ApiGenerator/Program.cs
@@ -0,0 +1,17 @@
+using System;
+using Torch.ApiGenerator;
+
+namespace CodeMinion.ApiGenerator
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ ICodeGenerator generator = new NumPy.ApiGenerator();
+ var result = generator.Generate();
+
+ Console.WriteLine(result);
+ //Console.ReadKey();
+ }
+ }
+}
diff --git a/src/CodeMinion.Core/Attributes/PartialClassTemplateAttribute.cs b/src/CodeMinion.Core/Attributes/PartialClassTemplateAttribute.cs
new file mode 100644
index 0000000..a31876f
--- /dev/null
+++ b/src/CodeMinion.Core/Attributes/PartialClassTemplateAttribute.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace CodeMinion.Core.Attributes
+{
+ public class PartialClassTemplateAttribute : Attribute
+ {
+ public string ClassName { get; set; }
+ public string MemberName { get; set; }
+
+ public PartialClassTemplateAttribute(string class_name, string member_name)
+ {
+ ClassName = class_name;
+ MemberName = member_name;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CodeMinion.Core/Attributes/TemplateAttribute.cs b/src/CodeMinion.Core/Attributes/TemplateAttribute.cs
new file mode 100644
index 0000000..79635d4
--- /dev/null
+++ b/src/CodeMinion.Core/Attributes/TemplateAttribute.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace CodeMinion.Core.Attributes
+{
+
+ public class TemplateAttribute : Attribute
+ {
+ public string ApiFunction { get; set; }
+
+ public TemplateAttribute(string api_function)
+ {
+ ApiFunction = api_function;
+ }
+ }
+}
diff --git a/src/CodeMinion.Core/CodeGenerator.cs b/src/CodeMinion.Core/CodeGenerator.cs
new file mode 100644
index 0000000..ab2017a
--- /dev/null
+++ b/src/CodeMinion.Core/CodeGenerator.cs
@@ -0,0 +1,1107 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Text.RegularExpressions;
+using CodeMinion.Core.Attributes;
+using CodeMinion.Core.Helpers;
+using CodeMinion.Core.Models;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using SliceAndDice;
+
+namespace CodeMinion.Core
+{
+ public class CodeGenerator
+ {
+ public CodeGenerator()
+ {
+ LoadTemplates();
+ }
+
+ public string CopyrightNotice { get; set; }
+ public List StaticApis { get; set; } = new List();
+ public List DynamicApis { get; set; } = new List();
+ public List ApiClasses { get; set; } = new List();
+ public bool PrintModelJson { get; set; } = false;
+ public string NameSpace { get; set; } = "Numpy";
+ public string StaticModuleName { get; set; } = "np";
+ public string PythonModuleName { get; set; } = "numpy";
+ public List> InitializationGenerators { get; set; } = new List>();
+
+ //public bool UsePythonIncluded { get; set; } = true;
+ public HashSet Usings { get; set; } = new HashSet()
+ {
+ @"using System;",
+ @"using System.Collections;",
+ @"using System.Collections.Generic;",
+ @"using System.IO;",
+ @"using System.Linq;",
+ @"using System.Runtime.InteropServices;",
+ @"using System.Text;",
+ @"using Python.Runtime;",
+ };
+ public string StaticApiFilesPath { get; set; }
+ public string DynamicApiFilesPath { get; set; }
+ public string ModelsPath { get; set; }
+ public string TestFilesPath { get; set; }
+ public List TestFiles { get; set; } = new List();
+ protected Dictionary _templates;
+ protected virtual void LoadTemplates()
+ {
+ _templates = Assembly.GetEntryAssembly().GetTypes()
+ .Where(x => x.GetCustomAttribute() != null)
+ .Select(x => (FunctionBodyTemplate)Activator.CreateInstance(x)).ToDictionary(x =>
+ x.GetType().GetCustomAttribute().ApiFunction);
+ }
+
+ // generate an entire API function declaration
+ protected virtual void GenerateApiFunction(Declaration decl, CodeWriter s, bool prefix = false, bool @static=false)
+ {
+ if (decl.ManualOverride)
+ return;
+ //if (decl.Name=="cholesky")
+ // Debugger.Break();
+ decl.Sanitize();
+ if (decl.CommentOut)
+ s.Out("/*");
+ var class_names = (decl.GeneratedClassName ?? decl.ClassName ?? "no_name").Split('.');
+ int levels = class_names.Length - 1;
+ if (levels > 0)
+ {
+ foreach (var name in class_names.Skip(1))
+ {
+ s.Out($"public static partial class {EscapeName(name)} {{");
+ s.Indent();
+ }
+ }
+ GenerateDocString(decl, s);
+ var retval = GenerateReturnType(decl);
+ switch (decl)
+ {
+ case Function func:
+ var arguments = GenerateArguments(func);
+ //var passed_args = GeneratePassedArgs(func);
+ var generics = func.Generics == null ? "" : $"<{string.Join(",", func.Generics)}>";
+ var prefix_str = "";
+ if (prefix && levels > 0)
+ prefix_str = string.Join("_", class_names.Skip(1)) + "_";
+ s.Out($"public {(@static ? "static ":"")}{retval} {EscapeName(prefix_str + decl.Name)}{func.SharpOnlyPostfix}{generics}({(@static && func.IsExtensionFunction ? "this " : "")}{arguments})");
+ s.Block(() =>
+ {
+ GenerateFunctionBody(func, s, prefix_str);
+ });
+ break;
+ case Property prop:
+ s.Out($"public {(@static ? "static " : "")}{prop.Type} {EscapeName(prop.Name)}");
+ s.Block(() =>
+ {
+ s.Out("get", () =>
+ {
+ GeneratePropertyGetter(prop, s);
+ });
+ s.Out("set", () =>
+ {
+ GeneratePropertySetter(prop, s);
+ });
+ });
+ break;
+ }
+ if (levels > 0)
+ {
+ foreach (var name in class_names.Skip(1))
+ {
+ s.Outdent();
+ s.Out("}");
+ }
+ }
+ if (decl.CommentOut)
+ s.Out("*/");
+ if (PrintModelJson)
+ {
+ s.Out("// the declaration model:");
+ s.Out("/*");
+ s.Out(JObject.FromObject(decl).ToString(Formatting.Indented));
+ s.Out("*/");
+ }
+ s.Break();
+ }
+
+ //protected virtual void GenerateStaticApiRedirection(StaticApi api, Declaration decl, CodeWriter s)
+ //{
+ // if (decl.DebuggerBreak)
+ // Debugger.Break();
+ // decl.Sanitize();
+ // if (decl.CommentOut)
+ // s.Out("/*");
+ // var class_names = (decl.GeneratedClassName ?? decl.ClassName ?? "no_name").Split('.');
+ // int levels = class_names.Length - 1;
+ // if (levels > 0)
+ // {
+ // foreach (var name in class_names.Skip(1))
+ // {
+ // s.Out($"public static partial class {EscapeName(name)} {{");
+ // s.Indent();
+ // }
+ // }
+ // GenerateDocString(decl, s);
+ // var retval = GenerateReturnType(decl);
+ // switch (decl)
+ // {
+ // case Function func:
+ // var arguments = GenerateArguments(func);
+ // var passed_args = GeneratePassedArgs(func);
+ // var generics = func.Generics == null ? "" : $"<{string.Join(",", func.Generics)}>";
+ // s.Out($"public static {retval} {EscapeName(decl.Name)}{func.SharpOnlyPostfix}{generics}({arguments})");
+ // var prefix = "";
+ // if (levels > 0)
+ // prefix = string.Join("_", class_names.Skip(1)) + "_";
+ // s.Indent(() => s.Out(
+ // $"=> {api.ImplName}.Instance.{EscapeName(prefix + decl.Name)}({passed_args});"));
+ // break;
+ // case Property prop:
+ // s.Out($"public static {retval} {EscapeName(decl.Name)}");
+ // s.Indent(() => s.Out(
+ // $"=> {api.ImplName}.Instance.{EscapeName(decl.Name)};"));
+ // break;
+ // }
+ // if (levels > 0)
+ // {
+ // foreach (var name in class_names.Skip(1))
+ // {
+ // s.Outdent();
+ // s.Out("}");
+ // }
+ // }
+ // if (decl.CommentOut)
+ // s.Out("*/");
+ // s.Break();
+ //}
+
+ // generate the argument list between the parentheses of a generated API function
+ protected virtual string GenerateArguments(Function decl)
+ {
+ var s = new StringBuilder();
+ int i = 0;
+ foreach (var arg in decl.Arguments)
+ {
+ if (arg.Type == "string")
+ arg.IsValueType = false;
+ // TODO modifier (if any)
+ // parameter type
+ CheckArgument(arg);
+ s.Append(arg.Type);
+ if (arg.IsNullable && arg.IsValueType)
+ s.Append("?");
+ s.Append(" ");
+ // parameter name
+ s.Append(EscapeName(arg.Name));
+ if (!string.IsNullOrWhiteSpace(arg.DefaultValue))
+ s.Append($" = {MapDefaultValue(arg)}");
+ else if (arg.IsNullable)
+ s.Append($" = null");
+ i++;
+ if (i < decl.Arguments.Count)
+ s.Append(", ");
+ }
+ return s.ToString();
+ }
+
+ private string GeneratePassedArgs(Function decl)
+ {
+ var s = new StringBuilder();
+ int i = 0;
+ foreach (var arg in decl.Arguments)
+ {
+ // TODO modifier (if any)
+ var argname = EscapeName(arg.Name);
+ if (arg.IsNamedArg)
+ s.Append($"{argname}:");
+ s.Append(argname);
+ i++;
+ if (i < decl.Arguments.Count)
+ s.Append(", ");
+ }
+ return s.ToString();
+ }
+
+ // maps None to null, etc
+ protected virtual string MapDefaultValue(Argument arg)
+ {
+ switch (arg.DefaultValue)
+ {
+ case "None": return "null";
+ case "True": return "true";
+ case "False": return "false";
+ }
+ return arg.DefaultValue;
+ }
+
+ // list of c# keywords that are not allowed as variable names or parameter names
+ protected readonly HashSet _disallowed_names = new HashSet()
+ {
+ "abstract", "as", "base", "bool", "break",
+ "byte", "case", "catch", "char", "checked",
+ "class", "const", "continue", "decimal", "default",
+ "delegate", "do", "double", "else", "enum",
+ "event", "explicit", "extern", "false", "finally",
+ "fixed", "float", "for", "foreach", "goto",
+ "if", "implicit", "in", "int", "interface",
+ "internal", "is", "lock", "long", "namespace",
+ "new", "null", "object", "operator", "out",
+ "override", "params", "private", "protected", "public",
+ "readonly", "ref", "return", "sbyte", "sealed",
+ "short", "sizeof", "stackalloc", "static", "string",
+ "struct", "switch", "this", "throw", "true",
+ "try", "typeof", "uint", "ulong", "unchecked",
+ "unsafe", "ushort", "using", "var", "virtual",
+ "void", "volatile", "while",
+ "add", "alias", "async", "await", "dynamic",
+ "get", "global", "nameof", "partial", "remove",
+ "set", "value", "when", "where", "yield",
+ "ascending", "by", "descending", "equals", "from",
+ "group", "in", "into", "join", "let",
+ "on", "orderby", "select", "where"
+ };
+
+ // escape a varibale name if it violates C# syntax
+ protected virtual string EscapeName(string name)
+ {
+ if (_disallowed_names.Contains(name))
+ return "@" + name;
+ return name;
+ }
+
+ // generates the return type declaration of a generated API function declaration
+ protected virtual string GenerateReturnType(Declaration decl)
+ {
+ if (decl.Returns == null || decl.Returns.Count == 0)
+ return "void";
+ else if (decl.Returns.Count == 1)
+ {
+ CheckArgument(decl.Returns[0]);
+ return decl.Returns[0].Type;
+ }
+ else
+ {
+ return "(" + string.Join(", ", decl.Returns.Select(x => x.Type).ToArray()) + ")";
+ }
+ }
+
+ // argument type consistency checks
+ protected virtual void CheckArgument(Argument arg)
+ {
+ switch (arg.Type)
+ {
+ // basic types
+ case "bool":
+ case "int":
+ case "long":
+ case "double":
+ case "float":
+ arg.IsValueType = true;
+ break;
+ case "object":
+ case "string":
+ arg.IsValueType = false;
+ break;
+ // sequence types
+ }
+ }
+
+ ///
+ /// Generate the xml doc string from the description(s)
+ ///
+ ///
+ ///
+ protected virtual void GenerateDocString(Declaration decl, CodeWriter s)
+ {
+ if (string.IsNullOrWhiteSpace(decl.Description))
+ return;
+ s.Out("/// ");
+ var docstring = ProcessDocString(decl.Description);
+ foreach (var line in Regex.Split(docstring, @"\r?\n"))
+ s.Out("///\t" + line);
+ s.Out("/// ");
+ if (decl is Function)
+ {
+ var func = decl as Function;
+ foreach (var arg in func.Arguments)
+ {
+ if (string.IsNullOrWhiteSpace(arg.Description))
+ continue;
+ s.Out($"/// "); // note: docstring doesn't want parameters escaped with "@"
+ docstring = ProcessDocString(arg.Description);
+ foreach (var line in Regex.Split(docstring, @"\r?\n"))
+ s.Out("///\t" + line.TrimStart());
+ s.Out("/// ");
+ }
+ }
+ if (decl.Returns.All(rv => string.IsNullOrWhiteSpace(rv.Description)))
+ return;
+ s.Out("/// ");
+ if (decl.Returns.Count == 1)
+ foreach (var line in Regex.Split(ProcessDocString(decl.Returns[0].Description), @"\r?\n"))
+ s.Out("///\t" + line);
+ else
+ {
+ s.Out("/// A tuple of:");
+ foreach (var rv in decl.Returns)
+ {
+ s.Out("/// " + rv.Name);
+ foreach (var line in Regex.Split(rv.Description, @"\r?\n"))
+ s.Out("///\t" + line);
+ }
+ }
+ s.Out("/// ");
+ }
+
+ protected virtual void GenerateDocString(ApiClass decl, CodeWriter s)
+ {
+ if (string.IsNullOrWhiteSpace(decl.DocString))
+ return;
+ var docstring= ProcessDocString(decl.DocString);
+ s.Out("/// ");
+ foreach (var line in Regex.Split(docstring, @"\r?\n"))
+ s.Out("///\t" + line);
+ s.Out("/// ");
+ }
+
+ protected string ProcessDocString(string docstring)
+ {
+ if (string.IsNullOrWhiteSpace(docstring))
+ return docstring;
+ // insert linebreak after each sentence
+ var text= Regex.Replace(docstring, @"(?:(?<=\w|\)|\])(?\n", RegexOptions.Multiline);
+ text = Regex.Replace(text, @"(\r?\n){2,}", "\n\n");
+ text = Regex.Replace(text.Trim(), "
$", "");
+ return text;
+ }
+
+ // generates only the body of the API function declaration
+ protected virtual void GenerateFunctionBody(Function func, CodeWriter s, string prefix = "")
+ {
+ s.Out("//auto-generated code, do not change");
+ if (_templates.ContainsKey(func.Name))
+ {
+ // use generator template instead
+ _templates[func.Name].GenerateBody(func, s);
+ return;
+ }
+
+ //if (func.Name=="norm")
+ // Debugger.Break();
+ var class_names = (func.ClassName ?? "no_name").Split('.');
+ int levels = class_names.Length - 1;
+ if (levels < 1)
+ {
+ s.Out("var __self__=self;");
+ }
+ else
+ {
+ var last = "self";
+ foreach (var name in class_names.Skip(1))
+ {
+ s.Out($"var {EscapeName(name)} = {last}.GetAttr(\"{name}\");");
+ last = name;
+ }
+ s.Out($"var __self__={last};");
+ }
+ if (func.Arguments.Any())
+ {
+ // first generate the positional args
+ s.Out($"var pyargs=ToTuple(new object[]");
+ s.Block(() =>
+ {
+ foreach (var arg in func.Arguments.Where(a => a.IsNamedArg == false))
+ {
+ var name = EscapeName(arg.Name);
+ if (!string.IsNullOrWhiteSpace(arg.ConvertToSharpType))
+ s.Out($"SharpToSharp<{arg.ConvertToSharpType}>({name}),");
+ else
+ s.Out($"{name},");
+ }
+ }, "{", "});");
+ // then generate the named args
+ s.Out($"var kwargs=new PyDict();");
+ foreach (var arg in func.Arguments.Where(a => a.IsNamedArg == true))
+ {
+ var name = EscapeName(arg.Name);
+ if (!string.IsNullOrWhiteSpace(arg.DefaultValue))
+ s.Out($"if ({name}!={arg.DefaultValue}) kwargs[\"{arg.Name}\"]=ToPython({name});");
+ else if (string.IsNullOrWhiteSpace(arg.DefaultValue))
+ {
+ if (string.IsNullOrWhiteSpace(arg.DefaultIfNull) || arg.DefaultValue == "null")
+ s.Out($"if ({name}!=null) kwargs[\"{arg.Name}\"]=ToPython({name});");
+ else
+ s.Out($"kwargs[\"{arg.Name}\"]=ToPython({name} ?? {arg.DefaultIfNull});");
+ }
+ else //if (arg.IsNullable)
+ s.Out($"if ({name}!=null) kwargs[\"{arg.Name}\"]=ToPython({name});");
+
+ }
+ // then call the function
+ s.Out($"dynamic py = __self__.InvokeMethod(\"{func.Name}\", pyargs, kwargs);");
+ }
+ else
+ {
+ // call function with no arguments
+ s.Out($"dynamic py = __self__.InvokeMethod(\"{func.Name}\");");
+ }
+
+ if (func.IsConstructor)
+ {
+ s.Out("self=py as PyObject;");
+ return;
+ }
+ // return the return value if any
+ if (func.Returns.Count == 0)
+ return;
+ if (func.Returns.Count == 1)
+ s.Out($"return ToCsharp<{func.Returns[0].Type}>(py);");
+ else
+ {
+ var returns = func.Returns.Select((x, i) => $"ToCsharp<{x.Type}>(py[{i}])").ToArray();
+ s.Out($"return ({string.Join(", ", returns)});");
+ }
+ }
+
+ //private void GenerateForwardingBody(Function member_func, CodeWriter s, string prefix = "")
+ //{
+ // var func = member_func.Clone();
+ // // inserting this at position 0 since this is a forwarding of a member function to a static implementation
+ // func.Arguments.Insert(0, new Argument() { Name = "this", Type = "irrelevant" });
+ // var passed_args = GeneratePassedArgs(func);
+ // s.Out("var @this=this;");
+ // var return_keyword = member_func.Returns.Count > 0 ? "return " : "";
+ // s.Out($"{return_keyword}{func.ForwardToStaticImpl}.{EscapeName(prefix + func.Name)}({passed_args});");
+ //}
+
+ private void GeneratePropertyGetter(Property prop, CodeWriter s)
+ {
+ s.Out($"dynamic py = self.GetAttr(\"{prop.Name}\");");
+ if (prop.Returns.Count==1 && prop.Type!=null)
+ s.Out($"return ToCsharp<{prop.Type}>(py);");
+ else
+ {
+ throw new NotImplementedException("TODO: Property returns a tuple");
+ }
+ }
+
+ private void GeneratePropertySetter(Property prop, CodeWriter s)
+ {
+ s.Out($"self.SetAttr(\"{prop.Name}\", ToPython(value));");
+ }
+
+ public virtual void GenerateStaticApi(StaticApi api, CodeWriter s)
+ {
+ GenerateUsings(s);
+ s.Out($"namespace {NameSpace}");
+ s.Block(() =>
+ {
+ s.Out($"public static partial class {api.StaticName}");
+ s.Block(() =>
+ {
+ s.Break();
+ foreach (var decl in api.Declarations)
+ {
+ try
+ {
+ if (decl.Ignore)
+ continue;
+ GenerateApiFunction(decl, s, @static:true);
+ }
+ catch (Exception e)
+ {
+ s.Out("// Error generating delaration: " + decl.Name);
+ s.Out("// Message: " + e.Message);
+ s.Out("/*");
+ s.Out(e.StackTrace);
+ s.Out("----------------------------");
+ s.Out("Declaration JSON:");
+ s.Out(JObject.FromObject(decl).ToString(Formatting.Indented));
+ s.Out("*/");
+
+ }
+ }
+ s.Break();
+ });
+ });
+ }
+
+ private void GenerateUsings(CodeWriter s)
+ {
+ foreach (var @using in Usings)
+ {
+ s.AppendLine(@using);
+ }
+ s.Out(@"#if PYTHON_INCLUDED");
+ s.Out(@"using Python.Included;");
+ s.Out(@"#endif");
+ s.AppendLine();
+ }
+
+ public virtual void GenerateApiImpl(StaticApi api, CodeWriter s)
+ {
+ GenerateUsings(s);
+ s.AppendLine($"namespace {NameSpace}");
+ s.Block(() =>
+ {
+ s.Out($"public partial class {api.ImplName}");
+ s.Block(() =>
+ {
+ s.Break();
+ foreach (var decl in api.Declarations)
+ {
+ try
+ {
+ if (decl.ManualOverride || decl.Ignore)
+ continue;
+ GenerateApiFunction(decl, s, prefix: true);
+ }
+ catch (Exception e)
+ {
+ s.Out("// Error generating delaration: " + decl.Name);
+ s.Out("// Message: " + e.Message);
+ s.Out("/*");
+ s.Out(e.StackTrace);
+ s.Out("----------------------------");
+ s.Out("Declaration JSON:");
+ s.Out(JObject.FromObject(decl).ToString(Formatting.Indented));
+ s.Out("*/");
+
+ }
+ }
+ });
+ });
+ }
+
+ public virtual void GenerateDynamicApi(DynamicApi api, CodeWriter s)
+ {
+ GenerateUsings(s);
+ s.AppendLine($"namespace {NameSpace}");
+ s.Block(() =>
+ {
+ s.Out($"public partial class {api.ClassName}");
+ s.Block(() =>
+ {
+ s.Break();
+ foreach (var decl in api.Declarations)
+ {
+ try
+ {
+ if (decl.ManualOverride || decl.Ignore)
+ continue;
+ if (decl is Function && !(decl as Function).IsExtensionFunction)
+ GenerateApiFunction(decl, s);
+ }
+ catch (Exception e)
+ {
+ s.Out("// Error generating delaration: " + decl.Name);
+ s.Out("// Message: " + e.Message);
+ s.Out("/*");
+ s.Out(e.StackTrace);
+ s.Out("----------------------------");
+ s.Out("Declaration JSON:");
+ s.Out(JObject.FromObject(decl).ToString(Formatting.Indented));
+ s.Out("*/");
+ }
+ }
+ });
+ });
+ }
+
+ public virtual void GenerateClass(ApiClass api, CodeWriter s)
+ {
+ GenerateUsings(s);
+ s.AppendLine($"namespace {NameSpace}");
+ s.Block(() =>
+ {
+ var names = new ArraySlice(api.ClassName.Split('.'));
+ var static_classes = names.GetSlice(new Slice(0, names.Length - 1));
+ var class_name = names.Last();
+ int levels = names.Length - 1;
+ if (levels > 0)
+ {
+ foreach (var name in static_classes)
+ {
+ s.Out($"public static partial class {EscapeName(name)} {{");
+ s.Indent();
+ }
+ }
+ GenerateDocString(api, s);
+ s.Out($"public partial class {EscapeName(class_name)} : {EscapeName(api.BaseClass)}");
+ s.Block(() =>
+ {
+ s.Out($"// auto-generated class");
+ s.Break();
+ s.Out($"public {EscapeName(class_name)}(PyObject pyobj) : base(pyobj) {{ }}");
+ s.Break();
+ s.Out($"public {EscapeName(class_name)}({EscapeName(api.BaseClass)} other) : base(other.PyObject as PyObject) {{ }}");
+ s.Break();
+
+ // additional constructors
+ foreach (var func in api.Constructors)
+ {
+ try
+ {
+ if (func.ManualOverride || func.Ignore)
+ continue;
+ func.Sanitize();
+ func.IsConstructor = true;
+ func.ClassName = string.Join(".", static_classes);
+ func.Name = class_name;
+ var arguments = GenerateArguments(func);
+ //var passed_args = GeneratePassedArgs(func);
+ s.Out($"public {EscapeName(class_name)}({arguments})");
+ s.Block(() =>
+ {
+ GenerateFunctionBody(func, s);
+ });
+ }
+ catch (Exception e)
+ {
+ s.Out("// Error generating constructor");
+ s.Out("// Message: " + e.Message);
+ s.Out("/*");
+ s.Out(e.StackTrace);
+ s.Out("----------------------------");
+ s.Out("Declaration JSON:");
+ s.Out(JObject.FromObject(func).ToString(Formatting.Indented));
+ s.Out("*/");
+ }
+ }
+ // functions
+ s.Break();
+ foreach (var decl in api.Declarations)
+ {
+ try
+ {
+ if (decl.ManualOverride || decl.Ignore)
+ continue;
+ GenerateApiFunction(decl, s);
+ }
+ catch (Exception e)
+ {
+ s.Out("// Error generating delaration: " + decl.Name);
+ s.Out("// Message: " + e.Message);
+ s.Out("/*");
+ s.Out(e.StackTrace);
+ s.Out("----------------------------");
+ s.Out("Declaration JSON:");
+ s.Out(JObject.FromObject(decl).ToString(Formatting.Indented));
+ s.Out("*/");
+ }
+ }
+ });
+ if (levels > 0)
+ {
+ foreach (var name in static_classes)
+ {
+ s.Outdent();
+ s.Out("}");
+ }
+ }
+ //if (decl.CommentOut)
+ // s.Out("*/");
+ s.Break();
+ });
+ }
+ protected void WriteFile(string path, Action generate_action)
+ {
+ var s = new CodeWriter();
+ try
+ {
+ if (!string.IsNullOrWhiteSpace(CopyrightNotice))
+ s.Out("// " + CopyrightNotice);
+ s.Out("// Code generated by CodeMinion: https://github.com/SciSharp/CodeMinion");
+ s.Break();
+ generate_action(s);
+ }
+ catch (Exception e)
+ {
+ s.AppendLine("/*");
+ s.AppendLine("\r\n --------------- generator exception ---------------------");
+ s.AppendLine(e.Message);
+ s.AppendLine(e.StackTrace);
+ s.AppendLine("*/");
+ }
+
+ var dir = Path.GetDirectoryName(path);
+ if (!Directory.Exists(dir))
+ Directory.CreateDirectory(dir);
+ File.WriteAllText(path, s.ToString());
+ }
+
+ public void Generate()
+ {
+ // generate all static apis that have been configured
+ var generated_implementations = new HashSet();
+ var conv_file = Path.Combine(StaticApiFilesPath, $"{StaticModuleName}.module.gen.cs");
+ WriteFile(conv_file, s => { GenerateStaticModuleHead( s); });
+
+ foreach (var api in StaticApis)
+ {
+ var outpath = api.OutputPath ?? StaticApiFilesPath;
+ if (string.IsNullOrWhiteSpace(outpath))
+ throw new InvalidDataException("either set generators StaticApiFilesPath or static_api's OutputPath");
+ // generate static apis
+ //if (!generated_implementations.Contains(api.ImplName))
+ //{
+ //}
+
+ generated_implementations.Add(api.ImplName);
+ var partial = (api.PartialName == null ? "" : "." + api.PartialName);
+ var api_file = Path.Combine(outpath, $"{api.StaticName + partial}.gen.cs");
+ //var impl_file = Path.Combine(outpath, $"{api.ImplName + partial}.gen.cs");
+ WriteFile(api_file, s => { GenerateStaticApi(api, s); });
+ //WriteFile(impl_file, s => { GenerateApiImpl(api, s); });
+ }
+ // PythonObject functions:
+ var pyobj_file = Path.Combine(ModelsPath ?? DynamicApiFilesPath, $"PythonObject.gen.cs");
+ WriteFile(pyobj_file, s => { GeneratePythonObjectConversions(s); });
+ // Dynamic APIs
+ foreach (var api in DynamicApis)
+ {
+ var outpath = api.OutputPath ?? DynamicApiFilesPath;
+ // generate dynamic apis
+ var partial = (api.PartialName == null ? "" : "." + api.PartialName);
+ var api_file = Path.Combine(outpath, $"{api.ClassName + partial}.gen.cs");
+ WriteFile(api_file, s => { GenerateDynamicApi(api, s); });
+ }
+ // Classes
+ foreach (var api in ApiClasses)
+ {
+ if (api.Ignore)
+ continue;
+ var outpath = api.OutputPath ?? DynamicApiFilesPath;
+ if (api.SubDir != null)
+ outpath = Path.Combine(outpath, api.SubDir);
+ // generate dynamic apis
+ var partial = (api.PartialName == null ? "" : "." + api.PartialName);
+ var api_file = Path.Combine(outpath, $"{api.ClassName + partial}.gen.cs");
+ WriteFile(api_file, s => { GenerateClass(api, s); });
+ }
+ // generate missing tests
+ GenerateAllTests();
+ }
+
+ ///
+ /// Generate tests that probably have to be manually corrected, syntax wise. For that reason
+ /// We will not overwrite any existing files!
+ ///
+ public void GenerateAllTests()
+ {
+ foreach (var file in TestFiles)
+ {
+ if(file.TestCases.Count==0)
+ continue;
+ var path = TestFilesPath;
+ if (!string.IsNullOrWhiteSpace(file.SubDir))
+ path = Path.Combine(path, file.SubDir);
+ if (!Directory.Exists(path))
+ Directory.CreateDirectory(path);
+ var test_file = Path.Combine(path, $"{file.Name}.tests.cs");
+ if (File.Exists(test_file))
+ continue; // never overwrite already generated files!
+ WriteFile(test_file, s => { GenerateTests(file, s); });
+ }
+ }
+
+ private void GenerateTests(TestFile file, CodeWriter s)
+ {
+ GenerateUsings(s);
+ s.Out("using Microsoft.VisualStudio.TestTools.UnitTesting;");
+ s.Out("using Assert = NUnit.Framework.Assert;");
+ s.Break();
+ s.Out($"namespace {NameSpace}.UnitTest", () =>
+ {
+ s.Out("[TestClass]");
+ s.Out($"public class {file.Name}Test : BaseTestCase", () =>
+ {
+ foreach (var testcase in file.TestCases)
+ GenerateTestCase(testcase, s);
+ });
+ });
+ }
+
+ private void GenerateTestCase(TestCase testcase, CodeWriter s)
+ {
+ s.Break();
+ s.Out("[TestMethod]");
+ s.Out($"public void {testcase.Name}()", () =>
+ {
+ var given_var = false;
+ var expected_var = false;
+ foreach (var part in testcase.TestParts)
+ {
+ switch (part)
+ {
+ case Comment c:
+ foreach (var ln in Regex.Split(c.Text, @"\r?\n"))
+ s.Out(@"// " + ln);
+ s.Break();
+ break;
+ case ExampleCode example:
+ var lines = Regex.Split(example.Text, @"\r?\n");
+ foreach (var ln in lines)
+ s.Out(@"// " + ln);
+ s.Break();
+ s.Out("#if TODO");
+ foreach (var line in example.Lines)
+ {
+ if (line.Type == "comment")
+ {
+ s.Out(line.Text[0]);
+ continue;
+ }
+ if (line.Type == "cmd")
+ {
+ var cmd = line.Text[0];
+ s.Out($"{(given_var ? "" : "var")} given= " + cmd + ";");
+ given_var = true;
+ continue;
+ }
+
+ if (line.Type == "output")
+ {
+ s.Out($"{(expected_var ? "" : "var")} expected=");
+ expected_var = true;
+ s.Indent(() =>
+ {
+ int i = 0;
+ foreach (var output in line.Text)
+ {
+ var newline = i < line.Text.Count - 1 ? @"\n" : "";
+ var delimiter = i < line.Text.Count - 1 ? @" +" : ";";
+ s.Out($"\"{output}{newline}\"{delimiter}");
+ i++;
+ }
+ });
+ }
+ s.Out("Assert.AreEqual(expected, given.repr);");
+ }
+ s.Out("#endif");
+ break;
+ }
+ }
+ });
+ s.Break();
+ }
+
+ private void GenerateStaticModuleHead(CodeWriter s)
+ {
+ GenerateUsings(s);
+ s.AppendLine($"namespace {NameSpace}");
+ s.Block(() =>
+ {
+ s.Out($"public static partial class {StaticModuleName}", () =>
+ {
+ s.Out("static np()", () =>
+ {
+ s.Out("ReInitializeLazySelf();");
+ });
+ s.Break();
+ s.Out("public static PyObject self => _lazy_self.Value;");
+ s.Break();
+ s.Out($"private static Lazy _lazy_self = default;");
+ s.Out($"private static void ReInitializeLazySelf() => _lazy_self = new Lazy(() => ", () =>
+ {
+ s.Out("try", () =>
+ {
+ s.Out("return InstallAndImport();");
+ });
+ s.Out("catch (Exception)", () =>
+ {
+ s.Out("// retry to fix the installation by forcing a repair, if Python.Included is used.");
+ s.Out("return InstallAndImport(force: true);");
+ });
+ //s.Out("return instance;");
+ });
+ s.Out(");");
+ s.Break();
+ s.Out("private static PyObject InstallAndImport(bool force = false)", () =>
+ {
+ s.Out(@"#if PYTHON_INCLUDED");
+ s.Out("Installer.SetupPython(force).Wait();");
+ s.Out(@"#endif");
+ foreach (var generator in InitializationGenerators)
+ generator(s);
+ s.Out("PythonEngine.AddShutdownHandler(() => ReInitializeLazySelf());");
+ s.Out("PythonEngine.Initialize();");
+ s.Out($"var mod = Py.Import(\"{PythonModuleName}\");");
+ s.Out("return mod;");
+ });
+ s.Break();
+ s.Out("public static dynamic dynamic_self => self;");
+ s.Out("private static bool IsInitialized => self != null;");
+ s.Break();
+ //s.Out($"private {api.ImplName}() {{ }}");
+ s.Break();
+ s.Out("public static void Dispose()", () =>
+ {
+ s.Out("self?.Dispose();");
+ });
+ s.Break();
+ GenToTuple(s, @static:true);
+ GenToPython(s, @static: true);
+ GenToCsharp(s, @static: true);
+ GenSharpToSharp(s, @static: true);
+ GenSpecialConversions(s, @static: true);
+ });
+ });
+ }
+
+ private void GeneratePythonObjectConversions(CodeWriter s)
+ {
+ GenerateUsings(s);
+ s.Out($"namespace {NameSpace}", () =>
+ {
+ s.Out($"public partial class PythonObject", () =>
+ {
+ s.Break();
+ GenToTuple(s);
+ GenToPython(s);
+ GenToCsharp(s);
+ GenSharpToSharp(s);
+ GenSpecialConversions(s);
+ });
+ });
+ }
+
+ private void GenToTuple(CodeWriter s, bool @static=false)
+ {
+ s.Break();
+ s.Out("//auto-generated");
+ s.Out($"{(@static?"private static":"public")} PyTuple ToTuple(Array input)", () =>
+ {
+ s.Out("var array = new PyObject[input.Length];");
+ s.Out("for (int i = 0; i < input.Length; i++)", () =>
+ {
+ s.Out("array[i]=ToPython(input.GetValue(i));");
+ });
+ s.Out("return new PyTuple(array);");
+ });
+ }
+
+ public HashSet ToCsharpConversions { get; set; } = new HashSet();
+
+ private void GenToCsharp(CodeWriter s, bool @static = false)
+ {
+ s.Break();
+ s.Out("//auto-generated");
+ s.Out($"{(@static?"internal static":"public")} T ToCsharp(dynamic pyobj)", () =>
+ {
+ s.Out("switch (typeof(T).Name)", () =>
+ {
+ s.Out("// types from 'ToCsharpConversions'");
+ foreach (var @case in ToCsharpConversions)
+ {
+ s.Out(@case);
+ }
+ s.Out("default:");
+ s.Out("var pyClass = $\"{pyobj.__class__}\";");
+ s.Out("if (pyClass == \"\")", () => s.Out("return (T)(object)pyobj.ToString();"));
+ s.Out("if (pyClass.StartsWith(\" s.Out("return (pyobj.item() as PyObject).As();"));
+ s.Out("try", () => s.Out("return pyobj.As();"));
+ s.Out("catch (Exception e)", () =>
+ {
+ s.Out("throw new NotImplementedException($\"conversion from {pyobj.__class__} to {typeof(T).Name} not implemented\", e);");
+ s.Out("return default(T);");
+ });
+ });
+ });
+ }
+
+ public HashSet ToPythonConversions { get; set; } = new HashSet();
+
+ private void GenToPython(CodeWriter s, bool @static=false)
+ {
+ s.Break();
+ s.Out("//auto-generated");
+ s.Out($"{(@static?"internal static":"public")} PyObject ToPython(object obj)", () =>
+ {
+ s.Out("if (obj == null) return Runtime.None;");
+ s.Out("switch (obj)", () =>
+ {
+ s.Out("// basic types");
+ s.Out("case int o: return new PyInt(o);");
+ s.Out("case long o: return new PyInt(o);");
+ s.Out("case float o: return new PyFloat(o);");
+ s.Out("case double o: return new PyFloat(o);");
+ s.Out("case string o: return new PyString(o);");
+ s.Out("case bool o: return ConverterExtension.ToPython(o);");
+ s.Out("case PyObject o: return o;");
+ s.Out("// sequence types");
+ s.Out("case Array o: return ToTuple(o);");
+ s.Out("// special types from 'ToPythonConversions'");
+ foreach (var @case in ToPythonConversions)
+ {
+ s.Out(@case);
+ }
+ s.Out("default: throw new NotImplementedException($\"Type is not yet supported: { obj.GetType().Name}. Add it to 'ToPythonConversions'\");");
+ });
+ });
+ }
+
+ public List> SharpToSharpConversions { get; set; } = new List>();
+
+ private void GenSharpToSharp(CodeWriter s, bool @static=false)
+ {
+ s.Break();
+ s.Out("//auto-generated");
+ s.Out($"{(@static ? "internal static" : "public")} T SharpToSharp(object obj)", () =>
+ {
+ s.Out("if (obj == null) return default(T);");
+ s.Out("switch (obj)", () =>
+ {
+ s.Out("// from 'SharpToSharpConversions':");
+ foreach (var gen in SharpToSharpConversions)
+ {
+ gen(s);
+ }
+ });
+ s.Out("throw new NotImplementedException($\"Type is not yet supported: { obj.GetType().Name}. Add it to 'SharpToSharpConversions'\");");
+ });
+ }
+
+
+ public List> SpecialConversionGenerators { get; set; } = new List>();
+
+ private void GenSpecialConversions(CodeWriter s, bool @static=false)
+ {
+ foreach (var generator in SpecialConversionGenerators)
+ {
+ s.Break();
+ s.Out("//auto-generated: SpecialConversions");
+ generator(s);
+ }
+ }
+
+ public void GenerateIntermediateJson()
+ {
+ foreach (var api in StaticApis)
+ {
+ var outpath = api.OutputPath ?? StaticApiFilesPath;
+ if (string.IsNullOrWhiteSpace(outpath))
+ throw new InvalidDataException("either set generators StaticApiFilesPath or static_api's OutputPath");
+ // generate static apis
+ var partial = (api.PartialName == null ? "" : "." + api.PartialName);
+ var api_file = Path.Combine(outpath, $"{api.StaticName + partial}.gen.json");
+ WriteFile(api_file, s => s.AppendLine(JObject.FromObject(api).ToString(Formatting.Indented)));
+ }
+ foreach (var api in DynamicApis)
+ {
+ var outpath = api.OutputPath ?? DynamicApiFilesPath;
+ // generate dynamic apis
+ var partial = (api.PartialName == null ? "" : "." + api.PartialName);
+ var api_file = Path.Combine(outpath, $"{api.ClassName + partial}.gen.json");
+ WriteFile(api_file, s => s.AppendLine(JObject.FromObject(api).ToString(Formatting.Indented)));
+ }
+ }
+ }
+}
diff --git a/src/CodeMinion.Core/CodeMinion.Core.csproj b/src/CodeMinion.Core/CodeMinion.Core.csproj
new file mode 100644
index 0000000..0222f53
--- /dev/null
+++ b/src/CodeMinion.Core/CodeMinion.Core.csproj
@@ -0,0 +1,18 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
+
+
+ C:\Users\henon\.nuget\packages\sliceanddice\1.0.0\lib\netstandard2.0\SliceAndDice.dll
+
+
+
+
diff --git a/src/CodeMinion.Core/FunctionBodyTemplate.cs b/src/CodeMinion.Core/FunctionBodyTemplate.cs
new file mode 100644
index 0000000..281adc6
--- /dev/null
+++ b/src/CodeMinion.Core/FunctionBodyTemplate.cs
@@ -0,0 +1,12 @@
+using System.Text;
+using CodeMinion.Core.Helpers;
+using CodeMinion.Core.Models;
+
+namespace CodeMinion.Core
+{
+
+ public abstract class FunctionBodyTemplate
+ {
+ public abstract void GenerateBody(Function decl, CodeWriter s);
+ }
+}
diff --git a/src/CodeMinion.Core/Helpers/CodeWriter.cs b/src/CodeMinion.Core/Helpers/CodeWriter.cs
new file mode 100644
index 0000000..fcd0a5f
--- /dev/null
+++ b/src/CodeMinion.Core/Helpers/CodeWriter.cs
@@ -0,0 +1,100 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CodeMinion.Core.Helpers
+{
+ public class CodeWriter
+ {
+
+ public CodeWriter() { }
+
+ public CodeWriter(StringBuilder s)
+ {
+ StringBuilder = s;
+ }
+
+ public StringBuilder StringBuilder { get; set; } = new StringBuilder();
+ public int IndentSpaces { get; set; } = 4;
+ private int _level = 0;
+
+ ///
+ /// Write a line (with automatic indentation), line break is appended
+ ///
+ public void Out(string line, Action block=null)
+ {
+ if (_level > 0)
+ StringBuilder.Append(new String(' ', IndentSpaces * _level));
+ StringBuilder.AppendLine(line);
+ if (block==null)
+ return;
+ Block(block);
+ }
+
+ ///
+ /// Alias of Out
+ ///
+ public void AppendLine(string s="")
+ {
+ Out(s);
+ }
+
+ ///
+ /// Insert an empty line
+ ///
+ public void Break()
+ {
+ Out("");
+ }
+
+ ///
+ /// Increase the level of indentation
+ ///
+ public void Indent()
+ {
+ _level++;
+ }
+
+ ///
+ /// Decrease the level of indentation
+ ///
+ public void Outdent()
+ {
+ _level--;
+ }
+
+ ///
+ /// Increase the level of indentation for the generator action, then outdent
+ ///
+ public void Indent(Action a)
+ {
+ _level++;
+ try
+ {
+ a();
+ }
+ finally
+ {
+ _level--;
+ }
+ }
+
+ ///
+ /// Generate an indented code block
+ ///
+ ///
+ ///
+ ///
+ public void Block(Action a, string opening_brace = "{", string closing_brace = "}")
+ {
+ Out(opening_brace);
+ Indent(a);
+ Out(closing_brace);
+ }
+
+ public override string ToString()
+ {
+ return StringBuilder.ToString();
+ }
+ }
+}
diff --git a/src/CodeMinion.Core/ICodeGenerator.cs b/src/CodeMinion.Core/ICodeGenerator.cs
new file mode 100644
index 0000000..6907df6
--- /dev/null
+++ b/src/CodeMinion.Core/ICodeGenerator.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Torch.ApiGenerator
+{
+ public interface ICodeGenerator
+ {
+ string Generate();
+ }
+}
diff --git a/src/CodeMinion.Core/Models/Argument.cs b/src/CodeMinion.Core/Models/Argument.cs
new file mode 100644
index 0000000..e2fade4
--- /dev/null
+++ b/src/CodeMinion.Core/Models/Argument.cs
@@ -0,0 +1,58 @@
+using Newtonsoft.Json.Linq;
+
+namespace CodeMinion.Core.Models
+{
+ public class Argument
+ {
+ public bool IsNullable { get; set; }
+ public bool IsValueType { get; set; }
+ public string Name { get; set; }
+ public string Type { get; set; }
+ public string DefaultValue { get; set; }
+ public bool IsNamedArg { get; set; }
+ public string Description { get; set; }
+
+ ///
+ /// Before sending to Python convert to the given C# Type, only then convert to Python type
+ ///
+ public string ConvertToSharpType { get; set; }
+
+ public int Position { get; set; }
+ public bool IsReturnValue { get; set; }
+ public string Tag { get; set; }
+
+ ///
+ /// This default value is not a compile time constant, so it can not be used as a C# default value in
+ /// the function declaration. So if the parameter is passed as null it will be initialized with the given value.
+ ///
+ public string DefaultIfNull { get; set; }
+
+ public bool PassOnlyIfNotNull { get; set; }
+ public bool Ignore { get; set; }
+
+ public Argument Clone()
+ {
+ return JObject.FromObject(this).ToObject();
+ }
+
+ public void SetNullableOptional(string type, string @default = null)
+ {
+ Type = type;
+ IsNullable = true;
+ IsNamedArg = true;
+ DefaultValue = @default;
+ }
+
+ public void SetType(string type, string @default=null)
+ {
+ Type = type;
+ DefaultValue = @default;
+ }
+
+ public void MakeMandatory()
+ {
+ DefaultValue = null;
+ IsNullable = false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CodeMinion.Core/Models/Declaration.cs b/src/CodeMinion.Core/Models/Declaration.cs
new file mode 100644
index 0000000..7bf5e45
--- /dev/null
+++ b/src/CodeMinion.Core/Models/Declaration.cs
@@ -0,0 +1,55 @@
+using System.Collections.Generic;
+using Newtonsoft.Json.Linq;
+
+namespace CodeMinion.Core.Models
+{
+ public class Declaration
+ {
+ ///
+ /// Function name
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Class name is the name of the containing API class (i.e. "numpy").
+ /// If it is a nested class the class name contains all nesting levels (i.e. "numpy.core.records")
+ ///
+ public string ClassName { get; set; }
+ public string GeneratedClassName { get; set; }
+
+ public List Returns { get; set; } = new List();
+ public bool IsDeprecated { get; set; }
+ public bool ManualOverride { get; set; }
+ public bool CommentOut { get; set; }
+ public string SharpOnlyPostfix { get; set; }
+
+ ///
+ /// Do not generate if true
+ ///
+ public bool Ignore { get; set; }
+
+ ///
+ /// Break into the Debugger when generating this declaration
+ ///
+ public bool DebuggerBreak { get; set; }
+
+ public string Description { get; set; }
+
+ public virtual Declaration Clone()
+ {
+ return Clone();
+ }
+
+ public virtual T Clone()
+ {
+ return JObject.FromObject(this).ToObject();
+ }
+
+ public string Tag { get; set; }
+
+ public virtual void Sanitize()
+ {
+
+ }
+ }
+}
diff --git a/src/CodeMinion.Core/Models/DynamicApi.cs b/src/CodeMinion.Core/Models/DynamicApi.cs
new file mode 100644
index 0000000..1beb052
--- /dev/null
+++ b/src/CodeMinion.Core/Models/DynamicApi.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using CodeMinion.Core.Helpers;
+
+namespace CodeMinion.Core.Models
+{
+ ///
+ /// Represents the methods of a non-static class which should be generated.
+ ///
+ /// Note: the class itself is set up manually, this only generates more methods into that class.
+ /// To generate a full class from scratch use ApiClass
+ ///
+ public class DynamicApi : Api
+ {
+ ///
+ /// Class name is the name of a non-static class, i.e. NDArray
+ ///
+ public string ClassName { get; set; }
+ }
+
+ ///
+ /// Represents a non-static class which should be generated.
+ ///
+ public class ApiClass : Api
+ {
+ public string DocString;
+
+ ///
+ /// Class name is the name of a non-static class, i.e. NDArray
+ ///
+ public string ClassName { get; set; }
+
+ ///
+ /// Do not generate this class
+ ///
+ public bool Ignore { get; set; }
+
+ public string BaseClass { get; set; } = "PythonObject";
+
+ public List Constructors = new List();
+ }
+}
diff --git a/src/CodeMinion.Core/Models/Function.cs b/src/CodeMinion.Core/Models/Function.cs
new file mode 100644
index 0000000..8525999
--- /dev/null
+++ b/src/CodeMinion.Core/Models/Function.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Newtonsoft.Json;
+
+namespace CodeMinion.Core.Models
+{
+ public class Function : Declaration
+ {
+ public List Arguments { get; set; } = new List();
+
+ public bool IsConstructor { get; set; }
+
+ ///
+ /// Generate only the static function which also serves as an extension function
+ ///
+ public bool IsExtensionFunction { get; set; } = false;
+
+ ///
+ /// Generic type parameters of the function
+ ///
+ public string[] Generics { get; set; } = null;
+
+ public virtual Function Clone(Action a)
+ {
+ var clone= Clone();
+ a(clone);
+ return clone;
+ }
+
+ public void ChangeArg(string name, string Type=null, string DefaultValue = null, bool? IsNullable = null)
+ {
+ var arg = Arguments.First(a => a.Name == name);
+ if (Type != null) arg.Type = Type;
+ if (DefaultValue != null) arg.DefaultValue = DefaultValue;
+ if (IsNullable != null) arg.IsNullable = IsNullable.Value;
+ }
+
+ public override void Sanitize()
+ {
+ base.Sanitize();
+ SanitizeArguments();
+ }
+
+ public void SanitizeArguments()
+ {
+ var all_named = false;
+ foreach (var arg in Arguments.ToArray())
+ {
+ if (arg.Ignore)
+ Arguments.Remove(arg);
+ if (arg.DefaultValue != null || arg.IsNamedArg)
+ all_named = true;
+ if (all_named)
+ arg.IsNamedArg = true;
+ if (arg.Name == "self")
+ arg.Name = "self_";
+ if (arg.DefaultValue == "null" && !arg.IsNullable)
+ {
+ switch (arg.Type)
+ {
+ case "int":
+ case "long":
+ case "float":
+ case "double":
+ case "bool":
+ arg.IsNullable = true;
+ break;
+ }
+ }
+
+ if (arg.Type == "float" && !string.IsNullOrWhiteSpace(arg.DefaultValue) &&
+ arg.DefaultValue.Contains('.') && !arg.DefaultValue.EndsWith("f"))
+ arg.DefaultValue += "f";
+ if (arg.DefaultValue != null && arg.DefaultValue.StartsWith("\""))
+ arg.Type = "string";
+ }
+ if (Arguments.Count == 1)
+ {
+ var arg = Arguments[0];
+ if (arg.Type != null && arg.Type.EndsWith("[]") && !arg.Type.StartsWith("params"))
+ {
+ arg.Type = "params " + arg.Type;
+ arg.IsNullable = false;
+ arg.DefaultValue = null;
+ }
+ }
+ }
+
+ public Argument this[string name] => Arguments.FirstOrDefault(x => x.Name == name);
+
+ public void MakeGeneric(string type_param)
+ {
+ Generics = new[] {type_param};
+ }
+
+ [JsonIgnore]
+ public string ReturnType
+ {
+ get { return Returns.FirstOrDefault()?.Type; }
+ set
+ {
+ if (Returns.Count > 0)
+ Returns[0].Type = value;
+ else
+ Returns.Add(new Argument() { Type = value });
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/CodeMinion.Core/Models/Library/PyClass.cs b/src/CodeMinion.Core/Models/Library/PyClass.cs
new file mode 100644
index 0000000..14a6d6d
--- /dev/null
+++ b/src/CodeMinion.Core/Models/Library/PyClass.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CodeMinion.Core.Models
+{
+ ///
+ /// Information about python class
+ ///
+ public class PyClass
+ {
+ public PyClass()
+ {
+ Parameters = new List();
+ }
+
+ ///
+ /// Gets or sets the name.
+ ///
+ ///
+ /// The name.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the functions.
+ ///
+ ///
+ /// The functions.
+ ///
+ public PyFunction[] Functions { get; set; }
+
+ ///
+ /// Gets or sets the document string.
+ ///
+ ///
+ /// The document string.
+ ///
+ public string DocStr { get; set; }
+
+ ///
+ /// Gets or sets the arguments.
+ ///
+ ///
+ /// The arguments.
+ ///
+ public string[] Args { get; set; }
+
+ ///
+ /// Gets or sets the defaults.
+ ///
+ ///
+ /// The defaults.
+ ///
+ public string[] Defaults { get; set; }
+
+ ///
+ /// Gets or sets the parameters.
+ ///
+ ///
+ /// The parameters.
+ ///
+ public List Parameters { get; set; }
+ }
+}
diff --git a/src/CodeMinion.Core/Models/Library/PyFuncArg.cs b/src/CodeMinion.Core/Models/Library/PyFuncArg.cs
new file mode 100644
index 0000000..53824c2
--- /dev/null
+++ b/src/CodeMinion.Core/Models/Library/PyFuncArg.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CodeMinion.Core.Models
+{
+ ///
+ /// Function argument for the method
+ ///
+ public class PyFuncArg
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ ///
+ /// The name.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the type of the data.
+ ///
+ ///
+ /// The type of the data.
+ ///
+ public string DataType { get; set; }
+
+ ///
+ /// Gets or sets the enums.
+ ///
+ ///
+ /// The enums.
+ ///
+ public string[] Enums { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether [have default].
+ ///
+ ///
+ /// true if [have default]; otherwise, false.
+ ///
+ public bool HaveDefault { get; set; }
+
+ ///
+ /// Gets or sets the default value.
+ ///
+ ///
+ /// The default value.
+ ///
+ public object DefaultValue { get; set; }
+
+ ///
+ /// Gets or sets the argument comment.
+ ///
+ ///
+ /// The argument comment.
+ ///
+ public string ArgComment { get; set; }
+ }
+}
diff --git a/src/CodeMinion.Core/Models/Library/PyFunction.cs b/src/CodeMinion.Core/Models/Library/PyFunction.cs
new file mode 100644
index 0000000..166fae0
--- /dev/null
+++ b/src/CodeMinion.Core/Models/Library/PyFunction.cs
@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CodeMinion.Core.Models
+{
+ ///
+ /// Information about Python function
+ ///
+ public class PyFunction
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PyFunction()
+ {
+ Parameters = new List();
+ }
+
+ ///
+ /// Gets or sets the name.
+ ///
+ ///
+ /// The name.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the arguments.
+ ///
+ ///
+ /// The arguments.
+ ///
+ public string[] Args { get; set; }
+
+ ///
+ /// Gets or sets the defaults.
+ ///
+ ///
+ /// The defaults.
+ ///
+ public string[] Defaults { get; set; }
+
+ ///
+ /// Gets or sets the type of the return.
+ ///
+ ///
+ /// The type of the return.
+ ///
+ public string ReturnType { get; set; }
+
+ ///
+ /// Gets or sets the return argument.
+ ///
+ ///
+ /// The return argument.
+ ///
+ public string ReturnArg { get; set; }
+
+ ///
+ /// Gets or sets the document string.
+ ///
+ ///
+ /// The document string.
+ ///
+ public string DocStr { get; set; }
+
+ public bool Deprecated { get; set; }
+
+ ///
+ /// Gets or sets the parameters.
+ ///
+ ///
+ /// The parameters.
+ ///
+ public List Parameters { get; set; }
+ }
+}
diff --git a/src/CodeMinion.Core/Models/Library/PyLibrary.cs b/src/CodeMinion.Core/Models/Library/PyLibrary.cs
new file mode 100644
index 0000000..93ae449
--- /dev/null
+++ b/src/CodeMinion.Core/Models/Library/PyLibrary.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CodeMinion.Core.Models
+{
+ ///
+ /// Instance of the python libray with modules and function
+ ///
+ public class PyLibrary
+ {
+ ///
+ /// Gets or sets the modules.
+ ///
+ ///
+ /// The modules.
+ ///
+ public List Modules { get; set; }
+
+ ///
+ /// Loads the json.
+ ///
+ /// The json.
+ ///
+ public static PyLibrary LoadJson(string json)
+ {
+ PyLibrary lib = new PyLibrary();
+ lib.Modules = Newtonsoft.Json.JsonConvert.DeserializeObject>(json);
+ //lib.Modules.ForEach(x => { x.InferArg(); });
+ return lib;
+ }
+ }
+}
diff --git a/src/CodeMinion.Core/Models/Library/PyModule.cs b/src/CodeMinion.Core/Models/Library/PyModule.cs
new file mode 100644
index 0000000..4bb82e8
--- /dev/null
+++ b/src/CodeMinion.Core/Models/Library/PyModule.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Linq;
+
+namespace CodeMinion.Core.Models
+{
+ ///
+ /// Python module information
+ ///
+ public class PyModule
+ {
+ ///
+ /// Gets or sets the name.
+ ///
+ ///
+ /// The name.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the classes.
+ ///
+ ///
+ /// The classes.
+ ///
+ public PyClass[] Classes { get; set; }
+
+ ///
+ /// Gets or sets the functions.
+ ///
+ ///
+ /// The functions.
+ ///
+ public PyFunction[] Functions { get; set; }
+
+ ///
+ /// Gets or sets the document string.
+ ///
+ ///
+ /// The document string.
+ ///
+ public string DocStr { get; set; }
+
+ ///
+ /// Infers the argument.
+ ///
+ public void InferArg()
+ {
+ for (int i = 0; i < Functions.Length; i++)
+ {
+ var func = Functions[i];
+ if (func.Args == null)
+ continue;
+ GetArgs(func);
+
+ }
+
+ foreach (var item in Classes)
+ {
+ for (int i = 0; i < item.Functions.Length; i++)
+ {
+ var func = Functions[i];
+ if (func.Args == null)
+ continue;
+
+ GetArgs(func);
+ }
+
+ if (item.Args == null)
+ continue;
+
+ GetArgs(item);
+ }
+ }
+
+ private static void GetArgs(PyFunction func)
+ {
+ for (int j = func.Args.Length - 1; j >= 0; j--)
+ {
+ if (func.Args[j] == "self")
+ continue;
+
+ PyFuncArg parameter = new PyFuncArg()
+ {
+ Name = func.Args[j]
+ };
+
+ if (func.Defaults != null)
+ {
+ if (func.Defaults.Length > j)
+ {
+ parameter.HaveDefault = true;
+ parameter.DefaultValue = func.Defaults[j].Trim().Replace("'", "");
+ parameter.DefaultValue = parameter.DefaultValue.ToString() == "None" ? "null" : parameter.DefaultValue;
+ }
+ }
+
+ func.Parameters.Add(parameter);
+ }
+ }
+
+ private static void GetArgs(PyClass cls)
+ {
+ for (int j = cls.Args.Length - 1; j >= 0; j--)
+ {
+ if (cls.Args[j] == "self")
+ continue;
+
+ PyFuncArg parameter = new PyFuncArg()
+ {
+ Name = cls.Args[j]
+ };
+
+ if (cls.Defaults != null)
+ {
+ if (cls.Defaults.Length > j)
+ {
+ parameter.HaveDefault = true;
+ parameter.DefaultValue = cls.Defaults[j].Trim().Replace("'", "");
+ parameter.DefaultValue = parameter.DefaultValue.ToString() == "None" ? "null" : parameter.DefaultValue;
+ }
+ }
+
+ cls.Parameters.Add(parameter);
+ }
+
+ }
+ }
+}
diff --git a/src/CodeMinion.Core/Models/Property.cs b/src/CodeMinion.Core/Models/Property.cs
new file mode 100644
index 0000000..9848016
--- /dev/null
+++ b/src/CodeMinion.Core/Models/Property.cs
@@ -0,0 +1,28 @@
+namespace CodeMinion.Core.Models
+{
+ public class Property : Declaration
+ {
+ public bool HasSetter { get; set; } = true;
+
+ // shortcut for the type of the first return value.
+ // For a property that returns a tuple use Returns instead
+ public string Type
+ {
+ get
+ {
+ if (Returns.Count == 0)
+ return null;
+ return Returns[0].Type;
+ }
+ set
+ {
+ if (Returns.Count == 0)
+ Returns.Add(new Argument(){Type = value});
+ Returns[0].Type=value;
+ }
+ }
+
+ public string DefaultValue { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/src/CodeMinion.Core/Models/StaticApi.cs b/src/CodeMinion.Core/Models/StaticApi.cs
new file mode 100644
index 0000000..9649b94
--- /dev/null
+++ b/src/CodeMinion.Core/Models/StaticApi.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using CodeMinion.Core.Helpers;
+
+namespace CodeMinion.Core.Models
+{
+ public class Api
+ {
+ ///
+ /// API declarations
+ ///
+ public List Declarations { get; set; } = new List();
+
+ ///
+ /// Target directory for the generated files
+ ///
+ public string OutputPath { get; set; }
+
+ ///
+ /// Additional name of a partial API file (required for splitting the API into multiple partial class files)
+ ///
+ public string PartialName { get; set; }
+
+ public string SubDir { get; set; }
+
+ }
+
+ ///
+ /// Represents a static API class that should be generated
+ ///
+ public class StaticApi : Api
+ {
+ ///
+ /// Static name is the name of a static class that forwards to a singleton instance of the API implementation
+ ///
+ public string StaticName { get; set; } = "torch";
+
+ ///
+ /// The static class forwards to this Singleton instance which is the API implementation
+ ///
+ public string ImplName { get; set; } = "PyTorch";
+
+ ///
+ /// The python module this API represents
+ ///
+ public string PythonModule { get; set; } = "torch";
+
+
+ ///
+ /// These are generated into the constructor of the API implementation object
+ ///
+ public List> InitializationGenerators { get; set; } = new List>();
+
+ }
+}
diff --git a/src/CodeMinion.Core/Models/TestCase.cs b/src/CodeMinion.Core/Models/TestCase.cs
new file mode 100644
index 0000000..d0a25c5
--- /dev/null
+++ b/src/CodeMinion.Core/Models/TestCase.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CodeMinion.Core.Models
+{
+ public class TestCase
+ {
+ ///
+ /// Name of the test function, if Null the test cases are numbered through
+ ///
+ public string Name { get; set; }
+
+ public List TestParts { get; set; } = new List();
+
+ }
+
+ public class TestPart { }
+
+ public class Comment : TestPart
+ {
+ public string Text { get; set; }
+ }
+ public class ExampleCode : TestPart
+ {
+ public string Text { get; set; }
+ public List Lines = new List();
+ }
+
+ public class CodeLine
+ {
+ public string Type { get; set; }
+ public List Text { get; set; }= new List();
+ }
+
+}
diff --git a/src/CodeMinion.Core/Models/TestFile.cs b/src/CodeMinion.Core/Models/TestFile.cs
new file mode 100644
index 0000000..bea72e8
--- /dev/null
+++ b/src/CodeMinion.Core/Models/TestFile.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CodeMinion.Core.Models
+{
+ public class TestFile
+ {
+ ///
+ /// Name of the test file without extension
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// The tests in that test file
+ ///
+ public List TestCases { get; set; } = new List();
+
+ public string SubDir { get; set; }
+ }
+}
diff --git a/src/CodeMinion.DocsParser/CodeMinion.Parser.csproj b/src/CodeMinion.DocsParser/CodeMinion.Parser.csproj
new file mode 100644
index 0000000..1f02fa4
--- /dev/null
+++ b/src/CodeMinion.DocsParser/CodeMinion.Parser.csproj
@@ -0,0 +1,11 @@
+
+
+
+ netstandard2.0
+
+
+
+
+
+
+
diff --git a/src/CodeMinion.DocsParser/DocumentExtensions.cs b/src/CodeMinion.DocsParser/DocumentExtensions.cs
new file mode 100644
index 0000000..35bd37b
--- /dev/null
+++ b/src/CodeMinion.DocsParser/DocumentExtensions.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HtmlAgilityPack;
+
+namespace CodeMinion.Parser
+{
+ public static class HtmlNodeExtensions
+ {
+ public static IEnumerable DescendantsOfClass(this HtmlNode self, string tag, string @class)
+ {
+ return self.Descendants(tag).Where(x => x.Attributes["class"]?.Value == @class);
+ }
+ }
+}
diff --git a/src/CodeMinion.DocsParser/HtmlDoc.cs b/src/CodeMinion.DocsParser/HtmlDoc.cs
new file mode 100644
index 0000000..6d13f73
--- /dev/null
+++ b/src/CodeMinion.DocsParser/HtmlDoc.cs
@@ -0,0 +1,12 @@
+using HtmlAgilityPack;
+
+namespace CodeMinion.Parser
+{
+ public class HtmlDoc
+ {
+ public string Filename { get; set; }
+ //public string Url { get; set; }
+ public string Text { get; set; }
+ public HtmlDocument Doc { get; set; }
+ }
+}
diff --git a/src/CodeMinion.DocsParser/HtmlDocuParser.cs b/src/CodeMinion.DocsParser/HtmlDocuParser.cs
new file mode 100644
index 0000000..2c1963d
--- /dev/null
+++ b/src/CodeMinion.DocsParser/HtmlDocuParser.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace CodeMinion.DocsParser
+{
+ public class HtmlDocuParser
+ {
+ }
+}
diff --git a/src/CodeMinion.DocsParser/RegexExtensions.cs b/src/CodeMinion.DocsParser/RegexExtensions.cs
new file mode 100644
index 0000000..7d63385
--- /dev/null
+++ b/src/CodeMinion.DocsParser/RegexExtensions.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace CodeMinion
+{
+ public static class RegexExtensions
+ {
+ ///
+ /// Returns the first explicit group or null if no match
+ ///
+ /// For example: if the regex is "ab(cd)ef" it will return cd
+ /// if the regex is "ab(cd(ef))" it will return cdef
+ ///
+ ///
+ ///
+ public static string FirstGroupOrNull(this Match self)
+ {
+ if (!self.Success || self.Groups.Count < 2)
+ return null;
+ return self.Groups[1].Value;
+ }
+ }
+}
diff --git a/src/Examples/CustomInstallLocationExample/CustomInstallLocationExample.csproj b/src/Examples/CustomInstallLocationExample/CustomInstallLocationExample.csproj
new file mode 100644
index 0000000..b4c3e88
--- /dev/null
+++ b/src/Examples/CustomInstallLocationExample/CustomInstallLocationExample.csproj
@@ -0,0 +1,23 @@
+
+
+
+ Exe
+ netcoreapp3.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Examples/CustomInstallLocationExample/Program.cs b/src/Examples/CustomInstallLocationExample/Program.cs
new file mode 100644
index 0000000..8deff26
--- /dev/null
+++ b/src/Examples/CustomInstallLocationExample/Program.cs
@@ -0,0 +1,48 @@
+using System;
+using System.IO;
+using Numpy;
+
+namespace CustomInstallLocationExample
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ // ================================================
+ // This example demonstrates how to install Python and Numpy from the assembly's resources
+ // (build action 'Embedded resource') into a custom location (here the local execution directory ".")
+ // and then use Numpy.Bare with that installation.
+ // ================================================
+
+ // set the installation source to be the embedded python zip from our resources
+ Python.Deployment.Installer.Source = new Python.Deployment.Installer.EmbeddedResourceInstallationSource()
+ {
+ Assembly = typeof(Program).Assembly,
+ ResourceName = "python-3.7.3-embed-amd64.zip",
+ };
+
+ // install in local directory. if you don't set it will install in local app data of your user account
+ Python.Deployment.Installer.InstallPath = Path.GetFullPath(".");
+
+ // see what the installer is doing
+ Python.Deployment.Installer.LogMessage += Console.WriteLine;
+
+ // install from the given source
+ Python.Deployment.Installer.SetupPython(force: false).Wait();
+
+ Python.Deployment.Installer.InstallWheel(typeof(Program).Assembly,
+ "numpy-1.16.3-cp37-cp37m-win_amd64.whl").Wait();
+
+ // if the installation is local, you don't even need to set the path
+ //Environment.SetEnvironmentVariable("PATH", Path.GetFullPath(@"./python-3.7.3-embed-amd64"), EnvironmentVariableTarget.Process);
+
+ // Now use Numpy.Bare
+ var a = np.arange(10);
+ Console.WriteLine("a: "+ a.repr);
+ var b = np.arange(10)["::-1"];
+ Console.WriteLine("b: " + b.repr);
+ var a_x_b = np.matmul(a, b);
+ Console.WriteLine("a x b: " + a_x_b.repr);
+ }
+ }
+}
diff --git a/src/Numpy/Resources/numpy-1.16.3-cp37-cp37m-win_amd64.whl b/src/Examples/CustomInstallLocationExample/numpy-1.16.3-cp37-cp37m-win_amd64.whl
similarity index 100%
rename from src/Numpy/Resources/numpy-1.16.3-cp37-cp37m-win_amd64.whl
rename to src/Examples/CustomInstallLocationExample/numpy-1.16.3-cp37-cp37m-win_amd64.whl
diff --git a/src/Examples/CustomInstallLocationExample/python-3.7.3-embed-amd64.zip b/src/Examples/CustomInstallLocationExample/python-3.7.3-embed-amd64.zip
new file mode 100644
index 0000000..597fa58
Binary files /dev/null and b/src/Examples/CustomInstallLocationExample/python-3.7.3-embed-amd64.zip differ
diff --git a/src/Examples/MatmulExample/MatmulExample.csproj b/src/Examples/MatmulExample/MatmulExample.csproj
index 679266a..0e842bf 100644
--- a/src/Examples/MatmulExample/MatmulExample.csproj
+++ b/src/Examples/MatmulExample/MatmulExample.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/src/Examples/MatmulExample/Program.cs b/src/Examples/MatmulExample/Program.cs
index b4c5561..202d92f 100644
--- a/src/Examples/MatmulExample/Program.cs
+++ b/src/Examples/MatmulExample/Program.cs
@@ -10,40 +10,40 @@ class Program
{
static void Main(string[] args)
{
-Console.WriteLine("Efficient matrix multiplication with NumPy:");
-// before starting the measurement, let us call numpy once to get the setup checks done.
-var stopwatch = Stopwatch.StartNew();
-np.arange(1);
+ Console.WriteLine("Efficient matrix multiplication with NumPy:");
+ // before starting the measurement, let us call numpy once to get the setup checks done.
+ np.arange(1);
+ var stopwatch = Stopwatch.StartNew();
-var a1 = np.arange(60000).reshape(300, 200);
-var a2 = np.arange(80000).reshape(200, 400);
+ var a1 = np.arange(60000).reshape(300, 200);
+ var a2 = np.arange(80000).reshape(200, 400);
-var result = np.matmul(a1, a2);
-stopwatch.Stop();
+ var result = np.matmul(a1, a2);
+ stopwatch.Stop();
-Console.WriteLine($"execution time with NumPy: {stopwatch.Elapsed.TotalMilliseconds}ms\n");
-Console.WriteLine("Result:\n" + result.repr);
+ Console.WriteLine($"execution time with NumPy: {stopwatch.Elapsed.TotalMilliseconds}ms\n");
+ Console.WriteLine("Result:\n" + result.repr);
-Console.WriteLine("executing on bg thread");
+ Console.WriteLine("executing on bg thread");
-var a = np.arange(1000);
-var b = np.arange(1000);
+ var a = np.arange(1000);
+ var b = np.arange(1000);
-// https://github.com/pythonnet/pythonnet/issues/109
-PythonEngine.BeginAllowThreads();
+ // https://github.com/pythonnet/pythonnet/issues/109
+ PythonEngine.BeginAllowThreads();
-Task.Run(() =>
-{
- using (Py.GIL())
- {
- np.matmul(a, b);
- Console.WriteLine("matmul on bg thread is done");
- }
-}).Wait();
-Console.WriteLine("Press key");
+ Task.Run(() =>
+ {
+ using (Py.GIL())
+ {
+ np.matmul(a, b);
+ Console.WriteLine("matmul on bg thread is done");
+ }
+ }).Wait();
+ Console.WriteLine("Press key");
-Console.ReadKey();
+ Console.ReadKey();
}
}
}
diff --git a/src/Examples/NetCoreTest/NetCoreTest.csproj b/src/Examples/NetCoreTest/NetCoreTest.csproj
new file mode 100644
index 0000000..dafc95d
--- /dev/null
+++ b/src/Examples/NetCoreTest/NetCoreTest.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.2
+
+
+
+
+
+
+
diff --git a/src/Examples/NetCoreTest/Program.cs b/src/Examples/NetCoreTest/Program.cs
new file mode 100644
index 0000000..1b55a03
--- /dev/null
+++ b/src/Examples/NetCoreTest/Program.cs
@@ -0,0 +1,18 @@
+using System;
+using Numpy;
+
+namespace NetCoreTest
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ var m = np.array(new int[] { 1, 2, 3, 4 }) * 2;
+ Console.WriteLine(m.repr);
+
+ Console.WriteLine("");
+ Console.WriteLine("Press any key to exit..");
+ Console.ReadKey();
+ }
+ }
+}
diff --git a/src/Examples/NeuralNetworkExample/NeuralNetworkExample.csproj b/src/Examples/NeuralNetworkExample/NeuralNetworkExample.csproj
new file mode 100644
index 0000000..48497fd
--- /dev/null
+++ b/src/Examples/NeuralNetworkExample/NeuralNetworkExample.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ netcoreapp2.2
+
+
+
+
+
+
+
diff --git a/src/Examples/NeuralNetworkExample/Program.cs b/src/Examples/NeuralNetworkExample/Program.cs
new file mode 100644
index 0000000..a07e4f8
--- /dev/null
+++ b/src/Examples/NeuralNetworkExample/Program.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Diagnostics;
+using Numpy;
+
+namespace NeuralNetworkExample
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Console.WriteLine("Fitting random data with a two layer Neural Network ...");
+ // N is batch size; D_in is input dimension;
+ // H is hidden dimension; D_out is output dimension.
+ var (N, D_in, H, D_out) = (64, 1000, 100, 10);
+
+ // Create random input and output data
+ Console.WriteLine("\tcreating random data");
+ var x = np.random.randn(N, D_in);
+ var y = np.random.randn(N, D_out);
+
+ Console.WriteLine("\tlearning");
+ var stopwatch = Stopwatch.StartNew();
+ // Randomly initialize weights
+ var w1 = np.random.randn(D_in, H);
+ var w2 = np.random.randn(H, D_out);
+
+ var learning_rate = 1.0e-6;
+ double loss=double.MaxValue;
+ for (int t = 0; t < 500; t++)
+ {
+ // Forward pass: compute predicted y
+ var h = x.dot(w1);
+ var h_relu = np.maximum(h, (NDarray)0);
+ var y_pred = h_relu.dot(w2);
+
+ // Compute and print loss
+ loss = (double)(np.square(y_pred - y).sum());
+ if (t%20==0)
+ Console.WriteLine($"\tstep: {t} loss: {loss}");
+
+ // Backprop to compute gradients of w1 and w2 with respect to loss
+ var grad_y_pred = 2.0 * (y_pred - y);
+ var grad_w2 = h_relu.T.dot(grad_y_pred);
+ var grad_h_relu = grad_y_pred.dot(w2.T);
+ var grad_h = grad_h_relu.copy();
+ grad_h[h < 0] = (NDarray)0;
+ var grad_w1 = x.T.dot(grad_h);
+
+ // Update weights
+ w1.isub( learning_rate * grad_w1); // inplace substraction is faster than -=
+ w2.isub( learning_rate * grad_w2);
+ }
+ stopwatch.Stop();
+ Console.WriteLine($"\tstep: 500, final loss: {loss}, elapsed time: {stopwatch.Elapsed.TotalSeconds:F3} seconds\n");
+ Console.WriteLine("Hit any key to exit.");
+ Console.ReadKey();
+ }
+ }
+}
diff --git a/src/Examples/NeuralNetworkExample/numpy_nn.py b/src/Examples/NeuralNetworkExample/numpy_nn.py
new file mode 100644
index 0000000..cd39c56
--- /dev/null
+++ b/src/Examples/NeuralNetworkExample/numpy_nn.py
@@ -0,0 +1,35 @@
+# N is batch size; D_in is input dimension;
+# H is hidden dimension; D_out is output dimension.
+N, D_in, H, D_out = 64, 1000, 100, 10
+
+# Create random input and output data
+x = np.random.randn(N, D_in)
+y = np.random.randn(N, D_out)
+
+# Randomly initialize weights
+w1 = np.random.randn(D_in, H)
+w2 = np.random.randn(H, D_out)
+
+learning_rate = 1e-6
+for t in range(500):
+
+ # Forward pass: compute predicted y
+ h = x.dot(w1)
+ h_relu = np.maximum(h, 0)
+ y_pred = h_relu.dot(w2)
+
+ # Compute and print loss
+ loss = np.square(y_pred - y).sum()
+ print(t, loss)
+
+ # Backprop to compute gradients of w1 and w2 with respect to loss
+ grad_y_pred = 2.0 * (y_pred - y)
+ grad_w2 = h_relu.T.dot(grad_y_pred)
+ grad_h_relu = grad_y_pred.dot(w2.T)
+ grad_h = grad_h_relu.copy()
+ grad_h[h < 0] = 0
+ grad_w1 = x.T.dot(grad_h)
+
+ # Update weights
+ w1 -= learning_rate * grad_w1
+ w2 -= learning_rate * grad_w2
\ No newline at end of file
diff --git a/src/Examples/SlicingExample/Program.cs b/src/Examples/SlicingExample/Program.cs
new file mode 100644
index 0000000..ef5073e
--- /dev/null
+++ b/src/Examples/SlicingExample/Program.cs
@@ -0,0 +1,17 @@
+using System;
+using Numpy;
+
+namespace SlicingExample
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ var a = np.arange(20).reshape(4,5);
+ Console.WriteLine(a);
+ var b = a["2:4"];
+ Console.WriteLine("\n sliced with 2:4");
+ Console.WriteLine(b );
+ }
+ }
+}
diff --git a/src/Examples/SlicingExample/SlicingExample.csproj b/src/Examples/SlicingExample/SlicingExample.csproj
new file mode 100644
index 0000000..3520e25
--- /dev/null
+++ b/src/Examples/SlicingExample/SlicingExample.csproj
@@ -0,0 +1,12 @@
+
+
+
+ Exe
+ net5.0
+
+
+
+
+
+
+
diff --git a/src/Examples/WebApiExample/Controllers/ValuesController.cs b/src/Examples/WebApiExample/Controllers/ValuesController.cs
new file mode 100644
index 0000000..4424d58
--- /dev/null
+++ b/src/Examples/WebApiExample/Controllers/ValuesController.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Numpy;
+using Python.Runtime;
+
+namespace WebApiExample.Controllers
+{
+ [Route("api/[controller]")]
+ [ApiController]
+ public class ValuesController : ControllerBase
+ {
+ // GET api/values
+ [HttpGet]
+ public ActionResult Get()
+ {
+ using (Py.GIL()) {
+ var array = new float[2, 2] {{DateTime.Now.Minute, DateTime.Now.Second}, {DateTime.Now.Millisecond, (float)Math.PI}};
+ var ndArray = new NDarray(array);
+ //return ndArray.ToString();
+ return ndArray.repr;
+ }
+ }
+
+ // GET api/values/5
+ [HttpGet("{id}")]
+ public ActionResult Get(int id)
+ {
+ using (Py.GIL())
+ {
+ var array = new float[2, 2] { { DateTime.Now.Minute, DateTime.Now.Second }, { DateTime.Now.Millisecond, (float)Math.PI } };
+ var ndArray = new NDarray(array);
+ //return ndArray.ToString();
+ return ndArray.repr;
+ }
+ }
+
+ //// POST api/values
+ //[HttpPost]
+ //public void Post([FromBody] string value)
+ //{
+ //}
+
+ //// PUT api/values/5
+ //[HttpPut("{id}")]
+ //public void Put(int id, [FromBody] string value)
+ //{
+ //}
+
+ //// DELETE api/values/5
+ //[HttpDelete("{id}")]
+ //public void Delete(int id)
+ //{
+ //}
+ }
+}
diff --git a/src/Examples/WebApiExample/Program.cs b/src/Examples/WebApiExample/Program.cs
new file mode 100644
index 0000000..05a3a9c
--- /dev/null
+++ b/src/Examples/WebApiExample/Program.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using Numpy;
+
+namespace WebApiExample
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ // this call initializes numpy. it is necessary to do that before PythonEngine.BeginAllowThreads()
+ np.arange(1);
+ Python.Runtime.PythonEngine.BeginAllowThreads(); // <--- this is very important for a web server since all requests are on different threads
+ CreateWebHostBuilder(args).Build().Run();
+ }
+
+ public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
+ WebHost.CreateDefaultBuilder(args)
+ .UseStartup();
+ }
+}
diff --git a/src/Examples/WebApiExample/Startup.cs b/src/Examples/WebApiExample/Startup.cs
new file mode 100644
index 0000000..8cd981c
--- /dev/null
+++ b/src/Examples/WebApiExample/Startup.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+
+namespace WebApiExample
+{
+ public class Startup
+ {
+ public Startup(IConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+
+ public IConfiguration Configuration { get; }
+
+ // This method gets called by the runtime. Use this method to add services to the container.
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseMvc();
+ }
+ }
+}
diff --git a/src/Examples/WebApiExample/WebApiExample_netcore2.2.csproj b/src/Examples/WebApiExample/WebApiExample_netcore2.2.csproj
new file mode 100644
index 0000000..d777645
--- /dev/null
+++ b/src/Examples/WebApiExample/WebApiExample_netcore2.2.csproj
@@ -0,0 +1,21 @@
+
+
+
+ netcoreapp2.2
+ InProcess
+
+
+
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Examples/WebApiExample/appsettings.Development.json b/src/Examples/WebApiExample/appsettings.Development.json
new file mode 100644
index 0000000..a2880cb
--- /dev/null
+++ b/src/Examples/WebApiExample/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Debug",
+ "System": "Information",
+ "Microsoft": "Information"
+ }
+ }
+}
diff --git a/src/Examples/WebApiExample/appsettings.json b/src/Examples/WebApiExample/appsettings.json
new file mode 100644
index 0000000..7376aad
--- /dev/null
+++ b/src/Examples/WebApiExample/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/src/Examples/WebApiExample_netcore3.1/Controllers/ValuesController.cs b/src/Examples/WebApiExample_netcore3.1/Controllers/ValuesController.cs
new file mode 100644
index 0000000..4424d58
--- /dev/null
+++ b/src/Examples/WebApiExample_netcore3.1/Controllers/ValuesController.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Mvc;
+using Numpy;
+using Python.Runtime;
+
+namespace WebApiExample.Controllers
+{
+ [Route("api/[controller]")]
+ [ApiController]
+ public class ValuesController : ControllerBase
+ {
+ // GET api/values
+ [HttpGet]
+ public ActionResult Get()
+ {
+ using (Py.GIL()) {
+ var array = new float[2, 2] {{DateTime.Now.Minute, DateTime.Now.Second}, {DateTime.Now.Millisecond, (float)Math.PI}};
+ var ndArray = new NDarray(array);
+ //return ndArray.ToString();
+ return ndArray.repr;
+ }
+ }
+
+ // GET api/values/5
+ [HttpGet("{id}")]
+ public ActionResult Get(int id)
+ {
+ using (Py.GIL())
+ {
+ var array = new float[2, 2] { { DateTime.Now.Minute, DateTime.Now.Second }, { DateTime.Now.Millisecond, (float)Math.PI } };
+ var ndArray = new NDarray(array);
+ //return ndArray.ToString();
+ return ndArray.repr;
+ }
+ }
+
+ //// POST api/values
+ //[HttpPost]
+ //public void Post([FromBody] string value)
+ //{
+ //}
+
+ //// PUT api/values/5
+ //[HttpPut("{id}")]
+ //public void Put(int id, [FromBody] string value)
+ //{
+ //}
+
+ //// DELETE api/values/5
+ //[HttpDelete("{id}")]
+ //public void Delete(int id)
+ //{
+ //}
+ }
+}
diff --git a/src/Examples/WebApiExample_netcore3.1/Program.cs b/src/Examples/WebApiExample_netcore3.1/Program.cs
new file mode 100644
index 0000000..94645aa
--- /dev/null
+++ b/src/Examples/WebApiExample_netcore3.1/Program.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Numpy;
+using Python.Runtime;
+
+namespace WebApiExample_netcore3._1
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ // this call initializes numpy. it is necessary to do that before PythonEngine.BeginAllowThreads()
+ np.arange(1);
+ PythonEngine.BeginAllowThreads(); // <--- this is very important for a web server since all requests are on different threads
+
+ CreateHostBuilder(args).Build().Run();
+ }
+
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
+ }
+}
diff --git a/src/Examples/WebApiExample_netcore3.1/Startup.cs b/src/Examples/WebApiExample_netcore3.1/Startup.cs
new file mode 100644
index 0000000..3891c6a
--- /dev/null
+++ b/src/Examples/WebApiExample_netcore3.1/Startup.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace WebApiExample_netcore3._1
+{
+ public class Startup
+ {
+ public Startup(IConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+
+ public IConfiguration Configuration { get; }
+
+ // This method gets called by the runtime. Use this method to add services to the container.
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddControllers();
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseRouting();
+
+ app.UseAuthorization();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapControllers();
+ });
+ }
+ }
+}
diff --git a/src/Examples/WebApiExample_netcore3.1/WebApiExample_netcore3.1.csproj b/src/Examples/WebApiExample_netcore3.1/WebApiExample_netcore3.1.csproj
new file mode 100644
index 0000000..1d690d8
--- /dev/null
+++ b/src/Examples/WebApiExample_netcore3.1/WebApiExample_netcore3.1.csproj
@@ -0,0 +1,13 @@
+
+
+
+ netcoreapp3.1
+ WebApiExample_netcore3._1
+
+
+
+
+
+
+
+
diff --git a/src/Examples/WebApiExample_netcore3.1/appsettings.Development.json b/src/Examples/WebApiExample_netcore3.1/appsettings.Development.json
new file mode 100644
index 0000000..dba68eb
--- /dev/null
+++ b/src/Examples/WebApiExample_netcore3.1/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/src/Examples/WebApiExample_netcore3.1/appsettings.json b/src/Examples/WebApiExample_netcore3.1/appsettings.json
new file mode 100644
index 0000000..81ff877
--- /dev/null
+++ b/src/Examples/WebApiExample_netcore3.1/appsettings.json
@@ -0,0 +1,10 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/src/Numpy.Bare.Dotnet/Numpy.Bare.Dotnet.csproj b/src/Numpy.Bare.Dotnet/Numpy.Bare.Dotnet.csproj
new file mode 100644
index 0000000..3146206
--- /dev/null
+++ b/src/Numpy.Bare.Dotnet/Numpy.Bare.Dotnet.csproj
@@ -0,0 +1,218 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {8E1BD94E-6AE4-46D9-B0BA-6AC0515AF0D0}
+ Library
+ Properties
+ Numpy.Bare.Dotnet
+ Numpy.Bare.Dotnet
+ v4.5
+ 512
+ true
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\..\packages\pythonnet_py37_win.2.5.1\lib\net40\Python.Runtime.dll
+
+
+
+
+
+ ..\..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll
+
+
+
+
+
+
+
+
+
+
+ Manual\ctypes.module.cs
+
+
+ Manual\np.aliases.cs
+
+
+ Manual\np.array.cs
+
+
+ Manual\np.column_stack.cs
+
+
+ Manual\np.concatenate.cs
+
+
+ Manual\np.constants.cs
+
+
+ Manual\np.delete.cs
+
+
+ Manual\np.einsum.cs
+
+
+ Manual\np.insert.cs
+
+
+ Manual\np.linalg.norm.cs
+
+
+ Manual\np.linspace.cs
+
+
+ Manual\np.math.cs
+
+
+ Manual\np.meshgrid.cs
+
+
+ Manual\np.random.cs
+
+
+ Manual\np.resize.cs
+
+
+ Manual\np.save.cs
+
+
+ Models\Axis.cs
+
+
+ Models\Constants.cs
+
+
+ Models\Dtype.cs
+
+
+ Models\Flags.cs
+
+
+ Models\Matrix.cs
+
+
+ Models\MemMapMode.cs
+
+
+ Models\NDarray.aliases.cs
+
+
+ Models\NDarray.CastOperators.cs
+
+
+ Models\NDarray.cs
+
+
+ Models\NDarray.gen.cs
+
+
+ Models\NDarray.Operators.cs
+
+
+ Models\PythonObject.cs
+
+
+ Models\PythonObject.gen.cs
+
+
+ Models\Shape.cs
+
+
+ Models\Slice.cs
+
+
+ np.array_creation.gen.cs
+
+
+ np.array_manipulation.gen.cs
+
+
+ np.bitwise.gen.cs
+
+
+ np.datetime.gen.cs
+
+
+ np.dtype.gen.cs
+
+
+ np.dtype.routines.gen.cs
+
+
+ np.fft.gen.cs
+
+
+ np.financial.gen.cs
+
+
+ np.indexing.gen.cs
+
+
+ np.io.gen.cs
+
+
+ np.linalg.gen.cs
+
+
+ np.linalg_fft.gen.cs
+
+
+ np.logic.gen.cs
+
+
+ np.math.gen.cs
+
+
+ np.module.gen.cs
+
+
+ np.padding.gen.cs
+
+
+ np.random.gen.cs
+
+
+ np.set.gen.cs
+
+
+ np.sorting.gen.cs
+
+
+ np.staticstics.gen.cs
+
+
+ np.string.gen.cs
+
+
+ np.window.gen.cs
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Numpy.Bare.Dotnet/Numpy.Bare.Dotnet.nuspec b/src/Numpy.Bare.Dotnet/Numpy.Bare.Dotnet.nuspec
new file mode 100644
index 0000000..983b52d
--- /dev/null
+++ b/src/Numpy.Bare.Dotnet/Numpy.Bare.Dotnet.nuspec
@@ -0,0 +1,18 @@
+
+
+
+ Numpy.Bare.Dotnet
+ 3.7.1.14
+ Numpy.Bare.Dotnet
+ Meinrad Recheis (SciSharp)
+ Meinrad Recheis
+ https://github.com/SciSharp/Numpy.NET/blob/master/LICENSE
+ https://github.com/SciSharp/Numpy.NET
+ https://api.nuget.org/v3-flatcontainer/numpy.bare/3.7.1.14/icon
+ false
+ C# bindings for NumPy on Win64 - a fundamental library for scientific computing, machine learning and AI. Does require Python 3.7 with NumPy 1.16 installed!
+ This one is compiled against .NET Framework 4.0
+ Copyright 2019-2020 Meinrad Recheis (SciSharp)
+ Data science Machine Learning AI Scientific Computing NumPy Linear Algebra FFT SVD Matrix Python
+
+
\ No newline at end of file
diff --git a/src/Numpy.Bare.Dotnet/Properties/AssemblyInfo.cs b/src/Numpy.Bare.Dotnet/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..9cccc05
--- /dev/null
+++ b/src/Numpy.Bare.Dotnet/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Numpy.Bare.Dotnet")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Numpy.Bare.Dotnet")]
+[assembly: AssemblyCopyright("Copyright © 2020 Meinrad Recheis (SciSharp)")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("8e1bd94e-6ae4-46d9-b0ba-6ac0515af0d0")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("3.7.1.14")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/Numpy.Bare.Dotnet/packages.config b/src/Numpy.Bare.Dotnet/packages.config
new file mode 100644
index 0000000..f5b2dbc
--- /dev/null
+++ b/src/Numpy.Bare.Dotnet/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Numpy.Bare/Manual/NumPy.array.cs b/src/Numpy.Bare/Manual/NumPy.array.cs
deleted file mode 100644
index 159ce6c..0000000
--- a/src/Numpy.Bare/Manual/NumPy.array.cs
+++ /dev/null
@@ -1,147 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using Numpy;
-using Numpy.Models;
-using Python.Runtime;
-
-namespace Numpy
-{
- ///
- /// Manual type conversions
- ///
- public partial class NumPy
- {
-
- public NDarray array(NDarray @object, Dtype dtype = null, bool? copy = null, string order = null, bool? subok = null, int? ndmin = null)
- {
- var args = ToTuple(new object[]
- {
- @object,
- });
- var kwargs = new PyDict();
- if (dtype != null) kwargs["dtype"] = ToPython(dtype);
- if (copy != null) kwargs["copy"] = ToPython(copy);
- if (order != null) kwargs["order"] = ToPython(order);
- if (subok != null) kwargs["subok"] = ToPython(subok);
- if (ndmin != null) kwargs["ndmin"] = ToPython(ndmin);
- dynamic py = self.InvokeMethod("array", args, kwargs);
- return ToCsharp(py);
- }
-
- public NDarray array(T[] @object, Dtype dtype = null, bool? copy = null, string order = null, bool? subok = null, int? ndmin = null)
- {
- var type = @object.GetDtype();
- //if (dtype != null && !type.Equals( dtype))
- // throw new NotImplementedException("Type of the array is different from specified dtype. Data conversion is not supported (yet)");
- var ndarray = this.empty(new Shape(@object.Length), dtype: dtype??type, order:order); // todo: check out the other parameters
- long ptr = ndarray.PyObject.ctypes.data;
- switch ((object)@object)
- {
- case byte[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case short[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case int[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case long[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case float[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case double[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case bool[] a:
- var bytes = a.Select(x => (byte)(x ? 1 : 0)).ToArray();
- Marshal.Copy(bytes, 0, new IntPtr(ptr), a.Length);
- break;
- }
- return new NDarray(ndarray);
- }
-
- public NDarray array(T[,] @object, Dtype dtype = null, bool? copy = null, string order = null, bool? subok = null, int? ndmin = null)
- {
- var d1_array = @object.Cast().ToArray();
- var type = d1_array.GetDtype();
- //if (dtype != null && type != dtype)
- // throw new NotImplementedException("Type of the array is different from specified dtype. Data conversion is not supported (yet)");
- var ndarray = this.empty(new Shape(@object.GetLength(0), @object.GetLength(1)), dtype: dtype??type, order: order); // todo: check out the other parameters
- long ptr = ndarray.PyObject.ctypes.data;
- switch ((object)d1_array)
- {
- case byte[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case short[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case int[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case long[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case float[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case double[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case bool[] a:
- var bytes = a.Select(x => (byte) (x ? 1 : 0)).ToArray();
- Marshal.Copy(bytes, 0, new IntPtr(ptr), a.Length);
- break;
- }
- return new NDarray(ndarray);
- }
-
- public NDarray array(T[,,] @object, Dtype dtype = null, bool? copy = null, string order = null, bool? subok = null, int? ndmin = null)
- {
- var d1_array = @object.Cast().ToArray();
- var type = d1_array.GetDtype();
- //if (dtype != null && type != dtype)
- // throw new NotImplementedException("Type of the array is different from specified dtype. Data conversion is not supported (yet)");
- var ndarray = this.empty(new Shape(@object.GetLength(0), @object.GetLength(1), @object.GetLength(2)), dtype: dtype ?? type, order: order); // todo: check out the other parameters
- long ptr = ndarray.PyObject.ctypes.data;
- switch ((object)d1_array)
- {
- case byte[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case short[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case int[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case long[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case float[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case double[] a: Marshal.Copy(a, 0, new IntPtr(ptr), a.Length); break;
- case bool[] a:
- var bytes = a.Select(x => (byte)(x ? 1 : 0)).ToArray();
- Marshal.Copy(bytes, 0, new IntPtr(ptr), a.Length);
- break;
- }
- return new NDarray(ndarray);
- }
-
- public NDarray array(string[] obj, int? itemsize = null, bool? copy = null, bool? unicode = null, string order = null)
- {
- var args = ToTuple(obj);
- var kwargs = new PyDict();
- if (itemsize != null) kwargs["itemsize"] = ToPython(itemsize);
- if (copy != null) kwargs["copy"] = ToPython(copy);
- if (unicode != null) kwargs["unicode"] = ToPython(unicode);
- if (order != null) kwargs["order"] = ToPython(order);
- dynamic py = self.InvokeMethod("array", args, kwargs);
- return ToCsharp(py);
- }
-
- ///
- /// Create a 0d array from scalar
- ///
- ///
- ///
- ///
- public NDarray asarray(ValueType scalar, Dtype dtype = null)
- {
- var __self__ = self;
- var pyargs = ToTuple(new object[]
- {
- scalar,
- });
- var kwargs = new PyDict();
- if (dtype != null) kwargs["dtype"] = ToPython(dtype);
- dynamic py = __self__.InvokeMethod("asarray", pyargs, kwargs);
- return ToCsharp(py);
- }
-
- ///
- /// Convert an array of size 1 to its scalar equivalent.
- ///
- ///
- /// Scalar representation of a. The output data type is the same type
- /// returned by the input’s item method.
- ///
- public T asscalar(NDarray a) => self.InvokeMethod("asscalar", a.PyObject).As();
-
-
- }
-}
diff --git a/src/Numpy.Bare/Manual/NumPy.linalg.norm.cs b/src/Numpy.Bare/Manual/NumPy.linalg.norm.cs
deleted file mode 100644
index 75c0d7d..0000000
--- a/src/Numpy.Bare/Manual/NumPy.linalg.norm.cs
+++ /dev/null
@@ -1,108 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using Numpy;
-using Numpy.Models;
-using Python.Runtime;
-
-namespace Numpy
-{
- ///
- /// Manual type conversions
- ///
- public partial class NumPy
- {
-
- ///
- /// Matrix or vector norm.
- ///
- /// This function is able to return one of eight different matrix norms,
- /// or one of an infinite number of vector norms (described below), depending
- /// on the value of the ord parameter.
- ///
- /// Notes
- ///
- /// For values of ord <= 0, the result is, strictly speaking, not a
- /// mathematical ‘norm’, but it may still be useful for various numerical
- /// purposes.
- ///
- /// The following norms can be calculated:
- ///
- /// The Frobenius norm is given by [1]:
- ///
- /// The nuclear norm is the sum of the singular values.
- ///
- /// References
- ///
- ///
- /// Input array. If axis is None, x must be 1-D or 2-D.
- ///
- ///
- /// Order of the norm (see table under Notes). inf means numpy’s
- /// inf object.
- ///
- ///
- /// If axis is an integer, it specifies the axis of x along which to
- /// compute the vector norms. If axis is a 2-tuple, it specifies the
- /// axes that hold 2-D matrices, and the matrix norms of these matrices
- /// are computed. If axis is None then either a vector norm (when x
- /// is 1-D) or a matrix norm (when x is 2-D) is returned.
- ///
- ///
- /// If this is set to True, the axes which are normed over are left in the
- /// result as dimensions with size one. With this option the result will
- /// broadcast correctly against the original x.
- ///
- ///
- /// Norm of the matrix or vector(s).
- ///
- public NDarray norm(NDarray x, int? ord = null, int[] axis = null, bool? keepdims = null)
- {
- var pyargs = ToTuple(new object[] { x, });
- var kwargs = new PyDict();
- if (ord != null) kwargs["ord"] = ToPython(ord);
- if (axis != null) kwargs["axis"] = ToPython(axis);
- if (keepdims != null) kwargs["keepdims"] = ToPython(keepdims);
- var linalg = self.GetAttr("linalg");
- dynamic py = linalg.InvokeMethod("norm", pyargs, kwargs);
- return ToCsharp (py);
- }
-
- public float norm(NDarray x, int? ord = null)
- {
- var pyargs = ToTuple(new object[] { x, });
- var kwargs = new PyDict();
- if (ord != null) kwargs["ord"] = ToPython(ord);
- var linalg = self.GetAttr("linalg");
- dynamic py = linalg.InvokeMethod("norm", pyargs, kwargs);
-
- return ToCsharp(py);
- }
-
- public float norm(NDarray x, string ord)
- {
- var pyargs = ToTuple(new object[] { x, });
- var kwargs = new PyDict();
- if (ord != null) kwargs["ord"] = ToPython(ord);
- var linalg = self.GetAttr("linalg");
- dynamic py = linalg.InvokeMethod("norm", pyargs, kwargs);
- return ToCsharp(py);
- }
-
- public float norm(NDarray x, Constants ord)
- {
- if (ord!=Constants.inf && ord!=Constants.neg_inf)
- throw new ArgumentException("ord must be either inf or neg_inf");
-
- var pyargs = ToTuple(new object[] { x, });
- var kwargs = new PyDict();
- if (ord != null) kwargs["ord"] = ord==Constants.inf ? self.inf : -(self.inf);
- var linalg = self.GetAttr("linalg");
- dynamic py = linalg.InvokeMethod("norm", pyargs, kwargs);
- return ToCsharp(py);
- }
-
- }
-}
diff --git a/src/Numpy.Bare/Manual/NumPy.reshape.cs b/src/Numpy.Bare/Manual/NumPy.reshape.cs
deleted file mode 100644
index dc4a659..0000000
--- a/src/Numpy.Bare/Manual/NumPy.reshape.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using Numpy;
-using Numpy.Models;
-using Python.Runtime;
-
-namespace Numpy
-{
- ///
- /// Manual type conversions
- ///
- public static partial class np
- {
- ///
- /// Gives a new shape to an array without changing its data.
- ///
- /// Notes
- ///
- /// It is not always possible to change the shape of an array without
- /// copying the data. If you want an error to be raised when the data is copied,
- /// you should assign the new shape to the shape attribute of the array:
- ///
- /// The order keyword gives the index ordering both for fetching the values
- /// from a, and then placing the values into the output array.
- /// For example, let’s say you have an array:
- ///
- /// You can think of reshaping as first raveling the array (using the given
- /// index order), then inserting the elements from the raveled array into the
- /// new array using the same kind of index ordering as was used for the
- /// raveling.
- ///
- /// The array to reshape
- ///
- /// The new shape should be compatible with the original shape. If
- /// an integer, then the result will be a 1-D array of that length.
- /// One shape dimension can be -1. In this case, the value is
- /// inferred from the length of the array and remaining dimensions.
- ///
- ///
- /// This will be a new view object if possible; otherwise, it will
- /// be a copy. Note there is no guarantee of the memory layout (C- or
- /// Fortran- contiguous) of the returned array.
- ///
- public static NDarray reshape(NDarray a, params int[] newshape)
- {
- return NumPy.Instance.reshape(a, new Shape(newshape));
- }
- }
-}
diff --git a/src/Numpy.Bare/Manual/NumPy.resize.cs b/src/Numpy.Bare/Manual/NumPy.resize.cs
deleted file mode 100644
index 1a770eb..0000000
--- a/src/Numpy.Bare/Manual/NumPy.resize.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using Numpy;
-using Numpy.Models;
-using Python.Runtime;
-
-namespace Numpy
-{
- ///
- /// Manual type conversions
- ///
- public partial class NumPy
- {
-
- ///
- /// Return a new array with the specified shape.
- ///
- /// If the new array is larger than the original array, then the new
- /// array is filled with repeated copies of a. Note that this behavior
- /// is different from a.resize(new_shape) which fills with zeros instead
- /// of repeated copies of a.
- ///
- /// Notes
- ///
- /// Warning: This functionality does not consider axes separately,
- /// i.e. it does not apply interpolation/extrapolation.
- /// It fills the return array with the required number of elements, taken
- /// from a as they are laid out in memory, disregarding strides and axes.
- /// (This is in case the new shape is smaller. For larger, see above.)
- /// This functionality is therefore not suitable to resize images,
- /// or data where each axis represents a separate and distinct entity.
- ///
- ///
- /// Array to be resized.
- ///
- ///
- /// Shape of resized array.
- ///
- ///
- /// The new array is formed from the data in the old array, repeated
- /// if necessary to fill out the required number of elements. The
- /// data are repeated in the order that they are stored in memory.
- ///
- public NDarray resize(NDarray a, Shape new_shape)
- {
- var pyargs = ToTuple(new object[]
- {
- a,
- new_shape,
- });
- dynamic py = self.InvokeMethod("resize", pyargs);
- return ToCsharp(py);
- }
-
- }
-}
diff --git a/src/Numpy.Bare/Manual/np.aliases.cs b/src/Numpy.Bare/Manual/np.aliases.cs
deleted file mode 100644
index a039cab..0000000
--- a/src/Numpy.Bare/Manual/np.aliases.cs
+++ /dev/null
@@ -1,142 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Numpy.Models;
-
-namespace Numpy
-{
-
- public static partial class np
- {
-
- ///
- /// Calculate the absolute value element-wise.
- ///
- /// np.abs is a shorthand for this function.
- ///
- ///
- /// Input array.
- ///
- ///
- /// A location into which the result is stored. If provided, it must have
- /// a shape that the inputs broadcast to. If not provided or None,
- /// a freshly-allocated array is returned. A tuple (possible only as a
- /// keyword argument) must have length equal to the number of outputs.
- ///
- ///
- /// Values of True indicate to calculate the ufunc at that position, values
- /// of False indicate to leave the value in the output alone.
- ///
- ///
- /// An ndarray containing the absolute value of
- /// each element in x. For complex input, a + ib, the
- /// absolute value is .
- /// This is a scalar if x is a scalar.
- ///
- public static NDarray abs(NDarray x, NDarray @out = null, NDarray @where = null)
- => NumPy.Instance.absolute(x, @out, @where);
-
- ///
- /// Return the minimum of an array or minimum along an axis.
- ///
- /// Notes
- ///
- /// NaN values are propagated, that is if at least one item is NaN, the
- /// corresponding min value will be NaN as well. To ignore NaN values
- /// (MATLAB behavior), please use nanmin.
- ///
- /// Don’t use amin for element-wise comparison of 2 arrays; when
- /// a.shape[0] is 2, minimum(a[0], a[1]) is faster than
- /// amin(a, axis=0).
- ///
- ///
- /// Input data.
- ///
- ///
- /// Axis or axes along which to operate. By default, flattened input is
- /// used.
- ///
- /// If this is a tuple of ints, the minimum is selected over multiple axes,
- /// instead of a single axis or all the axes as before.
- ///
- ///
- /// Alternative output array in which to place the result. Must
- /// be of the same shape and buffer length as the expected output.
- /// See doc.ufuncs (Section “Output arguments”) for more details.
- ///
- ///
- /// If this is set to True, the axes which are reduced are left
- /// in the result as dimensions with size one. With this option,
- /// the result will broadcast correctly against the input array.
- ///
- /// If the default value is passed, then keepdims will not be
- /// passed through to the amin method of sub-classes of
- /// ndarray, however any non-default value will be. If the
- /// sub-class’ method does not implement keepdims any
- /// exceptions will be raised.
- ///
- ///
- /// The maximum value of an output element. Must be present to allow
- /// computation on empty slice. See reduce for details.
- ///
- ///
- /// Minimum of a. If axis is None, the result is a scalar value.
- /// If axis is given, the result is an array of dimension
- /// a.ndim - 1.
- ///
- public static NDarray min(NDarray a, int[] axis = null, NDarray @out = null, bool? keepdims = null, ValueType initial = null)
- => NumPy.Instance.amin(a, axis: axis, @out: @out, keepdims: keepdims, initial: initial);
-
- ///
- /// Return the maximum of an array or maximum along an axis.
- ///
- /// Notes
- ///
- /// NaN values are propagated, that is if at least one item is NaN, the
- /// corresponding max value will be NaN as well. To ignore NaN values
- /// (MATLAB behavior), please use nanmax.
- ///
- /// Don’t use amax for element-wise comparison of 2 arrays; when
- /// a.shape[0] is 2, maximum(a[0], a[1]) is faster than
- /// amax(a, axis=0).
- ///
- ///
- /// Input data.
- ///
- ///
- /// Axis or axes along which to operate. By default, flattened input is
- /// used.
- ///
- /// If this is a tuple of ints, the maximum is selected over multiple axes,
- /// instead of a single axis or all the axes as before.
- ///
- ///
- /// Alternative output array in which to place the result. Must
- /// be of the same shape and buffer length as the expected output.
- /// See doc.ufuncs (Section “Output arguments”) for more details.
- ///
- ///
- /// If this is set to True, the axes which are reduced are left
- /// in the result as dimensions with size one. With this option,
- /// the result will broadcast correctly against the input array.
- ///
- /// If the default value is passed, then keepdims will not be
- /// passed through to the amax method of sub-classes of
- /// ndarray, however any non-default value will be. If the
- /// sub-class’ method does not implement keepdims any
- /// exceptions will be raised.
- ///
- ///
- /// The minimum value of an output element. Must be present to allow
- /// computation on empty slice. See reduce for details.
- ///
- ///
- /// Maximum of a. If axis is None, the result is a scalar value.
- /// If axis is given, the result is an array of dimension
- /// a.ndim - 1.
- ///
- public static NDarray max(NDarray a, int[] axis = null, NDarray @out = null, bool? keepdims = null, ValueType initial = null)
- => NumPy.Instance.amax(a, axis: axis, @out: @out, keepdims: keepdims, initial: initial);
-
- }
-}
diff --git a/src/Numpy.Bare/Manual/np.array.cs b/src/Numpy.Bare/Manual/np.array.cs
deleted file mode 100644
index b76b8e8..0000000
--- a/src/Numpy.Bare/Manual/np.array.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Numpy
-{
-
- public static partial class np
- {
-
- ///
- /// Create an array.
- ///
- ///
- /// The array to initialize the ndarray with
- ///
- ///
- /// An array object satisfying the specified requirements.
- ///
- public static NDarray array(params T[] data)
- {
- return NumPy.Instance.array(data);
- }
-
- public static NDarray array(T[,,] data, Dtype dtype = null, bool? copy = null, string order = null, bool? subok = null, int? ndmin = null)
- {
- return NumPy.Instance.array(data, dtype, copy, order, subok, ndmin);
- }
-
- public static NDarray asarray(ValueType a, Dtype dtype = null)
- => NumPy.Instance.asarray(a, dtype: dtype);
-
- ///
- /// Convert an array of size 1 to its scalar equivalent.
- ///
- ///
- /// Scalar representation of a. The output data type is the same type
- /// returned by the input’s item method.
- ///
- public static T asscalar(NDarray a) => NumPy.Instance.asscalar(a);
-
- }
-}
diff --git a/src/Numpy.Bare/Manual/np.constants.cs b/src/Numpy.Bare/Manual/np.constants.cs
deleted file mode 100644
index 403dc7f..0000000
--- a/src/Numpy.Bare/Manual/np.constants.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Python.Runtime;
-
-namespace Numpy
-{
- public static partial class np
- {
- ///
- /// IEEE 754 floating point representation of (positive) infinity.
- ///
- public static float inf => NumPy.Instance.self.GetAttr("inf").As();
-
- ///
- /// IEEE 754 floating point representation of (positive) infinity.
- ///
- /// Use np.inf because Inf, Infinity, PINF and infty are aliases for inf.For more details, see inf.
- ///
- public static float Inf => NumPy.Instance.self.GetAttr("inf").As();
-
- ///
- /// IEEE 754 floating point representation of (positive) infinity.
- ///
- /// Use np.inf because Inf, Infinity, PINF and infty are aliases for inf.For more details, see inf.
- ///
- public static float Infinity => NumPy.Instance.self.GetAttr("inf").As();
-
- ///
- /// IEEE 754 floating point representation of (positive) infinity.
- ///
- /// Use np.inf because Inf, Infinity, PINF and infty are aliases for inf.For more details, see inf.
- ///
- public static float PINF => NumPy.Instance.self.GetAttr("inf").As();
-
- ///
- /// IEEE 754 floating point representation of (positive) infinity.
- ///
- /// Use np.inf because Inf, Infinity, PINF and infty are aliases for inf.For more details, see inf.
- ///
- public static float infty => NumPy.Instance.self.GetAttr("inf").As();
-
- ///
- /// IEEE 754 floating point representation of (positive) infinity.
- ///
- public static float NINF => NumPy.Instance.self.GetAttr("NINF").As();
-
- ///
- /// IEEE 754 floating point representation of Not a Number(NaN).
- ///
- public static float nan => NumPy.Instance.self.GetAttr("nan").As();
-
- ///
- /// IEEE 754 floating point representation of Not a Number(NaN).
- ///
- /// NaN and NAN are equivalent definitions of nan.Please use nan instead of NAN.
- ///
- public static float NaN => NumPy.Instance.self.GetAttr("nan").As();
-
- ///
- /// IEEE 754 floating point representation of Not a Number(NaN).
- ///
- /// NaN and NAN are equivalent definitions of nan.Please use nan instead of NAN.
- ///
- public static float NAN => NumPy.Instance.self.GetAttr("nan").As();
-
- ///
- /// IEEE 754 floating point representation of negative zero.
- ///
- public static float NZERO => NumPy.Instance.self.GetAttr("NZERO").As();
-
- ///
- /// IEEE 754 floating point representation of positive zero.
- ///
- public static float PZERO => NumPy.Instance.self.GetAttr("PZERO").As();
-
- ///
- /// Euler’s constant, base of natural logarithms, Napier’s constant.
- ///
- public static float e => NumPy.Instance.self.GetAttr("e").As();
-
- ///
- /// γ = 0.5772156649015328606065120900824024310421...
- /// https://en.wikipedia.org/wiki/Euler-Mascheroni_constant
- ///
- public static float euler_gamma => NumPy.Instance.self.GetAttr("e").As();
-
- ///
- /// A convenient alias for None, useful for indexing arrays.
- ///
- public static object newaxis => NumPy.Instance.self.GetAttr("newaxis");
-
- ///
- /// pi = 3.1415926535897932384626433...
- ///
- public static float pi => NumPy.Instance.self.GetAttr("pi").As();
-
- }
-}
diff --git a/src/Numpy.Bare/Manual/np.empty.cs b/src/Numpy.Bare/Manual/np.empty.cs
deleted file mode 100644
index efcb9e9..0000000
--- a/src/Numpy.Bare/Manual/np.empty.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Numpy.Models;
-
-namespace Numpy
-{
-
- public static partial class np
- {
-
- ///
- /// Create an array.
- ///
- ///
- /// The shape of the empty ndarray
- ///
- ///
- /// An array object satisfying the specified requirements.
- ///
- public static NDarray empty(params int[] shape)
- {
- return NumPy.Instance.empty(new Shape(shape));
- }
- }
-}
diff --git a/src/Numpy.Bare/Manual/np.linalg.norm.cs b/src/Numpy.Bare/Manual/np.linalg.norm.cs
deleted file mode 100644
index 77b43ea..0000000
--- a/src/Numpy.Bare/Manual/np.linalg.norm.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Numpy.Models;
-
-namespace Numpy
-{
-
- public static partial class np
- {
- public static partial class linalg
- {
- ///
- /// Matrix or vector norm.
- ///
- /// This function is able to return one of eight different matrix norms,
- /// or one of an infinite number of vector norms (described below), depending
- /// on the value of the ord parameter.
- ///
- /// Notes
- ///
- /// For values of ord <= 0, the result is, strictly speaking, not a
- /// mathematical ‘norm’, but it may still be useful for various numerical
- /// purposes.
- ///
- /// The following norms can be calculated:
- ///
- /// The Frobenius norm is given by [1]:
- ///
- /// The nuclear norm is the sum of the singular values.
- ///
- /// References
- ///
- ///
- /// Input array. If axis is None, x must be 1-D or 2-D.
- ///
- ///
- /// Order of the norm (see table under Notes). inf means numpy’s
- /// inf object.
- ///
- ///
- /// If axis is an integer, it specifies the axis of x along which to
- /// compute the vector norms. If axis is a 2-tuple, it specifies the
- /// axes that hold 2-D matrices, and the matrix norms of these matrices
- /// are computed. If axis is None then either a vector norm (when x
- /// is 1-D) or a matrix norm (when x is 2-D) is returned.
- ///
- ///
- /// If this is set to True, the axes which are normed over are left in the
- /// result as dimensions with size one. With this option the result will
- /// broadcast correctly against the original x.
- ///
- ///
- /// Norm of the matrix or vector(s).
- ///
- public static NDarray norm(NDarray x, int? ord, int[] axis, bool? keepdims = null)
- => NumPy.Instance.norm(x, ord, axis, keepdims);
-
- public static float norm(NDarray x, int? ord=null)
- => NumPy.Instance.norm(x, ord);
-
- public static float norm(NDarray x, string ord)
- => NumPy.Instance.norm(x, ord);
-
- public static float norm(NDarray x, Constants ord)
- => NumPy.Instance.norm(x, ord);
- }
- }
-}
diff --git a/src/Numpy.Bare/Manual/np.ones.cs b/src/Numpy.Bare/Manual/np.ones.cs
deleted file mode 100644
index 6072b2c..0000000
--- a/src/Numpy.Bare/Manual/np.ones.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Numpy.Models;
-
-namespace Numpy
-{
-
- public static partial class np
- {
-
- ///
- /// Return a new array of given shape and type, filled with ones.
- ///
- ///
- /// Shape of the new array, e.g., (2, 3) or 2.
- ///
- ///
- /// The desired data-type for the array, e.g., numpy.int8. Default is
- /// numpy.float64.
- ///
- ///
- /// Whether to store multi-dimensional data in row-major
- /// (C-style) or column-major (Fortran-style) order in
- /// memory.
- ///
- ///
- /// Array of ones with the given shape, dtype, and order.
- ///
- public static NDarray ones(params int[] shape)
- {
- return NumPy.Instance.ones(new Shape(shape));
- }
- }
-}
diff --git a/src/Numpy.Bare/Manual/np.zeros.cs b/src/Numpy.Bare/Manual/np.zeros.cs
deleted file mode 100644
index cd359b2..0000000
--- a/src/Numpy.Bare/Manual/np.zeros.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Numpy.Models;
-
-namespace Numpy
-{
-
- public static partial class np
- {
-
- ///
- /// Return a new array of given shape and type, filled with zeros.
- ///
- ///
- /// Shape of the new array, e.g., (2, 3) or 2.
- ///
- ///
- /// The desired data-type for the array, e.g., numpy.int8. Default is
- /// numpy.float64.
- ///
- ///
- /// Whether to store multi-dimensional data in row-major
- /// (C-style) or column-major (Fortran-style) order in
- /// memory.
- ///
- ///
- /// Array of zeros with the given shape, dtype, and order.
- ///
- public static NDarray zeros(params int[] shape)
- => NumPy.Instance.zeros(new Shape(shape));
- }
-}
diff --git a/src/Numpy.Bare/Models/Constants.cs b/src/Numpy.Bare/Models/Constants.cs
deleted file mode 100644
index 6e325ec..0000000
--- a/src/Numpy.Bare/Models/Constants.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Numpy.Models
-{
- public enum Constants
- {
- inf, neg_inf
- }
-}
diff --git a/src/Numpy.Bare/Models/Dtype.cs b/src/Numpy.Bare/Models/Dtype.cs
deleted file mode 100644
index 5d38921..0000000
--- a/src/Numpy.Bare/Models/Dtype.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Python.Runtime;
-
-namespace Numpy
-{
-
- public partial class Dtype : PythonObject
- {
- public Dtype(PyObject pyobj) : base(pyobj)
- {
- }
-
- public Dtype(Dtype t) : base((PyObject)t.PyObject)
- {
- }
-
- }
-
-
- public static class DtypeExtensions
- {
- public static Dtype GetDtype(this object obj)
- {
- switch (obj)
- {
- case bool o: return np.bool8;
- case sbyte o: return np.int8;
- case byte o: return np.uint8;
- case short o: return np.int16;
- case ushort o: return np.uint16;
- case int o: return np.int32;
- case uint o: return np.uint32;
- case long o: return np.int64;
- case ulong o: return np.uint64;
- case float o: return np.float32;
- case double o: return np.float64;
- case bool[] o: return np.bool8;
- case byte[] o: return np.@byte;
- case short[] o: return np.int16;
- case int[] o: return np.int32;
- case long[] o: return np.int64;
- case float[] o: return np.float32;
- case double[] o: return np.float64;
- case bool[,] o: return np.bool8;
- case byte[,] o: return np.uint8;
- case short[,] o: return np.int16;
- case int[,] o: return np.int32;
- case long[,] o: return np.int64;
- case float[,] o: return np.float32;
- case double[,] o: return np.float64;
- case bool[,,] o: return np.bool8;
- case byte[,,] o: return np.uint8;
- case short[,,] o: return np.int16;
- case int[,,] o: return np.int32;
- case long[,,] o: return np.int64;
- case float[,,] o: return np.float32;
- case double[,,] o: return np.float64;
- default: throw new ArgumentException("Can not convert type of given object to dtype: " + obj.GetType());
- }
- }
-
- //public static dtype ToDtype(this Type t)
- //{
- // if (t == typeof(byte)) return dtype.UInt8;
- // if (t == typeof(short)) return dtype.Int16;
- // if (t == typeof(int)) return dtype.Int32;
- // if (t == typeof(long)) return dtype.Int64;
- // if (t == typeof(float)) return dtype.Float32;
- // if (t == typeof(double)) return dtype.Float64;
- // throw new ArgumentException("Can not convert given type to dtype: " + t);
- //}
- }
-}
diff --git a/src/Numpy.Bare/Models/Flags.cs b/src/Numpy.Bare/Models/Flags.cs
deleted file mode 100644
index 161c987..0000000
--- a/src/Numpy.Bare/Models/Flags.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Python.Runtime;
-
-namespace Numpy.Models
-{
- public class Flags : PythonObject
- {
- public Flags(PyObject pyobject) : base(pyobject)
- {
- }
-
- }
-}
diff --git a/src/Numpy.Bare/Models/Matrix.cs b/src/Numpy.Bare/Models/Matrix.cs
deleted file mode 100644
index 1f99237..0000000
--- a/src/Numpy.Bare/Models/Matrix.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Python.Runtime;
-
-namespace Numpy.Models
-{
- public class Matrix : PythonObject
- {
- public Matrix(PyObject pyobject) : base(pyobject)
- {
- }
-
- }
-}
diff --git a/src/Numpy.Bare/Models/MemMapMode.cs b/src/Numpy.Bare/Models/MemMapMode.cs
deleted file mode 100644
index cf72a66..0000000
--- a/src/Numpy.Bare/Models/MemMapMode.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Python.Runtime;
-
-namespace Numpy.Models
-{
- public class MemMapMode : PythonObject
- {
- public MemMapMode(PyObject pyobject) : base(pyobject)
- {
- }
-
- }
-}
diff --git a/src/Numpy.Bare/Models/NDarray.CastOperators.cs b/src/Numpy.Bare/Models/NDarray.CastOperators.cs
deleted file mode 100644
index 758c69b..0000000
--- a/src/Numpy.Bare/Models/NDarray.CastOperators.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Text;
-
-namespace Numpy
-{
- public partial class NDarray
- {
- public static implicit operator NDarray(Array array)
- {
- if (array == null)
- return null;
- switch (array)
- {
- case byte[] a: return np.array(a);
- case bool[] a: return np.array(a);
- case short[] a: return np.array(a);
- case int[] a: return np.array(a);
- case long[] a: return np.array(a);
- case float[] a: return np.array(a);
- case double[] a: return np.array(a);
- case byte[,] a: return np.array(a);
- case bool[,] a: return np.array(a);
- case short[,] a: return np.array(a);
- case int[,] a: return np.array(a);
- case long[,] a: return np.array(a);
- case float[,] a: return np.array(a);
- case double[,] a: return np.array(a);
- case byte[,,] a: return np.array(a);
- case bool[,,] a: return np.array(a);
- case short[,,] a: return np.array(a);
- case int[,,] a: return np.array(a);
- case long[,,] a: return np.array(a);
- case float[,,] a: return np.array(a);
- case double[,,] a: return np.array(a);
- }
- throw new InvalidOperationException($"Unable to cast {array.GetType()} to NDarray");
- }
-
- // these must be explicit or we have bad side effects
- public static explicit operator NDarray(bool d) => np.asarray(d);
- public static explicit operator NDarray(byte d) => np.asarray(d);
- public static explicit operator NDarray(short d) => np.asarray(d);
- public static explicit operator NDarray(int d) => np.asarray(d);
- public static explicit operator NDarray(long d) => np.asarray(d);
- public static explicit operator NDarray(float d) => np.asarray(d);
- public static explicit operator NDarray(double d) => np.asarray(d);
-
- // these must be explicit or we have bad side effects
- public static explicit operator bool(NDarray a) => np.asscalar(a);
- public static explicit operator byte(NDarray a) => np.asscalar(a);
- public static explicit operator short(NDarray a) => np.asscalar(a);
- public static explicit operator int(NDarray a) => np.asscalar(a);
- public static explicit operator long(NDarray a) => np.asscalar(a);
- public static explicit operator float(NDarray a) => np.asscalar(a);
- public static explicit operator double(NDarray a) => np.asscalar(a);
-
-
-
- }
-}
diff --git a/src/Numpy.Bare/Models/NDarray.Operators.cs b/src/Numpy.Bare/Models/NDarray.Operators.cs
deleted file mode 100644
index 6c9b9da..0000000
--- a/src/Numpy.Bare/Models/NDarray.Operators.cs
+++ /dev/null
@@ -1,502 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Python.Runtime;
-
-namespace Numpy
-{
- public partial class NDarray
- {
- //------------------------------
- // Comparison operators:
- //------------------------------
-
- // Return self operator <(NDarray a, ValueType obj)
- {
- return new NDarray(a.self.InvokeMethod("__lt__", obj.ToPython()));
- }
-
- // Return self<=value.
- public static NDarray operator <=(NDarray a, ValueType obj)
- {
- return new NDarray(a.self.InvokeMethod("__le__", obj.ToPython()));
- }
-
- // Return self>value.
- public static NDarray operator >(NDarray a, ValueType obj)
- {
- return new NDarray(a.self.InvokeMethod("__gt__", obj.ToPython()));
- }
-
- // Return self>=value.
- public static NDarray operator >=(NDarray a, ValueType obj)
- {
- return new NDarray(a.self.InvokeMethod("__ge__", obj.ToPython()));
- }
-
- ///
- /// Returns an array of bool where the elements of the array are == value
- ///
- public NDarray equals(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__eq__", obj.ToPython()));
- }
-
- ///
- /// Returns an array of bool where the elements of the array are != value
- ///
- public NDarray not_equals(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__ne__", obj.ToPython()));
- }
-
- // Return element-wise self operator <(NDarray a, NDarray obj)
- {
- return new NDarray(a.self.InvokeMethod("__lt__", obj.self));
- }
-
- // Return element-wise self<=array.
- public static NDarray operator <=(NDarray a, NDarray obj)
- {
- return new NDarray(a.self.InvokeMethod("__le__", obj.self));
- }
-
- // Return element-wise self>array.
- public static NDarray operator >(NDarray a, NDarray obj)
- {
- return new NDarray(a.self.InvokeMethod("__gt__", obj.self));
- }
-
- // Return element-wise self>=array.
- public static NDarray operator >=(NDarray a, NDarray obj)
- {
- return new NDarray(a.self.InvokeMethod("__ge__", obj.self));
- }
-
- ///
- /// Returns an array of bool where the elements of the array are == array element-wise
- ///
- public NDarray equals(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__eq__", obj.self));
- }
-
- ///
- /// Returns an array of bool where the elements of the array are != array element-wise
- ///
- public NDarray not_equals(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__ne__", obj.self));
- }
-
- //------------------------------
- // Truth value of an array(bool) :
- //------------------------------
-
- ///
- /// Note
- /// Truth-value testing of an array invokes ndarray.__nonzero__, which raises an error if the
- /// number of elements in the array is larger than 1, because the truth value of such arrays is
- /// ambiguous.Use.any() and.all() instead to be clear about what is meant in such cases.
- /// (If the number of elements is 0, the array evaluates to False.)
- ///
- public static NDarray nonzero(NDarray a)
- {
- return new NDarray(a.self.InvokeMethod("__nonzero__"));
- }
-
- //------------------------------
- // Unary operations:
- //------------------------------
-
- // Return -self
- public static NDarray operator -(NDarray a)
- {
- return new NDarray(a.self.InvokeMethod("__neg__"));
- }
-
- // Return +self
- public static NDarray operator +(NDarray a)
- {
- return new NDarray(a.self.InvokeMethod("__pos__"));
- }
-
- // ndarray.__abs__(self) // C# doesn't have an operator for that
-
- // Return ~self
- public static NDarray operator ~(NDarray a)
- {
- return new NDarray(a.self.InvokeMethod("__invert__"));
- }
-
- //------------------------------
- // Arithmetic operators:
- //------------------------------
-
- // Return self+value.
- public static NDarray operator +(NDarray a, ValueType obj)
- {
- return new NDarray(a.self.InvokeMethod("__add__", obj.ToPython()));
- }
-
- // Return value+self.
- public static NDarray operator +(ValueType obj, NDarray a)
- {
- return new NDarray(a.self.InvokeMethod("__add__", obj.ToPython()));
- }
-
- // Return self-value.
- public static NDarray operator -(NDarray a, ValueType obj)
- {
- return new NDarray(a.self.InvokeMethod("__sub__", obj.ToPython()));
- }
-
- // Return self*value.
- public static NDarray operator *(NDarray a, ValueType obj)
- {
- return new NDarray(a.self.InvokeMethod("__mul__", obj.ToPython()));
- }
-
- // Return value*self.
- public static NDarray operator *(ValueType obj, NDarray a)
- {
- return new NDarray(a.self.InvokeMethod("__mul__", obj.ToPython()));
- }
-
- // Return self/value.
- public static NDarray operator /(NDarray a, ValueType obj)
- {
- return new NDarray(a.self.InvokeMethod("__truediv__", obj.ToPython()));
- }
-
- // Return element-wise self+array.
- public static NDarray operator +(NDarray a, NDarray obj)
- {
- return new NDarray(a.self.InvokeMethod("__add__", obj.self));
- }
-
- // Return element-wise self-array.
- public static NDarray operator -(NDarray a, NDarray obj)
- {
- return new NDarray(a.self.InvokeMethod("__sub__", obj.self));
- }
-
- // Return element-wise self*array.
- public static NDarray operator *(NDarray a, NDarray obj)
- {
- return new NDarray(a.self.InvokeMethod("__mul__", obj.self));
- }
-
- // Return element-wise self/array.
- public static NDarray operator /(NDarray a, NDarray obj)
- {
- return new NDarray(a.self.InvokeMethod("__truediv__", obj.self));
- }
-
- /////
- ///// Return self/value.
- /////
- //public static NDarray truediv(NDarray a, ValueType obj)
- //{
- // return new NDarray(a.self.InvokeMethod("__truediv__", obj.ToPython()));
- //}
-
- ///
- /// Return self//value.
- ///
- public NDarray floordiv(NDarray a, ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__floordiv__", obj.ToPython()));
- }
-
- // Return self%value.
- public static NDarray operator %(NDarray a, ValueType obj)
- {
- return new NDarray(a.self.InvokeMethod("__mod__", obj.ToPython()));
- }
-
- ///
- /// Return divmod(value).
- ///
- public NDarray divmod(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__divmod__", obj.ToPython()));
- }
-
- ///
- /// Return pow(value).
- ///
- public NDarray pow(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__pow__", obj.ToPython()));
- }
-
- ///
- /// Return self<<value.
- ///
- public static NDarray operator <<(NDarray a, int obj)
- {
- return new NDarray(a.self.InvokeMethod("__lshift__", obj.ToPython()));
- }
-
- ///
- /// Return self>>value.
- ///
- public static NDarray operator >>(NDarray a, int obj)
- {
- return new NDarray(a.self.InvokeMethod("__rshift__", obj.ToPython()));
- }
-
- ///
- /// Return self&value.
- ///
- public static NDarray operator &(NDarray a, int obj)
- {
- return new NDarray(a.self.InvokeMethod("__and__", obj.ToPython()));
- }
-
- ///
- /// Return self|value.
- ///
- public static NDarray operator |(NDarray a, int obj)
- {
- return new NDarray(a.self.InvokeMethod("__or__", obj.ToPython()));
- }
-
- ///
- /// Return self^value.
- ///
- public static NDarray operator ^(NDarray a, int obj)
- {
- return new NDarray(a.self.InvokeMethod("__xor__", obj.ToPython()));
- }
-
- //------------------------------
- // Arithmetic, in-place:
- //------------------------------
-
- ///
- /// Return self+=value.
- ///
- public NDarray iadd(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__iadd__", obj.ToPython()));
- }
-
- ///
- /// Return self-=value.
- ///
- public NDarray isub(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__isub__", obj.ToPython()));
- }
-
- ///
- /// Return self*=value.
- ///
- public NDarray imul(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__imul__", obj.ToPython()));
- }
-
- ///
- /// Return self/=value.
- ///
- public NDarray idiv(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__itruediv__", obj.ToPython()));
- }
-
- ///
- /// Return self/=value.
- ///
- public NDarray itruediv(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__itruediv__", obj.ToPython()));
- }
-
- ///
- /// Return self//=value.
- ///
- public NDarray ifloordiv(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__floordiv__", obj.ToPython()));
- }
-
- ///
- /// Return self%value.
- ///
- public NDarray imod(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__imod__", obj.ToPython()));
- }
-
- ///
- /// Return inplace pow(value).
- ///
- public NDarray ipow(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__ipow__", obj.ToPython()));
- }
-
- ///
- /// Return inplace self<<value.
- ///
- public NDarray ilshift(int obj)
- {
- return new NDarray(self.InvokeMethod("__ilshift__", obj.ToPython()));
- }
-
- ///
- /// Return inplace self>>value.
- ///
- public NDarray irshift(int obj)
- {
- return new NDarray(self.InvokeMethod("__irshift__", obj.ToPython()));
- }
-
- ///
- /// Return self&=value.
- ///
- public NDarray iand(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__iand__", obj.ToPython()));
- }
-
- ///
- /// Return self|=value.
- ///
- public NDarray ior(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__ior__", obj.ToPython()));
- }
-
- ///
- /// Return self^=value.
- ///
- public NDarray ixor(ValueType obj)
- {
- return new NDarray(self.InvokeMethod("__ixor__", obj.ToPython()));
- }
-
- ///
- /// Return self+=NDarray.
- ///
- public NDarray iadd(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__iadd__", obj.self));
- }
-
- ///
- /// Return self-=NDarray.
- ///
- public NDarray isub(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__isub__", obj.self));
- }
-
- ///
- /// Return self*=NDarray.
- ///
- public NDarray imul(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__imul__", obj.self));
- }
-
- ///
- /// Return self/=NDarray.
- ///
- public NDarray idiv(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__idiv__", obj.self));
- }
-
- ///
- /// Return self/=NDarray.
- ///
- public NDarray itruediv(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__itruediv__", obj.self));
- }
-
- ///
- /// Return self//=NDarray.
- ///
- public NDarray ifloordiv(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__floordiv__", obj.self));
- }
-
- ///
- /// Return self%NDarray.
- ///
- public NDarray imod(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__imod__", obj.self));
- }
-
- ///
- /// Return inplace pow(NDarray).
- ///
- public NDarray ipow(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__ipow__", obj.self));
- }
-
- ///
- /// Return inplace self<<NDarray.
- ///
- public NDarray ilshift(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__ilshift__", obj.self));
- }
-
- ///
- /// Return inplace self>>NDarray.
- ///
- public NDarray irshift(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__irshift__", obj.self));
- }
-
- ///
- /// Return self&=NDarray.
- ///
- public NDarray iand(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__iand__", obj.self));
- }
-
- ///
- /// Return self|=NDarray.
- ///
- public NDarray ior(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__ior__", obj.self));
- }
-
- ///
- /// Return self^=NDarray.
- ///
- public NDarray ixor(NDarray obj)
- {
- return new NDarray(self.InvokeMethod("__ixor__", obj.self));
- }
-
- // TODO:
- // ndarray.__matmul__($self, value, /) Return self@value.
- //ndarray.__copy__() Used if copy.copy is called on an array.
- //ndarray.__deepcopy__(memo, /) Used if copy.deepcopy is called on an array.
- //ndarray.__reduce__() For pickling.
- //ndarray.__setstate__(state, /) For unpickling.
- //ndarray.__contains__($self, key, /) Return key in self.
-
- //ndarray.__int__(self)
- //ndarray.__long__
- //ndarray.__float__(self)
- //ndarray.__oct__
- //ndarray.__hex__
- }
-}
diff --git a/src/Numpy.Bare/Models/NDarray.aliases.cs b/src/Numpy.Bare/Models/NDarray.aliases.cs
deleted file mode 100644
index f84d614..0000000
--- a/src/Numpy.Bare/Models/NDarray.aliases.cs
+++ /dev/null
@@ -1,131 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Numpy
-{
- public partial class NDarray
- {
- ///
- /// Calculate the absolute value element-wise.
- ///
- /// np.abs is a shorthand for this function.
- ///
- ///
- /// A location into which the result is stored. If provided, it must have
- /// a shape that the inputs broadcast to. If not provided or None,
- /// a freshly-allocated array is returned. A tuple (possible only as a
- /// keyword argument) must have length equal to the number of outputs.
- ///
- ///
- /// Values of True indicate to calculate the ufunc at that position, values
- /// of False indicate to leave the value in the output alone.
- ///
- ///
- /// An ndarray containing the absolute value of
- /// each element in x. For complex input, a + ib, the
- /// absolute value is .
- /// This is a scalar if x is a scalar.
- ///
- public NDarray abs(NDarray @out = null, NDarray @where = null)
- => this.absolute(@out, @where);
-
- ///
- /// Return the minimum of an array or minimum along an axis.
- ///
- /// Notes
- ///
- /// NaN values are propagated, that is if at least one item is NaN, the
- /// corresponding min value will be NaN as well. To ignore NaN values
- /// (MATLAB behavior), please use nanmin.
- ///
- /// Don’t use amin for element-wise comparison of 2 arrays; when
- /// a.shape[0] is 2, minimum(a[0], a[1]) is faster than
- /// amin(a, axis=0).
- ///
- ///
- /// Axis or axes along which to operate. By default, flattened input is
- /// used.
- ///
- /// If this is a tuple of ints, the minimum is selected over multiple axes,
- /// instead of a single axis or all the axes as before.
- ///
- ///
- /// Alternative output array in which to place the result. Must
- /// be of the same shape and buffer length as the expected output.
- /// See doc.ufuncs (Section “Output arguments”) for more details.
- ///
- ///
- /// If this is set to True, the axes which are reduced are left
- /// in the result as dimensions with size one. With this option,
- /// the result will broadcast correctly against the input array.
- ///
- /// If the default value is passed, then keepdims will not be
- /// passed through to the amin method of sub-classes of
- /// ndarray, however any non-default value will be. If the
- /// sub-class’ method does not implement keepdims any
- /// exceptions will be raised.
- ///
- ///
- /// The maximum value of an output element. Must be present to allow
- /// computation on empty slice. See reduce for details.
- ///
- ///
- /// Minimum of a. If axis is None, the result is a scalar value.
- /// If axis is given, the result is an array of dimension
- /// a.ndim - 1.
- ///
- public NDarray min(int[] axis = null, NDarray @out = null, bool? keepdims = null, ValueType initial = null)
- => this.amin( axis: axis, @out: @out, keepdims: keepdims, initial: initial);
-
- ///
- /// Return the maximum of an array or maximum along an axis.
- ///
- /// Notes
- ///
- /// NaN values are propagated, that is if at least one item is NaN, the
- /// corresponding max value will be NaN as well. To ignore NaN values
- /// (MATLAB behavior), please use nanmax.
- ///
- /// Don’t use amax for element-wise comparison of 2 arrays; when
- /// a.shape[0] is 2, maximum(a[0], a[1]) is faster than
- /// amax(a, axis=0).
- ///
- ///
- /// Axis or axes along which to operate. By default, flattened input is
- /// used.
- ///
- /// If this is a tuple of ints, the maximum is selected over multiple axes,
- /// instead of a single axis or all the axes as before.
- ///
- ///
- /// Alternative output array in which to place the result. Must
- /// be of the same shape and buffer length as the expected output.
- /// See doc.ufuncs (Section “Output arguments”) for more details.
- ///
- ///
- /// If this is set to True, the axes which are reduced are left
- /// in the result as dimensions with size one. With this option,
- /// the result will broadcast correctly against the input array.
- ///
- /// If the default value is passed, then keepdims will not be
- /// passed through to the amax method of sub-classes of
- /// ndarray, however any non-default value will be. If the
- /// sub-class’ method does not implement keepdims any
- /// exceptions will be raised.
- ///
- ///
- /// The minimum value of an output element. Must be present to allow
- /// computation on empty slice. See reduce for details.
- ///
- ///
- /// Maximum of a. If axis is None, the result is a scalar value.
- /// If axis is given, the result is an array of dimension
- /// a.ndim - 1.
- ///
- public NDarray max(int[] axis = null, NDarray @out = null, bool? keepdims = null, ValueType initial = null)
- {
- return this.amax( axis: axis, @out: @out, keepdims: keepdims, initial: initial);
- }
- }
-}
diff --git a/src/Numpy.Bare/Models/NDarray.cs b/src/Numpy.Bare/Models/NDarray.cs
deleted file mode 100644
index d0fb8f9..0000000
--- a/src/Numpy.Bare/Models/NDarray.cs
+++ /dev/null
@@ -1,576 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text;
-using Numpy.Models;
-using Python.Runtime;
-
-
-namespace Numpy
-{
- public partial class NDarray : PythonObject
- {
- // these are manual overrides of functions or properties that can not be automatically generated
-
- public NDarray(PyObject pyobj) : base(pyobj)
- {
- }
-
- public NDarray(NDarray t) : base((PyObject) t.PyObject)
- {
- }
-
- ///
- /// Returns a copy of the array data
- ///
- public T[] GetData()
- {
- // note: this implementation works only for device CPU
- long ptr = PyObject.ctypes.data;
- int size = PyObject.size;
- object array = null;
- if (typeof(T) == typeof(byte)) array = new byte[size];
- else if (typeof(T) == typeof(short)) array = new short[size];
- else if (typeof(T) == typeof(int)) array = new int[size];
- else if (typeof(T) == typeof(long)) array = new long[size];
- else if (typeof(T) == typeof(float)) array = new float[size];
- else if (typeof(T) == typeof(double)) array = new double[size];
- else if (typeof(T) == typeof(bool)) array = new byte[size];
- else
- throw new InvalidOperationException(
- "Can not copy the data with data type due to limitations of Marshal.Copy: " + typeof(T).Name);
- switch (array)
- {
- case byte[] a:
- Marshal.Copy(new IntPtr(ptr), a, 0, a.Length);
- break;
- case short[] a:
- Marshal.Copy(new IntPtr(ptr), a, 0, a.Length);
- break;
- case int[] a:
- Marshal.Copy(new IntPtr(ptr), a, 0, a.Length);
- break;
- case long[] a:
- Marshal.Copy(new IntPtr(ptr), a, 0, a.Length);
- break;
- case float[] a:
- Marshal.Copy(new IntPtr(ptr), a, 0, a.Length);
- break;
- case double[] a:
- Marshal.Copy(new IntPtr(ptr), a, 0, a.Length);
- break;
- }
- // special handling for types that are not supported by Marshal.Copy: must be converted i.e. 1 => true, 0 => false
- if (typeof(T) == typeof(bool)) return (T[])(object)((byte[])array).Select(x=>x>0).ToArray();
- return (T[]) array;
- }
-
- ///
- /// Information about the memory layout of the array.
- ///
- public Flags flags => new Flags(self.GetAttr("flags")); // TODO: implement Flags
-
- ///
- /// Tuple of array dimensions.
- ///
- public Shape shape => new Shape( self.GetAttr("shape").As());
-
- ///
- /// Tuple of bytes to step in each dimension when traversing an array.
- ///
- public int[] strides => self.GetAttr("strides").As();
-
- ///
- /// Number of array dimensions.
- ///
- public int ndim => self.GetAttr("ndim").As();
-
- ///
- /// Python buffer object pointing to the start of the array’s data.
- ///
- public PyObject data => self.GetAttr("data");
-
- ///
- /// Number of elements in the array.
- ///
- public int size => self.GetAttr("size").As();
-
- ///
- /// Length of one array element in bytes.
- ///
- public int itemsize => self.GetAttr("itemsize").As();
-
- ///
- /// Total bytes consumed by the elements of the array.
- ///
- public int nbytes => self.GetAttr("nbytes").As();
-
- ///
- /// Base object if memory is from some other object.
- ///
- public NDarray @base
- {
- get
- {
- PyObject base_obj = self.GetAttr("base");
- if (base_obj.IsNone())
- return null;
- return new NDarray(base_obj);
- }
- }
-
- ///
- /// Data-type of the array’s elements.
- ///
- public Dtype dtype => new Dtype(self.GetAttr("dtype"));
-
- ///
- /// Same as self.transpose(), except that self is returned if self.ndim < 2.
- ///
- public NDarray T => new NDarray(self.GetAttr("T"));
-
- /////
- ///// The real part of the array.
- /////
- //public NDarray real => new NDarray(self.GetAttr("real"));
-
- /////
- ///// The imaginary part of the array.
- /////
- //public NDarray imag => new NDarray(self.GetAttr("imag"));
-
- ///
- /// A 1-D iterator over the array.
- ///
- public PyObject flat => self.GetAttr("flat"); // todo: wrap and support usecases
-
- ///
- /// An object to simplify the interaction of the array with the ctypes module.
- ///
- public PyObject ctypes => self.GetAttr("ctypes"); // TODO: wrap ctypes
-
-
- ///
- /// Length of the array (same as size)
- ///
- public int len => self.InvokeMethod("__len__").As();
-
- ///
- /// Insert scalar into an array (scalar is cast to array’s dtype, if possible)
- ///
- /// There must be at least 1 argument, and define the last argument
- /// as item. Then, a.itemset(*args) is equivalent to but faster
- /// than a[args] = item. The item should be a scalar value and args
- /// must select a single item in the array a.
- ///
- /// Notes
- ///
- /// Compared to indexing syntax, itemset provides some speed increase
- /// for placing a scalar into a particular location in an ndarray,
- /// if you must do this. However, generally this is discouraged:
- /// among other problems, it complicates the appearance of the code.
- /// Also, when using itemset (and item) inside a loop, be sure
- /// to assign the methods to a local variable to avoid the attribute
- /// look-up at each loop iteration.
- ///
- ///
- /// If one argument: a scalar, only used in case a is of size 1.
- /// If two arguments: the last argument is the value to be set
- /// and must be a scalar, the first argument specifies a single array
- /// element location. It is either an int or a tuple.
- ///
- public void itemset(params object[] args)
- {
- var pyargs = ToTuple(args);
- var kwargs = new PyDict();
- dynamic py = self.InvokeMethod("itemset", pyargs, kwargs);
- }
-
- ///
- /// Construct Python bytes containing the raw data bytes in the array.
- ///
- /// Constructs Python bytes showing a copy of the raw contents of
- /// data memory. The bytes object can be produced in either ‘C’ or ‘Fortran’,
- /// or ‘Any’ order (the default is ‘C’-order). ‘Any’ order means C-order
- /// unless the F_CONTIGUOUS flag in the array is set, in which case it
- /// means ‘Fortran’ order.
- ///
- /// This function is a compatibility alias for tobytes. Despite its name it returns bytes not strings.
- ///
- ///
- /// Order of the data for multidimensional arrays:
- /// C, Fortran, or the same as for the original array.
- ///
- ///
- /// Python bytes exhibiting a copy of a’s raw data.
- ///
- public byte[] tostring(string order = null)
- {
- return tobytes();
- }
-
- ///
- /// Construct Python bytes containing the raw data bytes in the array.
- ///
- /// Constructs Python bytes showing a copy of the raw contents of
- /// data memory. The bytes object can be produced in either ‘C’ or ‘Fortran’,
- /// or ‘Any’ order (the default is ‘C’-order). ‘Any’ order means C-order
- /// unless the F_CONTIGUOUS flag in the array is set, in which case it
- /// means ‘Fortran’ order.
- ///
- ///
- /// Order of the data for multidimensional arrays:
- /// C, Fortran, or the same as for the original array.
- ///
- ///
- /// Python bytes exhibiting a copy of a’s raw data.
- ///
- public byte[] tobytes(string order = null)
- {
- throw new NotImplementedException("TODO: this needs to be implemented with Marshal.Copy");
- var pyargs = ToTuple(new object[]
- {
- });
- var kwargs = new PyDict();
- if (order != null) kwargs["order"] = ToPython(order);
- dynamic py = self.InvokeMethod("tobytes", pyargs, kwargs);
- return ToCsharp(py);
- }
-
- ///
- /// New view of array with the same data.
- ///
- /// Notes
- ///
- /// a.view() is used two different ways:
- ///
- /// a.view(some_dtype) or a.view(dtype=some_dtype) constructs a view
- /// of the array’s memory with a different data-type. This can cause a
- /// reinterpretation of the bytes of memory.
- ///
- /// a.view(ndarray_subclass) or a.view(type=ndarray_subclass) just
- /// returns an instance of ndarray_subclass that looks at the same array
- /// (same shape, dtype, etc.) This does not cause a reinterpretation of the
- /// memory.
- ///
- /// For a.view(some_dtype), if some_dtype has a different number of
- /// bytes per entry than the previous dtype (for example, converting a
- /// regular array to a structured array), then the behavior of the view
- /// cannot be predicted just from the superficial appearance of a (shown
- /// by print(a)). It also depends on exactly how a is stored in
- /// memory. Therefore if a is C-ordered versus fortran-ordered, versus
- /// defined as a slice or transpose, etc., the view may give different
- /// results.
- ///
- ///
- /// Data-type descriptor of the returned view, e.g., float32 or int16. The
- /// default, None, results in the view having the same data-type as a.
- /// This argument can also be specified as an ndarray sub-class, which
- /// then specifies the type of the returned object (this is equivalent to
- /// setting the type parameter).
- ///
- ///
- /// Type of the returned view, e.g., ndarray or matrix. Again, the
- /// default None results in type preservation.
- ///
- public void view(Dtype dtype = null, Type type = null)
- {
- throw new NotImplementedException("Get python type 'ndarray' and 'matrix' and substitute them for the given .NET type");
- var pyargs = ToTuple(new object[]
- {
- });
- var kwargs = new PyDict();
- if (dtype != null) kwargs["dtype"] = ToPython(dtype);
- if (type != null) kwargs["type"] = ToPython(type);
- dynamic py = self.InvokeMethod("view", pyargs, kwargs);
- }
-
- ///
- /// Change shape and size of array in-place.
- ///
- /// Notes
- ///
- /// This reallocates space for the data area if necessary.
- ///
- /// Only contiguous arrays (data elements consecutive in memory) can be
- /// resized.
- ///
- /// The purpose of the reference count check is to make sure you
- /// do not use this array as a buffer for another Python object and then
- /// reallocate the memory. However, reference counts can increase in
- /// other ways so if you are sure that you have not shared the memory
- /// for this array with another Python object, then you may safely set
- /// refcheck to False.
- ///
- ///
- /// Shape of resized array.
- ///
- ///
- /// If False, reference count will not be checked. Default is True.
- ///
- public void resize(Shape new_shape, bool? refcheck = null)
- {
- var pyargs = ToTuple(new object[]
- {
- new_shape,
- });
- var kwargs = new PyDict();
- if (refcheck != null) kwargs["refcheck"] = ToPython(refcheck);
- dynamic py = self.InvokeMethod("resize", pyargs, kwargs);
- }
-
- ///
- /// Gives a new shape to an array without changing its data.
- ///
- /// Notes
- ///
- /// It is not always possible to change the shape of an array without
- /// copying the data. If you want an error to be raised when the data is copied,
- /// you should assign the new shape to the shape attribute of the array:
- ///
- /// The order keyword gives the index ordering both for fetching the values
- /// from a, and then placing the values into the output array.
- /// For example, let’s say you have an array:
- ///
- /// You can think of reshaping as first raveling the array (using the given
- /// index order), then inserting the elements from the raveled array into the
- /// new array using the same kind of index ordering as was used for the
- /// raveling.
- ///
- ///
- /// The new shape should be compatible with the original shape. If
- /// an integer, then the result will be a 1-D array of that length.
- /// One shape dimension can be -1. In this case, the value is
- /// inferred from the length of the array and remaining dimensions.
- ///
- ///
- /// This will be a new view object if possible; otherwise, it will
- /// be a copy. Note there is no guarantee of the memory layout (C- or
- /// Fortran- contiguous) of the returned array.
- ///
- public NDarray reshape(params int[] newshape)
- {
- //auto-generated code, do not change
- var @this = this;
- return NumPy.Instance.reshape(@this, new Shape(newshape));
- }
-
- ///
- /// returns the 'array([ .... ])'-representation known from the console
- ///
- public string repr => self.InvokeMethod("__repr__").As();
-
- ///
- /// returns the '[ .... ]'-representation
- ///
- public string str => self.InvokeMethod("__str__").As();
-
- public NDarray this[string slicing_notation]
- {
- get
- {
- var tuple=new PyTuple(Slice.ParseSlices(slicing_notation).Select(s =>
- {
- if (s.IsIndex)
- return new PyInt(s.Start.Value);
- else
- return s.ToPython();
- }).ToArray());
- return new NDarray(this.PyObject[tuple]);
- }
- set
- {
- var tuple = new PyTuple(Slice.ParseSlices(slicing_notation).Select(s =>
- {
- if (s.IsIndex)
- return new PyInt(s.Start.Value);
- else
- return s.ToPython();
- }).ToArray());
- self.SetItem(tuple, ToPython(value));
- }
- }
-
- public NDarray this[params int[] coords]
- {
- get
- {
- var tuple = ToTuple(coords);
- return new NDarray(this.PyObject[tuple]);
- }
- set
- {
- var tuple = ToTuple(coords);
- self.SetItem(tuple, ToPython(value));
- }
- }
-
- public NDarray this[params NDarray[] indices]
- {
- get
- {
- var tuple = new PyTuple(indices.Select(a => (PyObject)a.PyObject).ToArray());
- return new NDarray(this.PyObject[tuple]);
- }
- set
- {
- var tuple = new PyTuple(indices.Select(a => (PyObject)a.PyObject).ToArray());
- self.SetItem(tuple, ToPython(value));
- }
- }
-
- public NDarray this[params object[] arrays_slices_or_indices]
- {
- get
- {
- var pyobjs = arrays_slices_or_indices.Select