/// <summary> /// Compute the truth value of x1 OR x2 element-wise. /// </summary> /// <param name="lhs">Input boolean array.</param> /// <param name="rhs">Input boolean array.</param> /// <returns>Returns True if the arrays are equal.</returns> /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.logical_or.html</remarks> public static unsafe NDArray <bool> logical_or(NDArray lhs, NDArray rhs) { #if _REGEN1 if (lhs.typecode != rhs.typecode) { throw new NotImplementedException("please make sure operands have the same data type"); } else if (lhs.typecode == NPTypeCode.Boolean) { if (lhs.Shape.IsScalar && rhs.Shape.IsScalar) { return(NDArray.Scalar(*(bool *)lhs.Address || *(bool *)rhs.Address).MakeGeneric <bool>()); } var(BroadcastedLeftShape, BroadcastedRightShape) = DefaultEngine.Broadcast(lhs.Shape, rhs.Shape); var lhs_address = (bool *)lhs.Address; var rhs_address = (bool *)rhs.Address; var ret = new NDArray <bool>(new Shape(BroadcastedLeftShape.dimensions), true); Shape retShape = ret.Shape; //iterate var ret_address = (bool *)ret.Address; var incr = new NDCoordinatesIncrementor(BroadcastedLeftShape.dimensions); //doesn't matter which side it is. int[] current = incr.Index; do { *(ret_address + retShape.GetOffset(current)) = (*(lhs_address + BroadcastedLeftShape.GetOffset(current))) || *(rhs_address + BroadcastedRightShape.GetOffset(current)); } while (incr.Next() != null); return(ret); }
/// <summary> /// Return random integers from the “discrete uniform” distribution of the specified dtype in the “half-open” interval [low, high). If high is None (the default), then results are from [0, low). /// </summary> /// <param name="low">Lowest (signed) integer to be drawn from the distribution (unless high=-1, in which case this parameter is one above the highest such integer).</param> /// <param name="high">If provided, one above the largest (signed) integer to be drawn from the distribution (see above for behavior if high=-1).</param> /// <param name="size">The shape of the array.</param> /// <param name="dtype">Desired dtype of the result. All dtypes are determined by their name, i.e., ‘int64’, ‘int’, etc, so byteorder is not available and a specific precision may have different C types depending on the platform. The default value is ‘np.int’.</param> /// <returns></returns> /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.random.randint.html</remarks> public NDArray randint(long low, long high = -1, Shape size = null, Type dtype = null) { dtype = dtype ?? np.int32; var typecode = dtype.GetTypeCode(); if (high == -1) { high = low; low = 0; } if (size == null || (size.NDim == 1 && size.Size == 1)) { return(NDArray.Scalar(randomizer.NextLong(low, high), typecode)); } var nd = new NDArray(dtype, size); //allocation called inside. switch (typecode) { #if _REGEN % foreach supported_numericals, supported_numericals_lowercase % case NPTypeCode.#1: { var data = (#2[])nd.Array; for (int i = 0; i < data.Length; i++) { data[i] = Convert.To #1 (randomizer.NextLong(low, high)); } break; }
/// <summary> /// Return random integers from the “discrete uniform” distribution of the specified dtype in the “half-open” interval [low, high). If high is None (the default), then results are from [0, low). /// </summary> /// <param name="low">Lowest (signed) integer to be drawn from the distribution (unless high=-1, in which case this parameter is one above the highest such integer).</param> /// <param name="high">If provided, one above the largest (signed) integer to be drawn from the distribution (see above for behavior if high=-1).</param> /// <param name="size">The shape of the array.</param> /// <param name="dtype">Desired dtype of the result. All dtypes are determined by their name, i.e., ‘int64’, ‘int’, etc, so byteorder is not available and a specific precision may have different C types depending on the platform. The default value is ‘np.int’.</param> /// <returns></returns> /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.random.randint.html</remarks> public NDArray randint(long low, long high = -1, Shape size = default, Type dtype = null) { dtype = dtype ?? np.int32; var typecode = dtype.GetTypeCode(); if (high == -1) { high = low; low = 0; } if (size.IsEmpty || size.IsScalar) return NDArray.Scalar(randomizer.NextLong(low, high), typecode); var nd = new NDArray(dtype, size); //allocation called inside. switch (typecode) { #if _REGEN %foreach supported_numericals,supported_numericals_lowercase% case NPTypeCode.#1: { var data = (ArraySlice<#2>)nd.Array; for (int i = 0; i < data.Count; i++) data[i] = Converts.To#1(randomizer.NextLong(low, high)); break; }
/// <summary> /// Return a new array of given shape and type, filled with ones. /// </summary> /// <param name="shape">Shape of the new array.</param> /// <param name="typeCode">The desired data-type for the array, e.g., <see cref="uint8"/>. Default is <see cref="float64"/> / <see cref="double"/>.</param> /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.ones.html</remarks> public static NDArray ones(Shape shape, NPTypeCode typeCode) { object one = null; switch (typeCode) { case NPTypeCode.Complex: one = new Complex(1d, 0d); break; case NPTypeCode.NDArray: one = NDArray.Scalar(1, np.int32); break; case NPTypeCode.String: one = "1"; break; case NPTypeCode.Char: one = '1'; break; default: one = Converts.ChangeType((byte)1, typeCode); break; } return(new NDArray(ArraySlice.Allocate(typeCode, shape.size, one), shape)); }
/// <summary> /// Return a new array of given shape and type, filled with ones. /// </summary> /// <param name="shape">Shape of the new array.</param> /// <param name="dtype">The desired data-type for the array, e.g., <see cref="uint8"/>. Default is <see cref="float64"/> / <see cref="double"/>.</param> /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.ones.html</remarks> public static NDArray ones(Shape shape, Type dtype = null) { dtype = dtype ?? typeof(double); var nd = new NDArray(dtype, shape); //already allocates inside. object one = null; switch (nd.GetTypeCode) { case NPTypeCode.Complex: one = new Complex(1d, 0d); break; case NPTypeCode.NDArray: one = NDArray.Scalar(1, np.int32); break; case NPTypeCode.String: one = "1"; break; default: one = Convert.ChangeType((byte)1, dtype); break; } switch (nd.GetTypeCode) { #if _REGEN %foreach except(supported_dtypes, "String")% case NPTypeCode.#1: { new Span<#1>((#1[]) nd.Array).Fill((#1)one); break; }
/// <summary> /// Return a new float array of given shape, filled with zeros. /// </summary> /// <param name="shape">Shape of the new array,</param> /// <param name="dtype">The desired data-type for the array, e.g., <see cref="uint8"/>. Default is <see cref="float64"/> / <see cref="double"/>.</param> /// <returns>Array of zeros with the given shape, dtype.</returns> /// <remarks>https://docs.scipy.org/doc/numpy/reference/generated/numpy.zeros.html</remarks> public static NDArray zeros(Shape shape, Type dtype = null) { dtype = dtype ?? np.float64; var nd = new NDArray(dtype, shape); //already allocates inside. if (dtype == typeof(NDArray)) //todo-NDArray Is it what is expected from NDArray dtype? { ((NDArray[])nd.Array).AsSpan().Fill(NDArray.Scalar(0, typeof(int))); //todo-NDArray! should it be int? } return(nd); }
/// <summary> /// Draw samples from a bernoulli distribution. /// </summary> /// <param name="p">Parameter of the distribution, >= 0 and <=1.</param> /// <param name="dims">Output Shape</param> /// <returns>Drawn samples from the parameterized bernoulli distribution.</returns> public NDArray bernoulli(double p, params int[] dims) { if (dims == null || dims.Length == 0) //return scalar { return(NDArray.Scalar(randomizer.NextDouble())); } var result = new NDArray <double>(dims); unsafe { var addr = result.Address; var len = result.size; Func <double> nextDouble = randomizer.NextDouble; for (int i = 0; i < len; i++) { addr[i] = nextDouble() > p ? 1 : 0; } } return(result); }
protected void SetIndices(object[] indicesObjects, NDArray values) { var indicesLen = indicesObjects.Length; if (indicesLen == 1) { switch (indicesObjects[0]) { case NDArray nd: SetIndices(this, new NDArray[] {nd}, values); return; case int i: Storage.SetData(values, i); return; case bool boolean: if (boolean == false) return; //do nothing SetData(values); return; // np.expand_dims(this, 0); //equivalent to [np.newaxis] case int[] coords: SetData(values, coords); return; case NDArray[] nds: this[nds] = values; return; case object[] objs: this[objs] = values; return; case string slicesStr: new NDArray(Storage.GetView(Slice.ParseSlices(slicesStr))).SetData(values); return; case null: throw new ArgumentNullException($"The 1th dimension in given indices is null."); //no default } } int ints = 0; int bools = 0; for (var i = 0; i < indicesObjects.Length; i++) { switch (indicesObjects[i]) { case NDArray _: case int[] _: goto _NDArrayFound; case int _: ints++; continue; case bool @bool: bools++; continue; case string _: case Slice _: continue; case null: throw new ArgumentNullException($"The {i}th dimension in given indices is null."); default: throw new ArgumentException($"Unsupported indexing type: '{(indicesObjects[i]?.GetType()?.Name ?? "null")}'"); } } //handle all ints if (ints == indicesLen) { Storage.SetData(values, indicesObjects.Cast<int>().ToArray()); return; } //handle all booleans if (bools == indicesLen) { this[np.array(indicesObjects.Cast<bool>().ToArray(), false).MakeGeneric<bool>()] = values; return; } Slice[] slices; //handle regular slices try { slices = indicesObjects.Select(x => { switch (x) { case Slice o: return o; case int o: return Slice.Index(o); case string o: return new Slice(o); case bool o: return o ? Slice.NewAxis : throw new NumSharpException("false bool detected"); //TODO: verify this case IConvertible o: return Slice.Index((int)o.ToInt32(CultureInfo.InvariantCulture)); default: throw new ArgumentException($"Unsupported slice type: '{(x?.GetType()?.Name ?? "null")}'"); } }).ToArray(); } catch (NumSharpException e) when (e.Message.Contains("false bool detected")) { //handle rare case of false bool return; } new NDArray(Storage.GetView(slices)).SetData(values); //handle complex ndarrays indexing _NDArrayFound: var @this = this; var indices = new List<NDArray>(); bool foundNewAxis = false; int countNewAxes = 0; //handle ndarray indexing bool hasCustomExpandedSlice = false; //use for premature slicing detection for (int i = 0; i < indicesLen; i++) { var idx = indicesObjects[i]; _recuse: switch (idx) { case Slice o: if (o.IsEllipsis) { indicesObjects = ExpandEllipsis(indicesObjects, @this.ndim).ToArray(); //TODO: i think we need to set here indicesLen = indicesObjects.Length continue; } if (o.IsNewAxis) { //TODO: whats the approach to handling a newaxis in setter, findout. countNewAxes++; foundNewAxis = true; continue; } hasCustomExpandedSlice = true; indices.Add(GetIndicesFromSlice(@this.Shape.dimensions, o, i - countNewAxes)); continue; case int o: indices.Add(NDArray.Scalar<int>(o)); continue; case string o: indicesObjects[i] = idx = new Slice(o); goto _recuse; case bool o: if (o) { indicesObjects[i] = idx = Slice.NewAxis; goto _recuse; } else return; //false bool causes nullification of return. case IConvertible o: indices.Add(NDArray.Scalar<int>(o.ToInt32(CultureInfo.InvariantCulture))); continue; case int[] o: indices.Add(np.array(o, copy: false)); //we dont copy, pinning will be freed automatically after we done indexing. continue; case NDArray nd: if (nd.typecode == NPTypeCode.Boolean) { //TODO: mask only specific axis??? find a unit test to check it against. throw new Exception("if (nd.typecode == NPTypeCode.Boolean)"); } indices.Add(nd); continue; default: throw new ArgumentException($"Unsupported slice type: '{(idx?.GetType()?.Name ?? "null")}'"); } } NDArray[] indicesArray = indices.ToArray(); //handle premature slicing when the shapes cant be broadcasted together if (hasCustomExpandedSlice && !np.are_broadcastable(indicesArray)) { var ndim = indicesObjects.Length; var prematureSlices = new Slice[ndim]; var dims = @this.shape; for (int i = 0; i < ndim; i++) { if (indicesObjects[i] is Slice slice) { prematureSlices[i] = slice; //todo: we might need this in the future indicesObjects[i] = Slice.All; } else { prematureSlices[i] = Slice.All; } } @this = @this[prematureSlices]; //updated premature axes dims = @this.shape; for (int i = 0; i < ndim; i++) { if (prematureSlices[i] != Slice.All) { indicesArray[i] = GetIndicesFromSlice(dims, Slice.All, i); } } } //TODO: we can use a slice as null indice instead of expanding it, then we use PrepareIndexGetters to actually simulate that. SetIndices(@this, indicesArray, values); //TODO: this is valid code for getter, we need to impl a similar technique before passing @this. //if (foundNewAxis) //{ // //TODO: This is not the behavior when setting with new axis, is it even possible? // var targettedAxis = indices.Count - 1; // var axisOffset = this.ndim - targettedAxis; // var retShape = ret.Shape; // for (int i = 0; i < indicesLen; i++) // { // if (!(indicesObjects[i] is Slice slc) || !slc.IsNewAxis) // continue; // // var axis = Math.Max(0, Math.Min(i - axisOffset, ret.ndim)); // retShape = retShape.ExpandDimension(axis); // } // // ret = ret.reshape(retShape); //} // //return ret; }