Thank you Michael for your quick response.

I started to write my own implementation of an n-dimensional array.
Currently I have only implemented __getitem__. You can pass in slice like in
numpy. E.g.

>>>from IronMath import ndarray
>>>a = ndarray(range(36), (6,6))
>>>print a
[[0,    1,      2,      3,      4,      5],
[6,     7,      8,      9,      10,     11],
[12,    13,     14,     15,     16,     17],
[18,    19,     20,     21,     22,     23],
[24,    25,     26,     27,     28,     29],
[30,    31,     32,     33,     34,     35]]
>>>b = a[1:5:2, :]
>>>print b
[[6,    7,      8,      9,      10,     11],
[18,    19,     20,     21,     22,     23]]
>>>b.Shape
(2, 6)
>>>b.Shape = (3,4)
>>>print b
[[6,    7,      8,      9],
[10,    11,     18,     19],
[20,    21,     22,     23]]
>>>c = b[:, [0,2,3]]
>>>print c
[[6,    8,      9],
[10,    18,     19],
[20,    22,     23]]


Im using a List<object> to hold the values internally. I'm not sure if this
is the best possible way in terms of speed. I'm also attaching the source
for the ndarray class. Can someone give me some pointers on optimization
aspects? Should I make it generic like ndarray<T>?

I know this class has a long way to go, but if anyone is interested in it
maybe I can set up a project on CodePlex and work on it? It could become a
base for a math library for IronPython.

Regards,
Aravin


-----Original Message-----
From: [email protected]
[mailto:[email protected]] On Behalf Of Michael Foord
Sent: Friday, November 13, 2009 7:18 PM
To: Discussion of IronPython
Subject: Re: [IronPython] n-dimensional array

Aravin wrote:
>
> Hello everyone,
>
> I'm developing an application for my research project. I'm using 
> IronPython as a scripting engine to allow easy data manipulation like 
> Matlab. I require a high performance n-dimensional array class. Does 
> anyone know of any .net library which provides a powerful 
> n-dimensional array?
>
> I would like to do slicing operations on the array like in NumPy. 
> (A[:2, :5] etc.)
>
I doubt you will find a .NET library that supports slicing in the same 
way as numpy...

You might try looking at Math.NET though:

http://www.mathdotnet.com/About.aspx

> And also things like ones(.) zeros(.). I tried to use NumPy with 
> Ironclad but im having some issues
>

Have you reported those issues?

All the best,

Michael Foord
>
> and would prefer if I could have a .net/ Ironpython ndarray library. 
> Can you please recommend me any such library? Thanks
>
> Aravin
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> Users mailing list
> [email protected]
> http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
>   


-- 
http://www.ironpythoninaction.com/

_______________________________________________
Users mailing list
[email protected]
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IronPython.Runtime;
using System.Collections;

namespace IronMath
{
    public class ndarray : IEnumerable
    {

        private int size;
        private int row;
        private int col;
        private List<int> shape;
        private int length;
        private List<object> tmpitems;

        public ndarray(List data)
        {
            //from the data figure out the dimension
            shape = new List<int>();
            GetShapeFromList(data);
            SetLength();
            tmpitems = new List<object>();
            UnpackData(data);
            if (tmpitems.Count != length)
                throw new ArgumentException();
        }

        public ndarray(IEnumerable<object> data, PythonTuple shape)
        {
            tmpitems = new List<object>(data);
            this.shape = new List<int>();
            length = 1;
            foreach (int axis in shape)
            {
                length *= axis;
                this.shape.Add(axis);
            }
            if (tmpitems.Count != length)
                throw new ArgumentException();
        }

        internal ndarray(List<int> shape, List<object> data)
        {
            this.shape = shape;
            this.tmpitems = data;
            this.length = data.Count;
        }

        private void UnpackData(List data)
        {
            for (int i = 0; i < data.Count; i++)
                if (data[i].GetType() == typeof(List))
                    UnpackData((List)data[i]);
                else
                    tmpitems.Add(data[i]);
        }

        private void GetShapeFromList(List data)
        {
            shape.Add(data.Count);
            if (data[0].GetType() == typeof(List))
            {
                GetShapeFromList((List)data[0]);
            }
        }

        private void SetLength()
        {
            length = 1;
            foreach (var axis in shape)
            {
                length *= axis;
            }
        }

        public int Length
        {
            get { return length; }
        }

        public PythonTuple Shape
        {
            get { return new PythonTuple(this.shape.ToArray()); }
            set { SetShape(value); }
        }

        private void SetShape(PythonTuple shape)
        {
            int len = 1;
            List<int> newShape = new List<int>();
            foreach (int i in shape)
            {
                len *= i;
                newShape.Add(i);
            }

            if (len != length)
                throw new ArgumentException("Not a valid shape");
            this.shape = newShape;
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return tmpitems.GetEnumerator();
        }

