Beispiel #1
0
        internal static void SetField(ndarray dest, NpyArray_Descr descr, int offset, object src)
        {
            // For char arrays pad the input string.
            if (dest.Dtype.Type == NPY_TYPECHAR.NPY_CHARLTR &&
                dest.ndim > 0 && src is String)
            {
                int ndimNew = (int)dest.Dim(dest.ndim - 1);
                int ndimOld = ((String)src).Length;

                if (ndimNew > ndimOld)
                {
                    src = ((String)src).PadRight(ndimNew, ' ');
                }
            }
            ndarray srcArray;

            if (src is ndarray)
            {
                srcArray = (ndarray)src;
            }
            else if (false)
            {
                // TODO: Not handling scalars.  See arrayobject.c:111
            }
            else
            {
                dtype src_dtype = new dtype(descr);
                srcArray = np.FromAny(src, src_dtype, 0, dest.ndim, NPYARRAYFLAGS.NPY_CARRAY, null);
            }
            NpyCoreApi.Incref(descr);
            if (numpyAPI.NpyArray_SetField(dest.core, descr, offset, srcArray.core) < 0)
            {
                NpyCoreApi.CheckError();
            }
        }
Beispiel #2
0
        public static dtype result_type(NPY_TYPES type_num)
        {
            var   return_type  = DefaultArrayHandlers.GetArrayHandler(type_num).MathOpFloatingType(UFuncOperation.divide);
            dtype result_dtype = NpyCoreApi.DescrFromType(return_type);

            return(result_dtype);
        }
Beispiel #3
0
        internal static ndarray FromPythonScalar(object src, dtype descr)
        {
            int       itemsize = descr.ElementSize;
            NPY_TYPES type     = descr.TypeNum;

            if (itemsize == 0 && NpyDefs.IsExtended(type))
            {
                int n = PythonOps.Length(src);
                if (type == NPY_TYPES.NPY_UNICODE)
                {
                    n *= 4;
                }
                descr             = new dtype(descr);
                descr.ElementSize = n;
            }

            ndarray result = NpyCoreApi.AllocArray(descr, 0, null, false);

            if (result.ndim > 0)
            {
                throw new ArgumentException("shape-mismatch on array construction");
            }

            result.Dtype.f.setitem(0, src, result.Array);
            return(result);
        }
Beispiel #4
0
            public static ndarray outer(NpyArray_Ops ops, dtype dtype, object a, object b, ndarray @out = null, int?axis = null)
            {
                var a1 = np.asanyarray(a);
                var b1 = np.asanyarray(b);


                List <npy_intp> destdims = new List <npy_intp>();

                foreach (var dim in a1.shape.iDims)
                {
                    destdims.Add(dim);
                }
                foreach (var dim in b1.shape.iDims)
                {
                    destdims.Add(dim);
                }



                ndarray dest = @out;

                if (dest == null)
                {
                    dest = np.empty(new shape(destdims), dtype: dtype != null ? dtype : a1.Dtype);
                }

                return(NpyCoreApi.PerformOuterOp(a1, b1, dest, ops));
            }
Beispiel #5
0
        internal static ndarray CheckFromAny(Object src, dtype descr, int minDepth,
                                             int maxDepth, NPYARRAYFLAGS requires, Object context)
        {
            if ((requires & NPYARRAYFLAGS.NPY_NOTSWAPPED) != 0)
            {
                if (descr == null && src is ndarray &&
                    !((ndarray)src).Dtype.IsNativeByteOrder)
                {
                    descr = new dtype(((ndarray)src).Dtype);
                }
                else if (descr != null && !descr.IsNativeByteOrder)
                {
                    // Descr replace
                }
                if (descr != null)
                {
                    descr.ByteOrder = '=';
                }
            }

            ndarray arr = np.FromAny(src, descr, minDepth, maxDepth, requires, context);

            if (arr != null && (requires & NPYARRAYFLAGS.NPY_ELEMENTSTRIDES) != 0 &&
                arr.ElementStrides == 0)
            {
                arr = arr.NewCopy(NPY_ORDER.NPY_ANYORDER);
            }
            return(arr);
        }
Beispiel #6
0
        private static bool can_cast(object from_, dtype to, string casting = "safe")
        {
            dtype from = null;

            if (from_ is dtype)
            {
                from = from_ as dtype;
            }
            else
            {
                try
                {
                    var arr = asanyarray(from_);
                    if (arr != null)
                    {
                        from = arr.Dtype;
                    }
                }
                catch (Exception ex)
                {
                    return(false);
                }
            }

            return(NpyCoreApi.CanCastTo(from, to));
        }
