/// <summary> /// Generates an NdArray with all elements set to a random value /// </summary> /// <param name="shape">The shape of the generated array</param> /// <returns>An NdArray with all elements set to a random value</returns> public virtual NdArray <T> Random(Shape shape) { var x = new NdArray <T>(shape); UFunc.Apply <T, TRand>(new TRand(), x); return(x); }
/// <summary> /// Repeats elements of the array /// </summary> /// <param name="repeats">The number of repeats to perform</param> /// <param name="axis">The axis to repeat, if not speficied, repeat is done on a flattened array</param> /// <returns>A repeated copy of the input data</returns> public NdArray <T> Repeat(long repeats, long?axis = null) { long real_axis = axis.HasValue ? (axis.Value < 0 ? this.Shape.Dimensions.LongLength - (axis.Value + 1) : (axis.Value + 1)) : this.Shape.Dimensions.LongLength; //First we add a new axis so all elements are in their own dimension var lv = this.Subview(Range.NewAxis, real_axis); //Then we extend the element dimension, and make the shapes match long[] targetDims = lv.Shape.Dimensions.Select(x => x.Length).ToArray(); targetDims[real_axis] = repeats; var tp = Shape.ToBroadcastShapes(lv.Shape, new Shape(targetDims)); //And then we can just copy data as normal var res = UFunc.Apply <T, CopyOp <T> >(lv.Reshape(tp.Item1), new NdArray <T>(tp.Item2)); //With no axis specified, we return a flat view if (!axis.HasValue) { return(new NdArray <T>(res.m_data)); } else { //With a specified axis, we return a reshaped array long[] newDims = this.Shape.Dimensions.Select(x => x.Length).ToArray(); newDims[real_axis - 1] = repeats * newDims[real_axis - 1]; return(res.Reshape(newDims)); } }
/// <summary> /// Sets all elements in the view to a specific value /// </summary> /// <param name="value">The value to set the elements to</param> public void Set(T value) { var tmp = new NdArray <T>(value); tmp = tmp.Reshape(Shape.ToBroadcastShapes(tmp.Shape, this.Shape).Item1); UFunc.Apply <T, CopyOp <T> >(tmp, this); }
/// <summary> /// Generates an NdArray with sequential integers, starting with zero /// </summary> /// <param name="shape">The shape of the generated array</param> /// <returns>A shaped NdArray with sequential integers, starting with zero</returns> public NdArray <T> Range(Shape shape) { var x = new NdArray <T>(shape); UFunc.Apply <T, TRange>(new TRange(), x); return(x); }
/// <summary> /// Generates an NdArray with all elements set to a random value /// </summary> /// <param name="size">The length of the generated array</param> /// <returns>An NdArray with all elements set to a random value</returns> public virtual NdArray <T> Random(long size) { var x = new NdArray <T>(new Shape(size)); UFunc.Apply <T, TRand>(new TRand(), x); return(x); }
/// <summary> /// Generates an NdArray with sequential integers, starting with zero /// </summary> /// <param name="size">The length of the generated array</param> /// <returns>An NdArray with sequential integers, starting with zero</returns> public NdArray <T> Range(long size) { var x = new NdArray <T>(new Shape(size)); UFunc.Apply <T, TRange>(new TRange(), x); return(x); }
/// <summary> /// Gets a subview on the array, collapses all single dimensions /// </summary> /// <param name="ranges">The range get the view from</param> /// <returns>A view on the selected element</returns> public NdArray <T> this[params Range[] ranges] { get { return(this.Subview(ranges, true)); } set { NdArray <T> lv = this[ranges]; var broadcastShapes = Shape.ToBroadcastShapes(value.Shape, lv.Shape); UFunc.Apply <T, NumCIL.CopyOp <T> >(value.Reshape(broadcastShapes.Item1), lv.Reshape(broadcastShapes.Item2)); } }
/// <summary> /// Returns a transposed view of this array. If <paramref name="out"/> is supplied, the contents are copied into that array. /// </summary> /// <param name="out">Optional output array</param> /// <returns>A transposed view or copy</returns> public NdArray <T> Transpose(NdArray <T> @out = null) { if (this.Shape.Dimensions.LongLength == 1) { return(new NdArray <T>(this)); } //Optimal case, just reshape the array if (@out == null) { return(this.Reshape(new Shape(this.Shape.Dimensions.Reverse().ToArray()))); } var lv = this.Reshape(new Shape(this.Shape.Dimensions.Select(x => x.Length).Reverse().ToArray())); UFunc.Apply <T, CopyOp <T> >(lv, @out); return(@out); }
/// <summary> /// Gets a subview on the array /// </summary> /// <param name="index">The element to get the view from</param> /// <returns>A view on the selected element</returns> public NdArray <T> this[params long[] index] { get { NdArray <T> v = this; foreach (long n in index) { v = v.Subview(n); } return(v); } set { NdArray <T> lv = this[index]; //Self-assignment if (lv.Shape.Equals(value.Shape) && value.m_data == this.m_data) { return; } if (lv.Shape.Dimensions.Length != value.Shape.Dimensions.Length) { throw new Exception("Cannot assign incompatible arrays"); } for (long i = 0; i < lv.Shape.Dimensions.Length; i++) { if (lv.Shape.Dimensions[i].Length != value.Shape.Dimensions[i].Length) { throw new Exception("Cannot assign incompatible arrays"); } } UFunc.Apply <T, NumCIL.CopyOp <T> >(value, lv); } }
/// <summary> /// Concatenates multiple arrays into a single array, joined at the axis /// </summary> /// <param name="axis">The axis to join at</param> /// <param name="args">The arrays to join</param> /// <returns>The joined array</returns> public static NdArray <T> Concatenate(NdArray <T>[] args, long axis = 0) { if (args == null) { throw new ArgumentNullException("args"); } if (args.LongLength == 1) { return(args[0]); } Shape basicShape = args[0].Shape.Plain; NdArray <T>[] ext = new NdArray <T> [args.LongLength]; foreach (var a in args) { if (a.Shape.Elements != 1) { basicShape = a.Shape.Plain; break; } } for (long i = 0; i < args.LongLength; i++) { var lv = args[i]; while (lv.Shape.Dimensions.LongLength <= axis) { lv = lv.Subview(Range.NewAxis, 0); } ext[i] = lv; } long newAxisSize = 0; foreach (var a in ext) { newAxisSize += a.Shape.Dimensions[axis].Length; } long[] dims = basicShape.Plain.Dimensions.Select(x => x.Length).ToArray(); dims[Math.Min(axis, dims.LongLength - 1)] = newAxisSize; var res = new NdArray <T>(new Shape(dims)); var reslv = res; while (reslv.Shape.Dimensions.LongLength <= axis) { reslv = reslv.Subview(Range.NewAxis, 0); } foreach (var a in ext) { if (a.Shape.Dimensions.LongLength != reslv.Shape.Dimensions.LongLength) { throw new Exception(string.Format("Incompatible shapes, size {0} vs {1}", a.Shape.Dimensions.LongLength, reslv.Shape.Dimensions.LongLength)); } for (long i = 0; i < dims.LongLength; i++) { if (i != axis && reslv.Shape.Dimensions[i].Length != a.Shape.Dimensions[i].Length) { throw new Exception(string.Format("Incompatible shapes, sizes in dimension {0} is {1} vs {2}", i, a.Shape.Dimensions[i].Length, reslv.Shape.Dimensions[i].Length)); } } } long startOffset = 0; foreach (NdArray <T> a in ext) { long endOffset = startOffset + a.Shape.Dimensions[axis].Length; var lv = reslv.Subview(new Range(startOffset, endOffset), axis); UFunc.Apply <T, CopyOp <T> >(a, lv); startOffset = endOffset; } return(res); }
/// <summary> /// Repeats elements of the array /// </summary> /// <param name="repeats">The number of repeats to perform in each axis</param> /// <param name="axis">The axis to repeat, if not specified, repeat is done on a flattened array</param> /// <returns>A repeated copy of the input data</returns> public NdArray <T> Repeat(long[] repeats, long?axis = null) { long real_axis = axis.HasValue ? (axis.Value < 0 ? this.Shape.Dimensions.LongLength - axis.Value : axis.Value) : this.Shape.Dimensions.LongLength; if (!axis.HasValue) { //Inefficient because we need to access each element long elements = this.Shape.Elements; if (elements % repeats.LongLength != 0) { throw new ArgumentException(string.Format("The repeats array has length {0} and is not broadcast-able to length {1}", repeats.LongLength, elements), "repeats"); } //We need to be able to address each element individually, // so we do not use tricks stride tricks and // just copy each element individually long resultSize = 0; for (long i = 0; i < elements; i++) { resultSize += repeats[i % repeats.LongLength]; } T[] result = new T[resultSize]; long[] counters = new long[this.Shape.Dimensions.LongLength]; long[] limits = this.Shape.Dimensions.Select(x => x.Length).ToArray(); var va = this.Value; long resCount = 0; //The we remove all the outer axis definitions, but preserve the stride for each element for (long i = 0; i < elements; i++) { T value = va[counters]; for (long j = 0; j < repeats[i % repeats.LongLength]; j++) { result[resCount++] = value; } //Basically a ripple carry adder long p = counters.LongLength - 1; while (++counters[p] == limits[p] && p > 0) { counters[p] = 0; p--; } } return(new NdArray <T>(result)); } else { if (this.Shape.Dimensions[real_axis].Length % repeats.LongLength != 0) { throw new ArgumentException(string.Format("The repeats array has length {0} and is not broadcast-able to length {1}", repeats.LongLength, this.Shape.Dimensions[real_axis].Length), "repeats"); } long resultSize = 1; if (repeats.LongLength != this.Shape.Dimensions[real_axis].Length) { long[] tmp = new long[this.Shape.Dimensions[real_axis].Length]; for (long i = 0; i < tmp.LongLength; i++) { tmp[i] = repeats[i % repeats.LongLength]; } repeats = tmp; } long extendedSize = repeats.Aggregate((a, b) => a + b); for (long i = 0; i < this.Shape.Dimensions.LongLength; i++) { if (i == real_axis) { resultSize *= extendedSize; } else { resultSize *= this.Shape.Dimensions[i].Length; } } long[] resultDims = this.Shape.Dimensions.Select(x => x.Length).ToArray(); resultDims[real_axis] = extendedSize; var resultShape = new Shape(resultDims); var result = new NdArray <T>(resultShape); long curStart = 0; for (long i = 0; i < repeats.LongLength; i++) { var lv = this.Subview(Range.El(i), real_axis); var xv = result.Subview(new Range(curStart, curStart + repeats[i]), real_axis); var broadcastShapes = Shape.ToBroadcastShapes(lv.Shape, xv.Shape); UFunc.Apply <T, CopyOp <T> >(lv.Reshape(broadcastShapes.Item1), xv.Reshape(broadcastShapes.Item2)); curStart += repeats[i]; } return(result); } }
/// <summary> /// Returns a copy of the underlying data, shaped as this view /// </summary> /// <returns>A copy of the view data</returns> public NdArray <T> Clone() { return(UFunc.Apply <T, CopyOp <T> >(this)); }
/// <summary> /// Sets the values in this view to values from another view, i.e. copies data /// </summary> /// <param name="value">The data to assign to this view</param> public void Set(NdArray <T> value) { var broadcastShapes = Shape.ToBroadcastShapes(value.Shape, this.Shape); UFunc.Apply <T, NumCIL.CopyOp <T> >(value.Reshape(broadcastShapes.Item1), this.Reshape(broadcastShapes.Item2)); }