        public object __getitem__(params object[] index)
        {
            List<object> data = new List<object>(index);
            if (data.Count < shape.Count)
            {
                //sub ndarray
                //pad it with empty ':'
                int start = data.Count;
                for (int i = start; i < shape.Count; i++)
                    data.Add(new Slice(null));
            }
            List<IEnumerable<int>> indices = new List<IEnumerable<int>>();
            for (int i = 0; i < data.Count; i++)
                indices.Add(Indices(data[i], i + 1).Distinct());

            //get the new shape
            List<int> newShape = new List<int>();
            for (int i = 0; i < indices.Count; i++)
                newShape.Add(indices[i].Count());

            //check to see if there are multi-dimensional indexes
            while (indices.Count > 1)
            {
                var setA = indices[0];
                var setB = indices[1];
                indices.RemoveRange(0, 2);
                indices.Insert(0, CombineIndex(setA, setB));
            }

            if (indices[0].Count() == 1)
                return tmpitems[indices[0].ToList()[0]];

            var sliceData = from i in indices[0].ToList()
                            select tmpitems[i];

            ndarray ret = new ndarray(newShape, sliceData.ToList());
            return ret;
        }



        private int DimensionOffset(int dimension)
        {
            int off = 1;
            for (int i = dimension; i < shape.Count; i++)
                off *= shape[i];
            return off;
        }

        private IEnumerable<int> Indices(object selection, int dimension)
        {
            List<int> ind = new List<int>();
            int baseOffset = DimensionOffset(dimension);
            //check the type of the selection
            if (selection.GetType() == typeof(List))
            {
                //its a list and can contain aditional selection objects
                foreach (object sel in (List)selection)
                {
                    ind.AddRange(Indices(sel, dimension));
                }
            }
            else if (selection.GetType() == typeof(Slice))
            {
                //its a python slice operator
                ndslice sel = new ndslice((Slice)selection, shape[dimension - 
1]);
                foreach (int i in sel.GetIndices())
                    ind.Add(i * baseOffset);
            }
            else
            {
                //could be just a number
                int i = (int)selection;
                ind.Add(i * baseOffset);
            }

            return ind;
        }

        private IEnumerable<int> CombineIndex(IEnumerable<int> a, 
IEnumerable<int> b)
        {
            //var result = a.SelectMany(x => b.Select(y => x + y));
            var result = from x in a
                         from y in b
                         select (x + y);

            return result;
        }


        public ndarray __add__(int value)
        {
            List<object> tmp = new List<object>();
            for (int i = 0; i < length; i++)
                tmp.Add((int)tmpitems[i] + value);
            return new ndarray(shape, tmp);
        }


        public ndarray __add__(double value)
        {
            List<object> tmp = new List<object>();
            for (int i = 0; i < length; i++)
                tmp.Add(Convert.ToDouble(tmpitems[i]) + value);
            return new ndarray(shape, tmp);
        }

        public ndarray __add__(long value)
        {
            List<object> tmp = new List<object>();
            for (int i = 0; i < length; i++)
                tmp.Add((long)tmpitems[i] + value);
            return new ndarray(shape, tmp);
        }


        public int __len__()
        {
            return length;
        }


        public string __str__()
        {
            return GenerateString(0, 1);
        }

        private string GenerateString(int offset, int dimension)
        {
            int baseOffset = DimensionOffset(dimension);
            StringBuilder sb = new StringBuilder();
            List<string> tmp = new List<string>();
            //check if this is the last dimension
            if (dimension < shape.Count)
            {
                sb.Append("[");
                //call the other level
                for (int i = 0; i < shape[dimension - 1]; i++)
                    tmp.Add(GenerateString(i * baseOffset + offset, dimension + 
1));

                sb.Append(string.Join(",\n", tmp.ToArray()));
                sb.Append("]");
            }
            else
            {
                sb.Append("[");
                for (int i = 0; i < shape[dimension - 1]; i++)
                    tmp.Add(tmpitems[i * baseOffset + offset].ToString());

                sb.Append(string.Join(",\t", tmp.ToArray()));
                sb.Append("]");
            }
            return sb.ToString();
        }



        public List flatten()
        {
            List l = new List();
            l.extend(tmpitems);
            return l;
        }

        internal class ndslice
        {
            int start;
            int stop;
            int step;
            public ndslice(Slice slice, int length)
            {
                start = (slice.start == null) ? 0 : (int)slice.start;
                stop = (slice.stop == null) ? length : (int)slice.stop;
                step = (slice.step == null) ? 1 : (int)slice.step;

                if (start < 0) start += length;
                if (stop < 0) stop += length;
                if (stop > length) stop = length; //or throw an exception??
            }

            public int Start { get { return start; } }
            public int Stop { get { return stop; } }
            public int Step { get { return step; } }

            public IEnumerable GetIndices()
            {
                for (int i = start; i < stop; i+= step)
                    yield return i;
            }
        }


    }
}
_______________________________________________
Users mailing list
[email protected]
http://lists.ironpython.com/listinfo.cgi/users-ironpython.com

Reply via email to