Beispiel #7
0
        public override string ToString()
        {
            string ret;

            if (this.HasNames)
            {
                Object lst = this.descr;
                ret = (lst != null) ? lst.ToString() : "<err>";

                ret = String.Format("('{0}', {1})", this.str, this.descr);
            }
            else if (this.HasSubarray)
            {
                dtype b = @base;
                if (!b.HasNames && !b.HasSubarray)
                {
                    ret = String.Format("('{0}',{1})", b.ToString(), shape);
                }
                else
                {
                    ret = String.Format("({0},{1})", b.ToString(), shape);
                }
            }
            else if (NpyDefs.IsFlexible(this.TypeNum) || !this.IsNativeByteOrder)
            {
                ret = this.str;
            }
            else
            {
                ret = this.name;
            }
            return(ret);
        }
Beispiel #8
0
        /// <summary>
        /// Performs a generic reduce or accumulate operation on an input array.
        /// A reduce operation reduces the number of dimensions of the input array
        /// by one where accumulate does not.  Accumulate stores in incremental
        /// accumulated values in the extra dimension.
        /// </summary>
        /// <param name="arr">Input array</param>
        /// <param name="indices">Used only for reduceat</param>
        /// <param name="axis">Axis to reduce</param>
        /// <param name="otype">Output type of the array</param>
        /// <param name="outArr">Optional output array</param>
        /// <param name="operation">Reduce/accumulate operation to perform</param>
        /// <returns>Resulting array, either outArr or a new array</returns>
        private Object GenericReduce(ndarray arr, ndarray indices, int axis,
                                     dtype otype, ndarray outArr, GenericReductionOp operation)
        {
            if (signature() != null)
            {
                throw new RuntimeException("Reduction is not defined on ufunc's with signatures");
            }
            if (nin != 2)
            {
                throw new ArgumentException("Reduce/accumulate only supported for binary functions");
            }
            if (nout != 1)
            {
                throw new ArgumentException("Reduce/accumulate only supported for functions returning a single value");
            }

            if (arr.ndim == 0)
            {
                throw new ArgumentTypeException("Cannot reduce/accumulate a scalar");
            }

            if (arr.IsFlexible || (otype != null && NpyDefs.IsFlexible(otype.TypeNum)))
            {
                throw new ArgumentTypeException("Cannot perform reduce/accumulate with flexible type");
            }

            return(NpyCoreApi.GenericReduction(this, arr, indices,
                                               outArr, axis, otype, operation));
        }
Beispiel #9
0
        public static ndarray asmatrix(object data, dtype dtype = null)
        {
            // Interpret the input as a matrix.

            // Unlike `matrix`, `asmatrix` does not make a copy if the input is already
            // a matrix or an ndarray.  Equivalent to ``matrix(data, copy = False)``.

            // Parameters
            // ----------
            // data: array_like
            //    Input data.
            //dtype : data - type
            //    Data - type of the output matrix.

            // Returns
            // ------ -
            // mat : matrix
            //     `data` interpreted as a matrix.

            // Examples
            // --------
            // >>> x = np.array([[1, 2], [3, 4]])

            // >>> m = np.asmatrix(x)

            // >>> x[0, 0] = 5

            // >>> m
            // matrix([[5, 2],
            //         [3, 4]])

            throw new NotImplementedException();
        }
Beispiel #10
0
 public bool Equals(dtype other)
 {
     if (other == null)
     {
         return(false);
     }
     return(this.core == other.core || NpyCoreApi.EquivTypes(this, other));
 }
