/// /// 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.Text; using ILNumerics.Storage; using ILNumerics.Exceptions; using System.Collections.Generic; namespace ILNumerics { /// /// ILCell: container class holding and managing arbitrary array objects /// /// /// ILCell acts as general purpose container. It stores arbitrary arrays of arbitrary element type. /// Read and write access to cells provide value semantics - changes on arrays stored inside/ and /// retrieved from a cell cannot change the corresponding original array. /// [Serializable] public sealed class ILCell : ILBaseCell { private static readonly bool s_isTempArray = false; #region constructors /// /// Create cell object with pre-created data in specified dimensions /// /// predefined element data array, will be used for new cell (no copy will be made) /// size of the new cell /// object array data will directly be used for storage. No /// copy will be made. However, any arrays referenced by data are dereferenced for storage inside the cell. The size must match prod(size) [Obsolete("use instead!")] internal ILCell(ILStorage[] data, params int[] size) : base(new ILCellStorage(data, new ILSize(size)), s_isTempArray) { } /// /// Create cell object with pre-created data in specified dimensions /// /// predefined element data array, will be used for new cell (no copy will be made) /// size of the new cell /// object array data will directly be used for storage. No /// copy will be made. However, any arrays referenced by data are dereferenced for storage inside the cell. The size must match prod(size) [Obsolete("use instead!")] internal ILCell(ILStorage[] data, ILSize size) : base(new ILCellStorage(data, size), s_isTempArray) { } /// /// [deprecated] create new cell object, elements will be 'null' /// /// dimension sizes of the new cell /// After creation, the cell elements can be set by use /// of the indexer methods or by using corresponding methods of ILCell like SetValue() /// Consider using in order to create /// cell arrays. /// /// /// [Obsolete("use instead!")] public ILCell(params int[] size) : base(new ILCellStorage(new ILStorage[prod(size)], new ILSize(size)), s_isTempArray) { } internal ILCell(ILCellStorage cellStorage) : base(cellStorage, s_isTempArray) { } [Obsolete("use instead!")] internal ILCell(ILSize size, params ILStorage[] values) : base(new ILCellStorage(values, size), s_isTempArray) { } #endregion constructors #region properties /// /// Replace the elements of this array with another array's elements, preventing memory leaks /// /// New array public ILRetCell a { set { Assign(value); } get { return this.C; } } #endregion #region implicit casts #region constructional operators //public static implicit operator ILCell(double value) { // return createScalar(value); //} //public static implicit operator ILCell(float value) { // return createScalar(value); //} //public static implicit operator ILCell(byte value) { // return createScalar(value); //} //public static implicit operator ILCell(int[] value) { // return createArray(value); //} #endregion #region conversional operators /// /// Convert temporary cell to persistent cell /// /// Temporary cell /// Persistent cell public static implicit operator ILCell(ILRetCell A) { if (object.Equals(A, null)) return null; ILCell ret = new ILCell((ILCellStorage)A.GiveStorageAwayOrClone()); ILScope.Context.RegisterArray(ret); return ret; } /// /// Convert input parameter cell to persistent cell /// /// Input parameter cell /// Persistent cell public static implicit operator ILCell(ILInCell A) { if (object.Equals(A, null)) return null; ILCell ret = new ILCell(new ILCellStorage( A.Storage.GetDataArray(), A.Size)); ILScope.Context.RegisterArray(ret); return ret; } /// /// Convert output parameter cell to persistent cell /// /// Output parameter cell /// Persistent cell public static implicit operator ILCell(ILOutCell A) { if (object.Equals(A, null)) return null; ILCell ret = new ILCell(new ILCellStorage( A.Storage.GetDataArray(), A.Size)); ILScope.Context.RegisterArray(ret); return ret; } #endregion #endregion #region helper functions internal static long prod(int[] sizes) { int ret = 1; for (int i = 0; i < sizes.Length; i++) ret *= sizes[i]; return ret; } #endregion helper functions #region public interface /// /// Replaces storage of this array with new array elements, registers this array for out-of-scope disposal /// /// New array public void Assign(ILRetCell value) { if (!IsDisposed) Storage.Dispose(); m_storage = value.GiveStorageAwayOrClone(); //ILScope.Context.RegisterArray(this); } /// /// Set single element of the cell /// /// The new value /// Indices specifying the location to set the element to /// The function supports the following features: /// /// Automatic expansion of the cell, when addressing an element outside of the cells size limits. /// Before storing the new element into the cell, an old element may existing on the same location gets disposed. /// A clone of the new value is stored, therefore, none of the source and the stored element are altered, whenever the other cell is altered (value semantics). /// The function supports deep index addressing. This is the only way of altering array elements inside the cell - without recreation. /// /// Removal of parts of the cell is not supported. If null or an empty array is provided as , the corresponding /// element is overwritten or removed. /// public void SetValue(ILBaseArray value, params int[] idx) { using (ILScope.Enter(value)) { Storage.SetValueTyped(value.Storage, idx); } } /// /// Set single element of the cell /// /// The new value /// Indices specifying the location to set the element to /// The function supports the following features: /// /// Automatic expansion of the cell, when addressing an element outside of the cells size limits. /// Before storing the new element into the cell, an old element may existing on the same location gets disposed. /// A clone of the new value is stored, therefore, none of the source and the stored element are altered, whenever the other cell is altered (value semantics). /// The function supports deep index addressing. This is the only way of altering array elements inside the cell - without recreation. /// /// Removal of parts of the cell is not supported. If null or an empty array is provided as , the corresponding /// element is overwritten or removed. /// internal void SetValue(ILStorage value, params int[] idx) { Storage.SetValueTyped(value, idx); } /// /// Alter range of this array /// /// Array with new values /// Range specification /// All common array modification/ reshaping/ removing/ expansion rules apply. /// Like for almost all operations on cell, the values stored in the cell are /// not connected to the original cell elements outside the cell (value semantics). public void SetRange(ILInCell value, params ILBaseArray[] range) { using (ILScope.Enter(range)) using (ILScope.Enter(value)) { if (Object.ReferenceEquals(value, null)) { Storage.IndexSubrange(null, range); } else { Storage.IndexSubrange((ILCellStorage)value.Storage.Clone(), range); } } } #endregion #region Index access /// /// Get/set/remove single element /// /// /// Inner element, new inner element or null /// The type of access depends on the length of indices. If indices contains only one element, /// the array will be accessed via sequential index access. This is sometimes called referred to as 'linear' /// index addressing. /// Sequential index access reflects the index of internal storage the way the data are actually organized /// in memory. This access method is mainly convinient for vectors where you are not interested of orientation. /// The following example demonstrates sequential index access for ILArray's (which also holds for ILCells): /// For /// ILArray<double> A = ILMath.counter(1,12);, A[2] gives: 3.0. /// But the transpose /// A.T[2] gives also: 3.0. /// For matrices and N-dimensional arrays this holds as well: /// /// ILArray<double> A = ILMath.counter(1.0,1.0,3,2,2); /// A = /// [1.0 4.0 /// 2.0 5.0 /// 3.0 6.0 /// /// 7.0 10.0 /// 8.0 11.0 /// 9.0 12.0] /// /// A = ILMath.Reshape(A,3,2,2); /// A[10] gives 11.0 /// A[10,1] gives ILArgumentException -> out of range /// A[2,1,1] gives 12.0 /// A[2,1] gives 6.0 (set trailing dimension to '0') /// If the element addressed is a ILCell itself, a deep reference to this element will be returned instead. /// I.e. all elements of the ILCell will be recursively replaced with references to itself. Therefore, altering the /// elements returned will not alter the elements contained in the cell. /// /// /// The type of the element returned depends on the type of the element addressed: /// For ILArray<ElementType> the array returned will be a clone of the original array. /// For ILCell the ILBaseArray returned is a deep reference of the original elements stored. /// For other types the behavior is undefined. (since other types are not implemented yet ;) /// /// This indexer may also be used for direct access to inner elements of (elements of elements of ...) this cell: /// /// /// ILCell innerCell = new ILCell(2,1); /// innerCell[0] = ILMath.vec(10,200); /// innerCell[1] = new int[] {-10,-20,-30}; /// ILCell cell = new ILCell(2,1); /// cell[0] = innerCell; /// cell[1] = new string[] {"foobla"}; /// // cell is now: /// // [ILCell,(1x2)] /// // [innerCell[0], ILArray<double>(1x181)] /// // [innerCell[0], ILArray<double>(1x3)] /// // [ILArray<string>,(1x1)] /// /// cell[0,0] -> will give innerCell eq. ILCell (1x2) /// cell[0,1] -> will give ILArray<string> /// cell[0,0,0,1] -> will give innerCell[1] eq. ILArray<int>(1x3) /// /// /// In the last example above the trailing indices specified make the indexer walk down into the ILCell element and retrieve /// the content of this element. This kind of index access may be done as deep as you want. Just /// append the inner indices into inner elements to the right side of index specification. Addressing inner elements /// this way is the only way to alter elements directly inside the ILCell. public ILRetCell this[params int[] indices] { get { ILStorage val = Storage.GetValueTyped(indices); if (val is ILCellStorage) return new ILRetCell((ILCellStorage)val); else return new ILRetCell(new ILStorage[] { val }, ILSize.Scalar1_1); } set { using (ILScope.Enter(value)) { if (!object.Equals(value,null) && value.Storage.FromImplicitCast && value.IsScalar) { SetValue((value as ILDenseArray).GetValue(0), indices); } else { SetValue((object.Equals(value,null)) ? null : value.Storage, indices); } } } } /// /// Subarray access. Get/set regular subarray. /// /// Address range /// Reference cell array with subarray addressed by indices. /// Query access: for N-dimensional cell arrays missing trailing dimensions indices will be choosen to be 0. Therefore you /// may ommit those trailing dimensions in indices. /// The indexer may be used for querying or altering single/any elements /// in this cell. indices may contains index specifications for one to any /// dimension. The cell array returned will have the size specified by indices. /// Values returned will be reference cells. All elements contained will be 'deep references' created by /// recursively walking downwards the elements and replacing them by references to itself. Therefore altering the /// values returned will not alter the original elements. /// The indexer may also be used for removing parts of the cell. Therefore null must be assigned to the range specified by indices (using the set-access). indices /// must contain exactly one dimension specification other than 'full' in this case. This may be any vector-sized numeric ILArray of any /// numeric type. If indices apply to fewer dimensions than the number of dimensions existing, the upper dimensions will be /// merged and the array will be reshaped before applying the removal to it. /// /// /// ILCell C = new ILCell(4,10); /// C[":",2] = null; // >- will remove the third column (index: 2) from the cell. /// C[full,vec(2,5)] = null; >- will remove columns 3...6 /// C[1,1] = null; >- will produce an error. Only one dimension can be specified not full! /// /// The general behavior of this access methods is full compatible with the corresponding Matlab/Octave/Scilab access: a(:) = []. /// public ILRetCell this[params ILBaseArray[] indices] { get { using (ILScope.Enter(indices)) { ILCellStorage elements = (ILCellStorage)Storage.Subarray(indices); return new ILRetCell(elements); } } set { using (ILScope.Enter(indices)) using (ILScope.Enter(value)) { if (Object.ReferenceEquals(value, null)) { Storage.IndexSubrange(null, indices); } else { //if (value.Storage.FromImplicitCast && value.IsScalar) { // Storage.IndexSubrange((ILDenseStorage)value.GetValue(0), indices); //} else { Storage.IndexSubrange((ILCellStorage)value.Storage.Clone(), indices); //} } } } } #endregion index access #region memory management internal override bool EnterScope() { return false; } #endregion } }