/// /// This file is part of ILNumerics Community Edition. /// /// ILNumerics Community Edition - high performance computing for applications. /// Copyright (C) 2006 - 2012 Haymo Kutschbach, http://ilnumerics.net /// /// ILNumerics Community Edition is free software: you can redistribute it and/or modify /// it under the terms of the GNU General Public License version 3 as published by /// the Free Software Foundation. /// /// ILNumerics Community Edition is distributed in the hope that it will be useful, /// but WITHOUT ANY WARRANTY; without even the implied warranty of /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /// GNU General Public License for more details. /// /// You should have received a copy of the GNU General Public License /// along with ILNumerics Community Edition. See the file License.txt in the root /// of your distribution package. If not, see . /// /// In addition this software uses the following components and/or licenses: /// /// ================================================================================= /// The Open Toolkit Library License /// /// Copyright (c) 2006 - 2009 the Open Toolkit library. /// /// Permission is hereby granted, free of charge, to any person obtaining a copy /// of this software and associated documentation files (the "Software"), to deal /// in the Software without restriction, including without limitation the rights to /// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of /// the Software, and to permit persons to whom the Software is furnished to do /// so, subject to the following conditions: /// /// The above copyright notice and this permission notice shall be included in all /// copies or substantial portions of the Software. /// /// ================================================================================= /// using System; using System.Collections.Generic; using System.IO; using ILNumerics; using ILNumerics.Misc; using ILNumerics.Exceptions; using ILNumerics.Storage; using ILNumerics.Native; using System.Text; namespace ILNumerics { /// /// Boolean array for high performance relational operations on arbitrary arrays /// /// /// Logical arrays store true/false conditions as elements. Each element consumes /// one byte. Logical arrays are the output parameter of all relational comparisons. [Serializable] public sealed class ILRetLogical : ILBaseLogical { private static readonly bool s_isTempArray = true; #region properties /// /// Number of 'true' elements in this array /// /// This value caches the number of 'true' elements in this logical array. /// It may be used for information purposes but is actually needed internally for performance /// reasons. public override long NumberNonZero { get { using (ILScope.Enter(this)) return Storage.NumberNonZero; } internal set { Storage.NumberNonZero = value; } } /// /// Shift the dimensions of this array by one (transpose for matrix) /// public new ILRetLogical T { get { using (ILScope.Enter(this)) return new ILRetLogical((ILLogicalStorage)Storage.ShiftDimensions(1), NumberNonZero); } } /// /// Create clone of this array /// public new ILRetLogical C { get { return this; } } /// /// Size descriptor shortcut /// public override ILSize S { get { using (ILScope.Enter(this)) return Storage.Size; } } /// /// Size descriptor /// public override ILSize Size { get { using (ILScope.Enter(this)) return Storage.Size; } } /// /// Test if this array instance is a column vector (e.g. n x 1) /// public override bool IsColumnVector { get { using (ILScope.Enter(this)) return Size[1] == 1 && Size.NumberOfDimensions == 2; ; } } /// /// Test if this array instance is a row vector (e.g. 1 x n) /// public override bool IsRowVector { get { using (ILScope.Enter(this)) return Size[0] == 1 && Size.NumberOfDimensions == 2; } } /// /// Determine if this array has complex elements. /// /// Calling this member will dispose this instance afterwards (for temporary arrays). public override bool IsComplex { get { using (ILScope.Enter(this)) return false; } } /// /// Test if this instance is an empty array (number of elements stored = 0) /// public override bool IsEmpty { get { using (ILScope.Enter(this)) return Size.NumberOfElements == 0; } } /// /// Test if this instance is a matrix /// /// In order for an array to be a matrix the number of non singleton /// dimensions must equal 2. This attribute is readonly. public override bool IsMatrix { get { using (ILScope.Enter(this)) return Size.NumberOfDimensions == 2; } } /// /// Determine if this array holds numeric values. /// /// An ILArray is numeric as long as its elements are one of the /// following types: /// /// /// inner type /// /// /// System.double /// floating point, real, 8 bytes /// /// /// System.float /// floating point real, 4 bytes /// /// /// ILNumerics.complex /// floating point complex, 16 bytes /// /// /// ILNumerics.fcomplex /// floating point complex, 8 bytes /// /// /// System.char /// integer, real, 1 byte /// /// /// System.byte /// integer, real, 1 byte /// /// /// System.Int16 /// integer, real, 2 byte /// /// /// System.Int32 /// integer, real, 4 byte /// /// /// System.Int64 /// integer, real, 8 byte /// /// /// System.UInt16 /// unsigned integer, real, 2 byte /// /// /// System.UInt32 /// unsigned integer, real, 4 byte /// /// /// System.UInt64 /// unsigned integer, real, 8 byte /// /// /// Calling this member will dispose this instance afterwards (for temporary arrays). /// public override bool IsNumeric { get { using (ILScope.Enter(this)) return true; } } /// /// Test if this instance is a scalar /// /// This attribute is readonly. It returns: Size.NumberOfElements == 1. public override bool IsScalar { get { using (ILScope.Enter(this)) return Size.NumberOfElements == 1; } } /// /// Test if this array is a vector /// /// In order for an array to be a vector the number of non singleton /// dimensions must equal 1. Keep in mind that all ILArrays have at least 2 dimensions. Therefore /// it is not sufficient to test for the number of dimensions, but to take the number of /// non singleton dimensions into account. This attribute is readonly. public override bool IsVector { get { using (ILScope.Enter(this)) return (Size[0] == 1 || Size[1] == 1) && Size.NumberOfDimensions == 2; } } /// /// Length of the longest dimension of this instance /// /// This property is readonly. /// Calling this member will dispose this instance afterwards (for temporary arrays). public override int Length { get { using (ILScope.Enter(this)) return base.Length; } } /// /// Gets the name of this array (readonly) /// public new String Name { get { using (ILScope.Enter(this)) return m_name; } } #endregion #region constructors internal ILRetLogical(ILDenseStorage A) : base(new ILLogicalStorage(A.GetDataArray(), A.Size), s_isTempArray) { } /// /// Constructor creating ILRetLogical from dense storage /// /// input array, the storage given will directly be used for /// storage of the new logical array internal ILRetLogical(ILLogicalStorage A) : base(A, s_isTempArray) { } /// /// create temporary logical from predefined storage /// /// the storage will directly be used as storage of the new logical array /// number of nonzero elements in A. Must be positive or 0. /// Providing this parameter prevents the constructor from having to count the /// 'true' elements in A. internal ILRetLogical(ILLogicalStorage A, long numberNonZero) : base(A, s_isTempArray) { if (numberNonZero < 0) throw new ILNumerics.Exceptions.ILArgumentException("invalid number of non-zero-elements given!"); NumberNonZero = numberNonZero; } /// /// create temporary logical array of specified size /// /// /// variable length int array specifying the number and size of dimensions to /// be created. /// /// /// The size parameter may not be null or an empty array. An exception will be /// thrown in this case. The dimensions will be trimmed before processing /// (removing trailing non singleton dimensions). /// Depending on the requested size a logical temporary array of the specified size /// will be created. internal ILRetLogical(ILSize size) : base(new ILLogicalStorage(size), s_isTempArray) { } /// /// Constructor - create ILRetLogical of specified size /// from data array /// /// /// Variable length int array specifying the number and size of dimensions to /// be created. /// /// byte array matching the size of the dimensions /// specified. The data will directly be used as storage! No copy will be made! /// /// The size parameter may not be null or an empty array! An Exception will be /// thrown in this case. The dimensions will be trimmed before processing /// (removing trailing non singleton dimensions). /// Depending on the requested size an ILRetLogical of the specified size /// will be created. The type of storage will be byte. /// public ILRetLogical(byte[] data, params int[] size) : base(new ILLogicalStorage(data, new ILSize(size)), s_isTempArray) { } /// /// Constructor creating ILRetLogical, provide predefined storage /// /// Predefined storage elements. The array will directly be used /// as underlying storage. No copy will be made! /// Size descriptor public ILRetLogical(byte[] data, ILSize size) : base(new ILLogicalStorage(data, size), s_isTempArray) { } /// /// Constructor creating ILRetLogical, predefined storage (fast version) /// /// Predefined storage elements. The array will directly be used /// as underlying storage. No copy will be made! /// Size descriptor /// Number of nonzero elements in . /// Providing this parameter prevents from counting the 'true' elements (again). public ILRetLogical(byte[] data, ILSize size, long nonZeroCount) : base(new ILLogicalStorage(data, size), s_isTempArray) { if (nonZeroCount < 0) throw new ILNumerics.Exceptions.ILArgumentException("invalid number of non-zero-elements given!"); NumberNonZero = nonZeroCount; } #endregion #region public functions /// /// Clone of this array /// /// /// Clones of all arrays in ILNumerics are done in a very fast, lazy way. This means, /// at the time the clone is made, no relevant memory is copied. Elements of both arrays rather point to the same /// underlying System.Array. A reference counting mechanism ensures the detaching of thoses arrays /// on write access. /// The clone returned will be of the same type as this instance. internal override ILBaseArray Clone() { return this; } /// /// Concatenate this array /// /// N-dimensional array. Except for dimensions /// the dimensions of A must match the dimensions of this storage /// Index of dimension to concatenate arrays along. /// If dim is larger than the number of dimensions of any of the arrays, /// its value will be used in modulus the number of dimensions. /// New array having the size /// of both input arrays layed behind each other along the dim's-dimension public new ILRetLogical Concat(ILInLogical A, int dim) { using (ILScope.Enter(this,A)) return new ILRetLogical((ILLogicalStorage)Storage.Concat(A.Storage, dim)); } /// /// Compare elements and shape of this array with another array /// /// Other array /// true if shape and element values of both arrays match, false otherwise /// Calling this member will dispose this instance afterwards (for temporary arrays. public override bool Equals(object A) { using (ILScope.Enter(this)) return base.Equals(A); } /// /// Copy values of all elements into System.Array. /// /// [Output] System.Array, holding all element values of this ILDenseStorage. /// The System.Array may be predefined. If its length is sufficient, it will be used and /// its leading elements will be overwritten when function returns. If 'outArray' is null or has too few elements, /// it will be recreated from the ILNumerics memory pool. public new void ExportValues(ref byte[] outArray) { using (ILScope.Enter(this)) Storage.ExportValues(ref outArray); } /// /// Enumerator returning elements as ElementType /// /// Enumerator /// This method enables the use of ILNumerics arrays in foreach loops. /// The iterator is returned, if arrays are directly used in foreach statements. The iterator /// is compatible with ILNumerics memory management. /// ILDenseStorage<T> A = ILMath.rand(5,4,6); /// foreach (double element in A) { /// // all elements are scalar double values /// String.Format("Element: {0} ",element); /// // Note: 'element' cannot be used to alter the collection! /// } /// public override IEnumerator GetEnumerator() { using (ILScope.Enter(this)) { byte[] values = GetArrayForRead(); int len = Size.NumberOfElements; for (int i = 0; i < len; i++) yield return values[i]; } } /// /// Generate a hash code based on the current arrays values /// /// Hash code /// The hashcode is generated by taking the values currently stored in the array into account. /// Therefore, the function must iterate over all elements in the array - which makes it somehow a costly /// operation. Take this into account, if you consider using large arrays in collections like dictionaries /// or hashtables, which make great use of hash codes. /// Calling this member will dispose this instance afterwards (for temporary arrays). public override int GetHashCode() { using (ILScope.Enter(this)) return base.GetHashCode(); } /// /// Get minimum and maximum value of all elements - if any /// /// [Output] Minimum value /// [Output] Maximum value /// true if the limits exists and could be computed, false otherwise /// Empty arrays will return false. In this case the output parameter will be: default(ElementType). /// Calling this member will dispose this instance afterwards (for temporary arrays). public override bool GetLimits(out byte min, out byte max) { using (ILScope.Enter(this)) return base.GetLimits(out min, out max); } /// /// Get single element from this array /// /// Indices, location of element /// The requested element public override byte GetValue(params int[] idx) { using (ILScope.Enter(this)) return base.GetValue(idx); } /// /// Create reshaped copy of this logical array /// /// New dimensions of the array /// Reshaped copy of this array /// The current instance will not be changed! A new array is created, having /// the elements of this array and a shape as determined by . /// /// If the number of elements in /// do not match the number of elements in this array. public new ILRetLogical Reshape(ILSize size) { using (ILScope.Enter(this)) { ILLogical ret = C; ret.Storage.Reshape(size); return ret; } } /// /// Create replication of this array /// /// Dimensions specifier. If the number of elements in is /// less than the number of dimensions in this array, the trailing dimensions will /// be set to 1 (singleton dimensions). On the other hand, if the number specified /// is larger then the number of dimension stored inside the storge the resulting /// storage will get its number of dimensions extended accordingly. /// Array being created out of multiple replications of this array along /// arbitrary dimensions according to public new ILRetLogical Repmat(params int[] dims) { using (ILScope.Enter(this)) return new ILRetLogical((ILLogicalStorage)Storage.Repmat(dims)); } /// /// Serialize this ILArray into a binary stream. /// /// System.IO.Stream to receive the byte stream /// for this ILBaseArray /// True on success, false on error. /// Calling this member will dispose this instance afterwards (for temporary arrays). /// public override bool Serialize(Stream outStream) { using (ILScope.Enter(this)) return base.Serialize(outStream); } /// /// Create logical array from this logical and shift dimensions /// /// Number of dimensions to shift /// Shifted version of this array /// The shift is done 'to the left': /// ILArray<double> A = zeros(2,4); /// ILArray<double> B = A.Shifted(1); /// // B is now: <double> [4,2] /// /// ILArray<double> C = zeros(2,4,3); /// ILArray<double> D = C.Shifted(1); /// // D is now: <double> [4,3,2] /// /// The dimensions are shifted circulary to the left. This /// can be imagined as removing the first dimensions from the beginning of the list of /// dimensions and "append" them to the end in a ringbuffer style. /// For dimension shifts of '1', you may consider using the /// property for readability. /// must be positive. It is taken modulus the number of dimensions. /// public new ILRetLogical Shifted(int shift) { using (ILScope.Enter(this)) return new ILRetLogical((ILLogicalStorage)Storage.ShiftDimensions(shift)); } /// /// Subarray from this array /// /// Arrays specifying the ranges to create subarray from /// Subarray as specified public new ILRetLogical Subarray(params ILBaseArray[] range) { using (ILScope.Enter(this)) using (ILScope.Enter(range)) return new ILRetLogical((ILLogicalStorage)Storage.Subarray(range)); } /// /// Send values of this instance to stream. /// /// Stream to write the values into. /// Format string to be used for output. See for a specification /// of valid formating expressions. This flag is only used, when 'method' is set to 'Serial'. /// A constant out of . Specifies the way in which /// the values will be serialized. /// If the 'Formatted' method is used, any occurences of the NewLine character(s) /// will be replaced from the format string before applying to the elements. This is done to /// prevent the format from breaking the 'page' style of the output. /// If 'method' is set to 'Matlab', the array will be written as Matfile version 5.0. No compression will be used. The internal 'Name' property will be used as the /// array name for writing. This array instance will be the only array in the .mat file. If you want to write several arrays bundled into one mat file, use the MatFile class to /// create a collection of arrays and write the MatFile to stream. public override void ToStream(Stream stream, string format, ILArrayStreamSerializationFlags method) { using (ILScope.Enter(this)) try { int len; switch (method) { case ILArrayStreamSerializationFlags.Serial: len = Size.NumberOfElements; using (TextWriter tw = new StreamWriter(stream)) { for (int i = 0; i < len; i++) { tw.Write(format, GetValue(i)); } } break; case ILArrayStreamSerializationFlags.Formatted: format = format.Replace(Environment.NewLine, ""); ILDenseStorage temp = this.Storage.ShiftDimensions(1); //len = Dimensions.NumberOfElements / Dimensions[1]; using (TextWriter tw = new StreamWriter(stream)) { tw.Write(temp.ValuesToString(0)); } break; case ILArrayStreamSerializationFlags.Matlab: ILMatFile mf = new ILMatFile(new ILBaseArray[1] { this }); mf.Write(stream); break; } } catch (Exception e) { throw new ILException("ToStream: Could not serialize to stream.", e); } } #endregion #region index access + mutability /// /// Subarray access (readonly) /// /// Range specification /// Logical array with the elements specified by range /// Query access: for N-dimensional arrays trailing dimensions will be choosen to be 0. Therefore you /// may ommit those trailing dimensions in range. /// The indexer may be used for querying any elements /// in this array. range may contains index specifications for one ... to any /// dimension. The array returned will have the size specified by range. /// public ILRetLogical this[params ILBaseArray[] range] { get { using (ILScope.Enter(this)) using (ILScope.Enter(range)) return new ILRetLogical((ILLogicalStorage)Storage.Subarray(range)); } } #endregion #region operator overloading #region constructional operators /// /// Implicitly cast one dimensional System.Array to ILNumerics array (vector) /// /// 1-dimensional system array, arbitrary type /// ILNumerics array of same element type as elements of A. /// Row vector. If A is null: empty array. /// The System.Array A will directly be used for the new ILNumerics array! /// No copy will be done! Make sure, not to reference A after this conversion! public static implicit operator ILRetLogical(byte[] A) { if (A == null) { return new ILRetLogical(ILSize.Empty00); } return new ILRetLogical(A, 1, A.Length); } /// /// Implicitly convert n-dim. System.Array to ILNumerics array /// /// Arbitrarily sized System.Array /// If A is null: empty array. Else: new ILNumerics array of the same size as A /// The resulting ILArray will reflect all dimensions of /// A. Elements of A will get copied to elements of output array (shallow copy). /// If type of input does not match /// ElementType public static implicit operator ILRetLogical(Array A) { if (A == null || A.Length == 0) { return new ILLogical(ILSize.Empty00); } if (A.GetType().GetElementType() != typeof(byte)) throw new ILCastException("inner type of System.Array must match"); int[] dims = new int[A.Rank]; byte[] retArr = ILMemoryPool.Pool.New(A.Length); int posArr = 0; for (int i = 0; i < dims.Length; i++) { dims[i] = A.GetLength(dims.Length - i - 1); } foreach (byte item in A) retArr[posArr++] = item; return new ILRetLogical(retArr, dims); } /// /// Implicitly cast two dimensional System.Array to ILNumerics array /// /// 2D System.Array /// If A is null: empty array. ILNumerics array of same size and type as A otherwise. public static implicit operator ILRetLogical(byte[,] A) { if (A == null || A.Length == 0) { return new ILRetLogical(ILSize.Empty00); } int[] dims = new int[2]; byte[] retArr = ILMemoryPool.Pool.New(A.Length); int posArr = 0; for (int i = 0; i < 2; i++) { dims[i] = A.GetLength(dims.Length - i - 1); } foreach (byte item in A) retArr[posArr++] = item; return new ILRetLogical(retArr, dims); } /// /// Implicitly cast three dimensional System.Array to ILNumerics array /// /// 3D System.Array /// If A is null: empty array. ILNumerics array of same size and type as A otherwise. public static implicit operator ILRetLogical(byte[, ,] A) { if (A == null || A.Length == 0) { return new ILRetLogical(ILSize.Empty00); } int[] dims = new int[3]; byte[] retArr = ILMemoryPool.Pool.New(A.Length); int posArr = 0; for (int i = 0; i < 3; i++) { dims[i] = A.GetLength(dims.Length - i - 1); } foreach (byte item in A) retArr[posArr++] = item; return new ILRetLogical(retArr, dims); } /// /// Implicitly convert boolean System.Byte to scalar logical array /// /// System.Byte /// Scalar logical array with value of val. public static implicit operator ILRetLogical(bool val) { ILRetLogical ret = new ILRetLogical(new byte[1] { val ? (byte)1 : (byte)0 }, 1, 1); return ret; } /// /// Implicitly convert logical array to System.Boolean /// /// Logical array /// true if elements of A are non-zero, false otherwise /// /// If A is null or empty, the function returns false. Otherwise returns true, /// if all elements of A are non-zero and returns false, if A contains zero elements. /// The behavior depends on the setting of the ILSettings.LogicalArrayToBoolConversion switch. /// Per default, only scalar arrays are allowed to be converted implicitely. This can be changed /// to implicitely convert non-scalar arrays by using ILMath.any on the array. /// /// /// public static implicit operator bool(ILRetLogical A) { using (ILScope.Enter(A)) { // this operator is implicit for convenience reasons: // if(tmp[0]!=-10.0) { ... is only possible this way if (object.Equals(A, null) || A.IsEmpty) return false; if (A.IsScalar) return A.GetValue(0, 0) == 1; if (Settings.LogicalArrayToBoolConversion == LogicalConversionMode.ImplicitAllAll) return ILMath.allall(A).GetValue(0) == 1; //else if (Settings.ILSettings.LogicalArrayToBoolConversion == LogicalConversionMode.NonScalarThrowsException) throw new ILArgumentException("Nonscalar logical to bool conversion. See ILSettings.LogicalArrayToBoolConversion"); } } /// /// Implicitly convert integer scalar to logical array of size 1x1 (scalar). /// /// Scalar value /// New logical array of size 1x1 holding the only element of type Byte /// with value of val. public static implicit operator ILRetLogical(int val) { ILRetLogical ret = new ILRetLogical(new Byte[1] { val != 0 ? (byte)1:(byte)0 }, 1, 1); return ret; } #endregion #region conversional operators /// /// Convert logical to temporary logical array /// /// Original logical array /// Temporary logical array public static implicit operator ILRetLogical(ILLogical a) { if (object.Equals(a,null)) return null; return a.C; } /// /// Convert logical input parameter type array to temporary logical array /// /// Logical input parameter type /// Temporary logical array public static implicit operator ILRetLogical(ILInLogical a) { if (object.Equals(a, null)) return null; return a.C; } /// /// Convert logical output parameter type array to temporary logical array /// /// Logical output parameter type /// Temporary logical array public static implicit operator ILRetLogical(ILOutLogical a) { if (object.Equals(a, null)) return null; return a.C; } /// /// Implicitly cast to ILArray<byte> /// /// A ILRetLogical /// ILArray<byte> public static implicit operator ILArray(ILRetLogical a) { if (object.Equals(a, null)) return null; ILArray ret = new ILArray(a.GiveStorageAwayOrClone()); ILScope.Context.RegisterArray(ret); return ret; } /// /// Implicitly cast from ILArray<byte> /// /// An ILArray<byte> /// logical return array public static implicit operator ILRetLogical(ILArray a) { if (object.Equals(a,null)) return null; return new ILRetLogical(new ILLogicalStorage( a.Storage.GetDataArray(),a.Size)); } /// /// Implicitly cast from ILInArray<byte> /// /// An ILInArray<byte> /// logical return array public static implicit operator ILInArray(ILRetLogical a) { if (object.Equals(a,null)) return null; ILArray ret = new ILArray(a.GiveStorageAwayOrClone()); if (Settings.AllowInArrayAssignments) ILScope.Context.RegisterArray(ret); return ret; } /// /// Implicitly cast from ILInArray<byte> /// /// An ILInArray<byte> /// logical return array public static implicit operator ILRetLogical(ILInArray a) { if (object.Equals(a, null)) return null; return new ILRetLogical(new ILLogicalStorage( a.Storage.GetDataArray(), a.Size)); } #endregion #region operational operators /// /// Invert values of array elements /// /// Input array /// New logical array, inverted element values public static ILRetLogical operator !(ILRetLogical in1) { if (object.Equals(in1,null)) throw new ILArgumentException("operator -(): parameter must not be null!"); return (in1 != (byte)1); } #endregion #endregion } }