Beispiel #11
0
        /// <summary>
        /// An array with ones at and below the given diagonal and zeros elsewhere.
        /// </summary>
        /// <param name="N">Number of rows in the array.</param>
        /// <param name="M">Number of columns in the array.</param>
        /// <param name="k">The sub-diagonal at and below which the array is filled.'k' = 0 is the main diagonal, while 'k' LT 0 is below it, and 'k' GT 0 is above.The default is 0.</param>
        /// <param name="dtype">Data type of the returned array.  The default is float.</param>
        /// <returns></returns>
        public static ndarray tri(int N, int?M = null, int k = 0, dtype dtype = null)
        {
            /*
             * An array with ones at and below the given diagonal and zeros elsewhere.
             *
             * Parameters
             * ----------
             * N : int
             *  Number of rows in the array.
             * M : int, optional
             *  Number of columns in the array.
             *  By default, `M` is taken equal to `N`.
             * k : int, optional
             *  The sub-diagonal at and below which the array is filled.
             *  `k` = 0 is the main diagonal, while `k` < 0 is below it,
             *  and `k` > 0 is above.  The default is 0.
             * dtype : dtype, optional
             *  Data type of the returned array.  The default is float.
             *
             * Returns
             * -------
             * tri : ndarray of shape (N, M)
             *  Array with its lower triangle filled with ones and zero elsewhere;
             *  in other words ``T[i,j] == 1`` for ``i <= j + k``, 0 otherwise.
             *
             * Examples
             * --------
             * >>> np.tri(3, 5, 2, dtype=int)
             * array([[1, 1, 1, 0, 0],
             *     [1, 1, 1, 1, 0],
             *     [1, 1, 1, 1, 1]])
             *
             * >>> np.tri(3, 5, -1)
             * array([[ 0.,  0.,  0.,  0.,  0.],
             *     [ 1.,  0.,  0.,  0.,  0.],
             *     [ 1.,  1.,  0.,  0.,  0.]])
             */

            if (dtype == null)
            {
                dtype = np.Float32;
            }

            if (M == null)
            {
                M = N;
            }


            ndarray m = ufunc.outer(UFuncOperation.greater_equal, np.Bool, arange(N, dtype: _min_int(0, N)),
                                    arange(-k, M - k, dtype: _min_int(-k, (int)M - k)));

            // Avoid making a copy if the requested type is already bool
            m = m.astype(dtype, copy: false);

            return(m);
        }
Beispiel #12
0
        internal static ndarray FromScalar(ScalarGeneric scalar, dtype descr = null)
        {
            ndarray arr = scalar.ToArray();

            if (descr != null && !NpyCoreApi.EquivTypes((dtype)scalar.dtype, descr))
            {
                arr = NpyCoreApi.CastToType(arr, descr, arr.IsFortran);
            }
            return(arr);
        }
Beispiel #13
0
 // todo: big task to reimplement this.
 public static dtype promote_types(dtype type1, dtype type2)
 {
     if (type1.TypeNum < type2.TypeNum)
     {
         return(type2);
     }
     else
     {
         return(type1);
     }
 }
Beispiel #14
0
        public static ndarray dot(object o1, object o2)
        {
            dtype d = FindArrayType(asanyarray(o1), null);

            d = FindArrayType(asanyarray(o2), d);

            ndarray a1 = np.FromAny(o1, d, flags: NPYARRAYFLAGS.NPY_ALIGNED);
            ndarray a2 = np.FromAny(o2, d, flags: NPYARRAYFLAGS.NPY_ALIGNED);

            return(NpyCoreApi.MatrixProduct(a1, a2, d.TypeNum));
        }
Beispiel #15
0
        private static dtype FindArrayReturn(dtype chktype, dtype minitype)
        {
            dtype result = NpyCoreApi.SmallType(chktype, minitype);

            if (result.TypeNum == NPY_TYPES.NPY_VOID &&
                minitype.TypeNum != NPY_TYPES.NPY_VOID)
            {
                result = NpyCoreApi.DescrFromType(NPY_TYPES.NPY_OBJECT);
            }
            return(result);
        }
Beispiel #16
0
        /// <summary>
        /// Dot product of two arrays.
        /// </summary>
        /// <param name="a">input array</param>
        /// <param name="b">input array</param>
        /// <returns></returns>
        public static ndarray dot(object a, object b)
        {
            dtype d = FindArrayType(asanyarray(a), null);

            d = FindArrayType(asanyarray(b), d);

            ndarray arr1 = np.FromAny(a, d, flags: NPYARRAYFLAGS.NPY_ALIGNED);
            ndarray arr2 = np.FromAny(b, d, flags: NPYARRAYFLAGS.NPY_ALIGNED);

            return(NpyCoreApi.MatrixProduct(arr1, arr2, d.TypeNum));
        }
Beispiel #17
0
        private static ndarray ndArrayFromMD(Array ssrc, NPY_TYPES type_num, int ndim)
        {
            npy_intp [] newshape = new npy_intp[ndim];
            for (int i = 0; i < ndim; i++)
            {
                newshape[i] = ssrc.GetLength(i);
            }

            dtype WantedDType = NpyCoreApi.DescrFromType(type_num);

            return(np.array(new VoidPtr(ArrayFromMD(ssrc, type_num), type_num), dtype: WantedDType).reshape(newshape));
        }
