/// <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 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> /// 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)); }
public static void RunTests() { var an = Generate.Empty(2000); var bn = Generate.Ones(2000); var cn = Generate.Empty(2000); var dn = Generate.Ones(2000); var an0 = an.Value[0]; var bn0 = bn.Value[0]; if (bn0 != 1) { throw new Exception("Error in accessor"); } cn.Value[0] = 1; dn.Value[0] = 2; var cn0 = cn.Value[0]; var dn0 = dn.Value[0]; if (cn0 != 1 || dn0 != 2) { throw new Exception("Error in accessor"); } var test = Generate.Range(3) * 4; test.Transpose(); Shape s = new Shape( new long[] { 2, 1, 2, 3 }, //Dimension sizes 6, //Offset new long[] { 18, 18, 6, 1 } //Strides ); var a = Generate.Range(s.Length); var b = a.Reshape(s); var c = b[1][0][1]; var d = c[2]; var e = b.Flatten(); if (e.AsArray().LongLength != 12 || e.AsArray()[3] != 12) { throw new Exception("Failure in flatten"); } List <T> fln = new List <T>(b[1, 0, 1].Value); if (fln.Count != 3) { throw new Exception("Failure in basic test 1"); } if (fln[0] != 30) { throw new Exception("Failure in basic test 2"); } if (fln[1] != 31) { throw new Exception("Failure in basic test 3"); } if (fln[2] != 32) { throw new Exception("Failure in basic test 4"); } T n = b.Value[1, 0, 1, 2]; if (n != 32) { throw new Exception("Failure in basic test 5"); } if (c.Value[2] != 32) { throw new Exception("Failure in basic test 6"); } if (c.Value[0] != 30) { throw new Exception("Failure in basic test 7"); } if (c.Value[1] != 31) { throw new Exception("Failure in basic test 8"); } if (b.Sum() != 228) { throw new Exception("Failure in basic test 9"); } var r1 = Generate.Range(12).Reshape(new long[] { 2, 1, 2, 3 }); if (!Equals(r1.AsArray(), new T[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 })) { throw new Exception("Failure in basic test 10"); } var r2 = r1.Reduce <Add>(0); //if (!Equals(r2.AsArray(), new T[] { 6, 8, 10, 12, 14, 16 })) throw new Exception("Failure in basic test 11"); r2 = r1.Reduce <Add>(1); var xxx = r2.AsArray(); if (!Equals(xxx, new T[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 })) { throw new Exception("Failure in basic test 12"); } r2 = r1.Reduce <Add>(2); var yyy = r2.AsArray(); if (!Equals(yyy, new T[] { 3, 5, 7, 15, 17, 19 })) { throw new Exception("Failure in basic test 13"); } //r2 = Add.Reduce(r1, 3); Console.WriteLine("Running problem test"); r2 = r1.Reduce <Add>(3); var nnn = r2.AsArray(); if (!Equals(nnn, new T[] { 3, 12, 21, 30 })) { throw new Exception(string.Format("Failure in basic test 14: {0}", string.Join(", ", nnn.Select(x => x.ToString())))); } var r3 = b.Reduce <Add>(); if (!Equals(r3.AsArray(), new T[] { 30, 32, 34, 42, 44, 46 })) { throw new Exception("Failure in basic test 15"); } var x1 = Generate.Range(12).Reshape(new long[] { 4, 3 }); var x2 = Generate.Range(3); var x3 = x1 + x2; var sqrd = x3.Sqrt(); sqrd *= sqrd; sqrd = sqrd.Round(); sqrd += 4; sqrd++; if (UFunc.Reduce <T, Add>(UFunc.Reduce <T, Add>(sqrd, 0)).Value[0] != 138) { throw new Exception("Failure in basic arithmetics"); } if (UFunc.Reduce <T, Add>(UFunc.Reduce <T, Add>(sqrd, 1)).Value[0] != 138) { throw new Exception("Failure in basic arithmetics"); } var x5 = sqrd.Apply((x) => x % 2 == 0 ? x : -x); if (!Equals(x5.AsArray(), new T[] { -5, -7, -9, 8, 10, 12, -11, -13, -15, 14, 16, 18 })) { throw new Exception("Failure in basic test 16"); } NumCIL.UFunc.Apply <T, Add>(x1, x2, x3); NumCIL.Double.NdArray x4 = (NumCIL.Double.NdArray)x3; if (!Equals(x4.AsArray(), new double[] { 0, 2, 4, 3, 5, 7, 6, 8, 10, 9, 11, 13 })) { throw new Exception("Failure in basic test 17"); } var x6 = Generate.Range(6).Reshape(new long[] { 2, 3 }); var x7 = x6.Reduce <Add>(); var rx7 = x7.AsArray(); if (!Equals(rx7, new T[] { 3, 5, 7 })) { throw new Exception(string.Format("Failure in basic test: [{0}]", string.Join(", ", rx7.Select(x => x.ToString()).ToArray()))); } var x8 = Generate.Range(10) * 0.5f; var rx8 = x8.Reduce <Add>().Value[0]; if (rx8 != 22.5) { throw new Exception(string.Format("Failure in broadcast multiply 1: {0}", rx8)); } var x9 = Mul.Apply(Generate.Range(10), 0.5f); var rx9 = x9.Reduce <Add>().Value[0]; if (rx9 != 22.5) { throw new Exception(string.Format("Failure in broadcast multiply 2: {0}", rx9)); } var x10 = 5 - Generate.Range(10); var x11 = Generate.Range(10) - 5; if (x10.Sum() != 5 || x11.Sum() != -5) { throw new Exception("Failure in scalar rhs/lhs"); } var n0 = Generate.Range(4); var n1 = n0[new Range(1, 4)]; var n2 = n0[new Range(0, 3)]; var n3 = n1 - n2; if (n3.Reduce <Add>().Value[0] != 3) { throw new Exception("Failure in basic slicing"); } var z0 = Generate.Range(new long[] { 2, 2, 3 }); var z1 = z0[Range.All, Range.All, Range.El(1)]; var z2 = z0[Range.All, Range.El(1), Range.El(1)]; var z3 = z0[Range.El(1), Range.El(1), Range.All]; var z4 = z0[Range.El(0), Range.El(1), Range.El(1)]; var z5 = z0[Range.El(0)]; if (z1.Shape.Elements != 4) { throw new Exception("Reduced range failed"); } if (z2.Shape.Elements != 2 || z2.Shape.Dimensions.LongLength != 1) { throw new Exception("Reduced range failed"); } if (z3.Shape.Elements != 3 || z3.Shape.Dimensions.LongLength != 1) { throw new Exception("Reduced range failed"); } if (z4.Shape.Elements != 1 || z4.Shape.Dimensions.LongLength != 1) { throw new Exception("Reduced range failed"); } if (z5.Shape.Elements != 6 || z5.Shape.Dimensions.LongLength != 2) { throw new Exception("Reduced range failed"); } var y1 = Generate.Range(9).Reshape(new long[] { 3, 3 }); var y2 = y1.Transposed; y1 = y1.Transposed; var y3 = y1 + y2; if (y3.Value[0, 2] != 12) { throw new Exception("Failure with double transpose"); } var y4 = Generate.Range(2 * 2 * 2 * 2 * 2).Reshape(new long[] { 2, 2, 2, 2, 2 }); var y5 = y4 * (Generate.Range(2) + 1); if (y5.Sum() != 752) { throw new Exception("Failure with 5 dimensions"); } var y6 = Generate.Range(2 * 2 * 2 * 2 * 2 * 2).Reshape(new long[] { 2, 2, 2, 2, 2, 2 }); var y7 = y6 * (Generate.Range(2) + 1); if (y7.Sum() != 3040) { throw new Exception("Failure with 6 dimensions"); } var r = Generate.Random(2000); var rmin = Min.Aggregate(r); var rmax = Max.Aggregate(r); var ravg = Add.Aggregate(r) / r.DataAccessor.Length; if (rmin < 0 || rmax > 1.0) { throw new Exception("Error in random"); } if (ravg < 0.4 || ravg > 0.6) { throw new Exception("Deviation in random average"); } }