SciSharp/Numpy.NET

Cannot slice by passing either a string or a Numpy.Models.Slice as an index.

megawattfs opened this issue · 6 comments

I am using Numpy.dll version 3.10.1.30 with Python.Runtime.dll version 2.5.2. When I try slicing a 1d NDarray I get a MissingMethodException. Here is my code:

using Numpy;
using static Numpy.np;
using System.Numerics;
using Numpy.Models;
using Python.Runtime;

public static void numpy_test()
{
        Python.Runtime.PythonEngine.Initialize();
        NDarray arr = np.array(new float[]{ 1, 2, 3, 4, 5 });
        Numpy.Models.Slice slice0 = new Numpy.Models.Slice(2, 4);
        var arr4 = arr[slice0];
        Numpy.Models.Slice slice1 = new Numpy.Models.Slice(2, -1);
        var arr5 = arr[slice1];
        var arr1 = arr["2:4"];
        var arr2 = arr[":4"];
        var arr3 = arr[":-1"];
        Debug.Log("Numpy test passed.");
}

As far as I can tell the syntax is as described in the README; however, none of the slicing operations in the above method work (I tested each of them individually). Indexing with a single value (arr[0]) works, but I haven't figured out a way to do slicing.

Stack trace back to my test method:

System.MissingMethodException: Python.Runtime.PyObject Python.Runtime.PythonEngine.Eval(string,Python.Runtime.PyDict,Python.Runtime.PyObject) at Numpy.PythonObject.ToPython (System.Object obj) [0x0014d] in <b8b5aebdcf44433497e62f392cbc5b60>:0 at Numpy.NDarray.<get_Item>b__71_0 (System.Object x) [0x00080] in <b8b5aebdcf44433497e62f392cbc5b60>:0 at System.Linq.Enumerable+SelectArrayIterator2[TSource,TResult].ToArray () [0x00012] in <351e49e2a5bf4fd6beabb458ce2255f3>:0 at System.Linq.Enumerable.ToArray[TSource] (System.Collections.Generic.IEnumerable1[T] source) [0x0001f] in <351e49e2a5bf4fd6beabb458ce2255f3>:0 at Numpy.NDarray.get_Item (System.Object[] arrays_slices_or_indices) [0x00012] in <b8b5aebdcf44433497e62f392cbc5b60>:0 at FilteringUtility.numpy_test () [0x00031]

Update: I have tried to dig into this issue by copying the slicing by string code over from NDarray.cs to figure out why it breaks down:

using Numpy;
using static Numpy.np;
using System.Numerics;
using Numpy.Models;
using Python.Runtime;

public static void numpy_test()
    {
        Python.Runtime.PythonEngine.Initialize();

        NDarray arr = np.array(new float[]{ 1, 2, 3, 4, 5 });

        var tuple = new PyTuple(Numpy.Models.Slice.ParseSlices("2:4").Select(s =>
        {
            if (s.IsIndex)
                return new PyInt(s.Start.Value);
            else
                return s.ToPython();
        }).ToArray());
        var arr0 = new NDarray(arr.PyObject[tuple]);
        Debug.Log("Numpy test passed.");
    }

But this does not compile because "The type 'PyObject' is defined in an assembly that is not referenced. You must add a reference to assembly 'Python.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=5000fea6cba702dd'."

But the most recent version of Python.Runtime available on NuGet is 2.5.2, which does have a definition for Python.Runtime.PyObject, as does Numpy.Models. Not sure what is going on here but will keep looking into it.

henon commented

I just added a little test case with your code and it works perfectly in my test environment.

        [TestMethod]
        public void IssueByMegawattFs()
        {
            var arr = np.array(new int[] { 1, 2, 3, 4, 5 });
            var slice0 = new Slice(2, 4);
            var arr4 = arr[slice0];
            Assert.AreEqual("array([3, 4])", arr4.repr);
            var slice1 = new Slice(2, -1);
            var arr5 = arr[slice1];
            Assert.AreEqual("array([3, 4])", arr5.repr);
            var arr1 = arr["2:4"];
            Assert.AreEqual("array([3, 4])", arr1.repr);
            var arr2 = arr[":4"];
            Assert.AreEqual("array([1, 2, 3, 4])", arr2.repr);
            var arr3 = arr[":-1"];
            Assert.AreEqual("array([1, 2, 3, 4])", arr3.repr);
        }

Here are the dependencies of my test project:
image

As you can see the difference is that Numpy references pythonnet 3.0.0-preview2022-04-11

I don't understand why yours uses Python.Runtime.dll version 2.5.2. I'll make a test project with the nuget to see if there is something wrong with the numpy 3.10.1.30 nuget.

henon commented

Have a look at the source code. I added a new SlicingExample for you which works just fine with the latest nuget

image

I see what happened:

I am using Unity, which is not compatible with NuGet. My process for adding Numpy to my project was as follows:

  1. Download the .nupkg directly from the NuGet website.
  2. Look under "Dependencies" on the NuGet page and download the .nupkg for all the dependencies
  3. Repeat step 2 with the NuGet page for all the dependencies until there are none left
  4. Extract the .nupkg files and add the .NET Standard 2 version of each package to my Unity project assets folder.

On the NuGet page for Numpy, Python.Runtime is not even listed as a dependency:
image

Therefore, I determined which version of Python.Runtime to use based on Python.Included, which lists Python.Runtime v2.5.2 as the minimum requirement and links to this download:
image

I see now that there is a version 3.0.0 available at https://www.nuget.org/packages/pythonnet/3.0.0-rc4. I will try that and see if it works. Maybe this version should be listed under dependencies for Numpy on the NuGet page?

Thank you for looking into this!

Never mind--I see now that I was using the wrong version of Python.Included (I got mixed up because NuGet linked me to the "latest" non-preview version of Python.Included from Numpy's dependency page, but I needed 3.10.0-preview2).

henon commented

Correct ;). Closing this. Should you still have issues you can reopen.