Beispiel #18
0
        private static ndarray reshape_uniq(ndarray uniq, int axis, dtype orig_dtype, npy_intp[] orig_shape)
        {
            uniq = uniq.view(orig_dtype);

            npy_intp[] orig_shape_adjusted = new npy_intp[orig_shape.Length];
            Array.Copy(orig_shape, 0, orig_shape_adjusted, 0, orig_shape.Length);
            orig_shape_adjusted[0] = -1;

            uniq = uniq.reshape(new shape(orig_shape_adjusted));
            uniq = np.swapaxes(uniq, 0, axis);
            return(uniq);
        }
Beispiel #19
0
            internal static ndarray reduce(NpyArray_Ops ops, object a, int axis = 0, dtype dtype = null, ndarray @out = null, bool keepdims = false)
            {
                ndarray arr = asanyarray(a);

                if (arr == null)
                {
                    throw new ValueError("unable to convert a to ndarray");
                }

                NPY_TYPES rtype = dtype != null ? dtype.TypeNum : arr.Dtype.TypeNum;

                return(NpyCoreApi.PerformReduceOp(arr, axis, ops, rtype, @out, keepdims));
            }
Beispiel #20
0
        public static dtype result_type(dtype a1, dtype a2, object type_suggestion = null)
        {
            if (a1.IsDecimal || a2.IsDecimal)
            {
                return(np.Decimal);
            }

            if (a1.IsComplex || a1.IsComplex)
            {
                return(np.Complex);
            }

            return(np.Float64);
        }
Beispiel #21
0
        private static ndarray FromScalar(object src, dtype descr, object context)
        {
            npy_intp[] dims = new npy_intp[1] {
                1
            };
            ndarray result = NpyCoreApi.AllocArray(descr, 1, dims, false);

            if (result.ndim != 1)
            {
                throw new ArgumentException("shape-mismatch on array construction");
            }

            result.Dtype.f.setitem(0, src, result.Array);
            return(result);
        }
Beispiel #22
0
        internal static ndarray FromNestedList(object src, dtype descr, bool fortran)
        {
            npy_intp[] dims = new npy_intp[NpyDefs.NPY_MAXDIMS];


            int nd = ObjectDepthAndDimension(src, dims, 0, NpyDefs.NPY_MAXDIMS);

            if (nd == 0)
            {
                return(FromPythonScalar(src, descr));
            }
            ndarray result = NpyCoreApi.AllocArray(descr, nd, dims, fortran);

            AssignToArray(src, result);
            return(result);
        }
Beispiel #23
0
        /// <summary>
        /// Builds an array from a sequence of objects.  The elements of the sequence
        /// can also be sequences in which case this function recursively walks the
        /// nested sequences and builds an n dimentional array.
        ///
        /// IronPython tuples and lists work as sequences.
        /// </summary>
        /// <param name="src">Input sequence</param>
        /// <param name="descr">Desired array element type or null to determine automatically</param>
        /// <param name="fortran">True if array should be Fortran layout, false for C</param>
        /// <param name="minDepth"></param>
        /// <param name="maxDepth"></param>
        /// <returns>New array instance</returns>
        internal static ndarray FromIEnumerable(IEnumerable <Object> src, dtype descr,
                                                bool fortran, int minDepth, int maxDepth)
        {
            ndarray result = null;


            if (descr == null)
            {
                descr = FindArrayType(src, null, NpyDefs.NPY_MAXDIMS);
            }

            int itemsize = descr.ElementSize;

            NPY_TYPES type         = descr.TypeNum;
            bool      checkIt      = true;
            bool      stopAtString =
                type != NPY_TYPES.NPY_STRING ||
                descr.Type == (char)NPY_TYPECHAR.NPY_STRINGLTR;
            bool stopAtTuple = false;

            int numDim = DiscoverDepth(src, NpyDefs.NPY_MAXDIMS + 1, stopAtString, stopAtTuple);

            if (numDim == 0)
            {
                return(FromPythonScalar(src, descr));
            }
            else
            {
                if (maxDepth > 0 && type == NPY_TYPES.NPY_OBJECT &&
                    numDim > maxDepth)
                {
                    numDim = maxDepth;
                }
                if (maxDepth > 0 && numDim > maxDepth ||
                    minDepth > 0 && numDim < minDepth)
                {
                    throw new ArgumentException("Invalid number of dimensions.");
                }

                npy_intp[] dims = new npy_intp[numDim];
                DiscoverDimensions(src, numDim, dims, 0, checkIt);

                result = NpyCoreApi.AllocArray(descr, numDim, dims, fortran);
                AssignToArray(src, result);
            }
            return(result);
        }
Beispiel #24
0
        /// <summary>
        /// Given some object and an optional minimum type, returns the appropriate type descriptor.
        /// Equivalent to _array_find_type in common.c of CPython interface.
        /// </summary>
        /// <param name="src">Source object</param>
        /// <param name="minitype">Minimum type, or null if any</param>
        /// <param name="max">Maximum dimensions</param>
        /// <returns>Type descriptor fitting requirements</returns>
        internal static dtype FindArrayType(Object src, dtype minitype, int max = NpyDefs.NPY_MAXDIMS)
        {
            dtype chktype = null;

            if (src.GetType().IsArray)
            {
                if (src is ndarray[])
                {
                    ndarray[] arr1 = src as ndarray[];
                    src = arr1[0];
                }
            }

            if (src is ndarray)
            {
                chktype = ((ndarray)src).Dtype;
                if (minitype == null)
                {
                    return(chktype);
                }
                else
                {
                    return(FindArrayReturn(chktype, minitype));
                }
            }

            if (minitype == null)
            {
                minitype = NpyCoreApi.DescrFromType(NPY_TYPES.NPY_BOOL);
            }
            if (max < 0)
            {
                chktype = UseDefaultType(src);
                return(FindArrayReturn(chktype, minitype));
            }

            chktype = FindScalarType(src);
            if (chktype != null)
            {
                return(FindArrayReturn(chktype, minitype));
            }


            chktype = UseDefaultType(src);
            return(FindArrayReturn(chktype, minitype));
        }
Beispiel #25
0
        private Dictionary <string, object> GetFieldsDict()
        {
            Dictionary <string, object> ret;

            if (!HasNames)
            {
                ret = null;
            }
            else
            {
                NpyDict_Iter iter = null;
                NpyDict      dict = core.fields;
                ret = new Dictionary <string, object>();
                try
                {
                    NpyDict_KVPair KVPair = new NpyDict_KVPair();
                    iter = NpyCoreApi.NpyDict_AllocIter();
                    while (NpyCoreApi.NpyDict_Next(dict, iter, KVPair))
                    {
                        string key = (string)KVPair.key;
                        NpyArray_DescrField value = (NpyArray_DescrField)KVPair.value;
                        PythonTuple         t;

                        dtype d = new dtype(value.descr);
                        if (value.title == null)
                        {
                            t = new PythonTuple(new Object[] { d, value.offset });
                        }
                        else
                        {
                            t = new PythonTuple(new Object[] { d, value.offset, value.title });
                        }
                        ret.Add(key, t);
                    }
                }
                finally
                {
                    NpyCoreApi.NpyDict_FreeIter(iter);
                }
            }
            return(ret);
        }
Beispiel #26
0
        internal static void FillObjects(ndarray arr, object o)
        {
            dtype d = arr.Dtype;

            if (d.IsObject)
            {
                if (d.HasNames)
                {
                    foreach (string name in d.Names)
                    {
                        ndarray view = NpyCoreApi.GetField(arr, name);
                        FillObjects(view, o);
                    }
                }
                else
                {
                    NpyCoreApi.FillWithObject(arr, o);
                }
            }
        }
Beispiel #27
0
        internal static ndarray[] ConvertToCommonType(IEnumerable <object> objs)
        {
            // Determine the type and size;
            // TODO: Handle scalars correctly.
            long  n      = 0;
            dtype intype = null;

            foreach (object o in objs)
            {
                intype = np.FindArrayType(o, intype, NpyDefs.NPY_MAXDIMS);
                ++n;
            }

            if (n == 0)
            {
                throw new ArgumentException("0-length sequence");
            }

            // Convert items to array objects
            return(objs.Select(x => np.FromAny(x, intype, 0, 0, NPYARRAYFLAGS.NPY_CARRAY)).ToArray());
        }
Beispiel #28
0
        /// <summary>
        /// Matrix product of two arrays.
        /// </summary>
        /// <param name="o1"></param>
        /// <param name="o2"></param>
        /// <returns></returns>
        public static ndarray MatrixProduct(object o1, object o2)
        {
            dtype d = FindArrayType(o1, null);

            d = FindArrayType(o2, d);

            ndarray a1 = np.FromAny(o1, d, flags: NPYARRAYFLAGS.NPY_ALIGNED);
            ndarray a2 = np.FromAny(o2, d, flags: NPYARRAYFLAGS.NPY_ALIGNED);

            if (a1.ndim == 0)
            {
                return(EnsureAnyArray((a1.item() as ndarray) * a2));
            }
            else if (a2.ndim == 0)
            {
                return(EnsureAnyArray(a1 * (a2.item() as ndarray)));
            }
            else
            {
                return(NpyCoreApi.MatrixProduct(a1, a2, d.TypeNum));
            }
        }
Beispiel #29
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="dest"></param>
        /// <param name="descr"></param>
        /// <param name="offset"></param>
        /// <param name="src"></param>
        internal static void SetField(ndarray dest, NpyArray_Descr descr, int offset, object src)
        {
            ndarray srcArray;

            if (src is ndarray)
            {
                srcArray = (ndarray)src;
            }
            else if (false)
            {
                // TODO: Not handling scalars.  See arrayobject.c:111
            }
            else
            {
                dtype src_dtype = new dtype(descr);
                srcArray = np.FromAny(src, src_dtype, 0, dest.ndim, NPYARRAYFLAGS.NPY_CARRAY, null);
            }
            NpyCoreApi.Incref(descr);
            if (numpyAPI.NpyArray_SetField(dest.core, descr, offset, srcArray.core) < 0)
            {
                NpyCoreApi.CheckError();
            }
        }
Beispiel #30
0
        public static uniqueData unique(ndarray ar, bool return_index = false, bool return_inverse = false, bool return_counts = false, int?axis = null)
        {
            /*
             * Find the unique elements of an array.
             *
             * Returns the sorted unique elements of an array. There are three optional
             * outputs in addition to the unique elements:
             *
             * the indices of the input array that give the unique values
             * the indices of the unique array that reconstruct the input array
             * the number of times each unique value comes up in the input array
             *
             * Parameters
             * ----------
             * ar : array_like
             *  Input array. Unless `axis` is specified, this will be flattened if it
             *  is not already 1-D.
             * return_index : bool, optional
             *  If True, also return the indices of `ar` (along the specified axis,
             *  if provided, or in the flattened array) that result in the unique array.
             * return_inverse : bool, optional
             *  If True, also return the indices of the unique array (for the specified
             *  axis, if provided) that can be used to reconstruct `ar`.
             * return_counts : bool, optional
             *  If True, also return the number of times each unique item appears
             *  in `ar`.
             *
             *  .. versionadded:: 1.9.0
             *
             * axis : int or None, optional
             *  The axis to operate on. If None, `ar` will be flattened. If an integer,
             *  the subarrays indexed by the given axis will be flattened and treated
             *  as the elements of a 1-D array with the dimension of the given axis,
             *  see the notes for more details.  Object arrays or structured arrays
             *  that contain objects are not supported if the `axis` kwarg is used. The
             *  default is None.
             *
             *  .. versionadded:: 1.13.0
             *
             * Returns
             * -------
             * unique : ndarray
             *  The sorted unique values.
             * unique_indices : ndarray, optional
             *  The indices of the first occurrences of the unique values in the
             *  original array. Only provided if `return_index` is True.
             * unique_inverse : ndarray, optional
             *  The indices to reconstruct the original array from the
             *  unique array. Only provided if `return_inverse` is True.
             * unique_counts : ndarray, optional
             *  The number of times each of the unique values comes up in the
             *  original array. Only provided if `return_counts` is True.
             */

            ar = np.asanyarray(ar);
            if (axis == null)
            {
                var ret = _unique1d(ar, return_index, return_inverse, return_counts);
                return(ret);
            }

            // axis was specified and not None
            try
            {
                ar = swapaxes(ar, axis.Value, 0);
            }
            catch (Exception ex)
            {
                string Error = ex.Message;
                throw new Exception(Error);
            }

            npy_intp[] orig_shape = ar.dims;
            dtype      orig_dtype = ar.Dtype;

            ar = ar.reshape(new shape((int)orig_shape[0], -1));
            ar = np.ascontiguousarray(ar);

            ndarray consolidated = null;

            try
            {
                // todo: this nasty code needs to be implemented in order for this to work correctly.
                // dtype = [('f{i}'.format(i = i), ar.dtype) for i in range(ar.shape[1])]
                // consolidated = ar.view(dtype);
                consolidated = ar.view(ar.Dtype);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }

            var output = _unique1d(consolidated, return_index, return_inverse, return_counts);

            output.data = reshape_uniq(output.data, axis.Value, orig_dtype, orig_shape);

            return(output);
        }