/// /// 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.Exceptions; using ILNumerics.Storage; namespace ILNumerics { /// /// ILCell: container class holding arbitrary array objects /// /// /// ILCell acts as general purpose container. It stores arbitrary arrays of arbitrary element type. /// public sealed class ILRetCell : ILBaseCell { private static readonly bool s_isTempArray = true; #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 ILRetCell(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 ILRetCell(ILStorage[] data, ILSize size) : base(new ILCellStorage(data, size), s_isTempArray) { } /// /// Create new cell object, elements will be 'null' /// /// Size descriptor of the new cell [Obsolete("use instead!")] internal ILRetCell(params int[] size) : base(new ILCellStorage(new ILStorage[ILCell.prod(size)], new ILSize(size)), s_isTempArray) { } internal ILRetCell(ILCellStorage cellStorage) : base(cellStorage, s_isTempArray) { } [Obsolete("use instead!")] internal ILRetCell(ILSize size, params ILStorage[] values) : base(new ILCellStorage(values, size), s_isTempArray) { } #endregion constructors #region properties /// /// Clone of this cell /// /// /// 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. /// Cells profit from the same efficient clone creation process. However, since a cell may store an arbitrarily deep /// hierarchy of other cells and arrays, in order to clone a cell, the cell elements have to be cloned as well - in an /// recursive manner. Clones play an important role for ILNumerics cells. They are used to implement value semantics for cell /// elements. I.e.: the cloned cell returned cannot not be used to alter elements of the original cell in any way. public new ILRetCell 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 /// 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 /// 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 base.IsComplex; } } /// /// 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 base.IsNumeric; } } /// /// Test if this instance is a scalar /// /// This attribute is readonly. It returns: Dimension.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; } } /// /// Transposed version of this ILCell /// public new ILRetCell T { get { using (ILScope.Enter(this)) return new ILRetCell((ILCellStorage)Storage.ShiftDimensions(1)); } } /// /// Gets the name of this array (readonly) /// public new String Name { get { using (ILScope.Enter(this)) return m_name; } } /// /// Access to the more specialized version (ILCellStorage) of this storage /// internal new ILCellStorage Storage { get { return (m_storage as ILCellStorage); } set { // e.g. Storage.Detach() may return itself (if no detaching is // required). So we must check for that equalty here! if (!object.Equals(value, m_storage)) { m_storage.Dispose(); m_storage = value; } } } #endregion #region implicit casts #region constructional operators /// /// Convert primitive integer to a scalar temporary cell /// /// Primitive scalar int value /// New scalar temporary cell public static implicit operator ILRetCell(int value) { ILRetCell ret = createScalar(value); ret.Storage.FromImplicitCast = true; return ret; } /// /// Convert primitive double to a scalar temporary cell /// /// Primitive scalar double value /// New scalar temporary cell public static implicit operator ILRetCell(double value) { ILRetCell ret = createScalar(value); ret.Storage.FromImplicitCast = true; return ret; } /// /// Convert primitive float to a scalar temporary cell /// /// Primitive scalar float value /// New scalar temporary cell public static implicit operator ILRetCell(float value) { ILRetCell ret = createScalar(value); ret.Storage.FromImplicitCast = true; return ret; } /// /// Convert primitive byte to a scalar temporary cell /// /// Primitive byte int value /// New scalar temporary cell public static implicit operator ILRetCell(byte value) { ILRetCell ret = createScalar(value); ret.Storage.FromImplicitCast = true; return ret; } /// /// Encapsulate integer System.Array into a scalar temporary cell /// /// Primitive System.Int32 value - no copy will be made! /// New scalar temporary cell public static implicit operator ILRetCell(int[] value) { ILRetCell ret = createArray(value); ret.Storage.FromImplicitCast = true; return ret; } /// /// Convert string to a scalar temporary cell /// /// String value /// New scalar temporary cell public static implicit operator ILRetCell(string value) { ILRetCell ret = createScalar(value); ret.Storage.FromImplicitCast = true; return ret; } /// /// Encapsulate array of strings into a scalar temporary cell /// /// String array - no copy will be made! /// New scalar temporary cell public static implicit operator ILRetCell(string[] value) { ILRetCell ret = createArray(value); ret.Storage.FromImplicitCast = true; return ret; } #endregion #region conversional operators /// /// Convert cell to temporary cell /// /// Cell /// Temporary cell public static implicit operator ILRetCell(ILCell A) { if (object.Equals(A, null)) return null; return A.C; } /// /// Convert input parameter cell to temporary cell /// /// Input parameter cell /// Temporary cell public static implicit operator ILRetCell(ILInCell A) { if (object.Equals(A, null)) return null; return A.C; } /// /// Convert output parameter cell to temporary cell /// /// Output parameter cell /// Temporary cell public static implicit operator ILRetCell(ILOutCell A) { if (object.Equals(A, null)) return null; return A.C; } /// /// Wrap single logical array into a new scalar temporary cell /// /// Logical array /// Scalar cell public static implicit operator ILRetCell(ILBaseLogical A) { if (object.Equals(A, null)) return null; ILRetCell ret = ILMath.cell(A); ret.Storage.FromImplicitCast = true; return ret; } #endregion #endregion #region helper functions private static ILRetCell createScalar(T value) { using (ILScope.Enter()) { ILCell ret = new ILCell(1, 1); ret.SetValue(new ILDenseStorage(new T[] { value }, ILSize.Scalar1_1), 0, 0); return ret; } } private static ILRetCell createArray(T[] value) { using (ILScope.Enter()) { ILCell ret = new ILCell(1, 1); ret.SetValue(new ILDenseStorage(value, new ILSize(1, value.Length)), 0, 0); return ret; } } #endregion helper functions #region public interface /// /// 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 cell /// /// Cell to concatenate this cell with /// Dimension index along which to concatenate the cells. /// new cell with concatenation of all elements of both cells /// The array returned will be a copy of both cells involved. /// If is larger than /// the number of dimensions of one of the arrays its value will be used in modulus. /// The resulting cell has the size of both input cells, laid beside one /// another along the dimension. public new ILRetCell Concat(ILInCell A, int dim) { using (ILScope.Enter(this)) using (ILScope.Enter(A)) return base.Concat(A, 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. internal new void ExportValues(ref ILStorage[] outArray) { using (ILScope.Enter(this)) Storage.ExportValues(ref outArray); } /// /// Retrieve a single array of a known type from a cell position /// /// Element type of the array /// Position of the array within this cell /// Lazy, shallow clone of the array found at the given position public new ILRetArray GetArray(params ILBaseArray[] indices) { using (ILScope.Enter(this)) using (ILScope.Enter(indices)) return base.GetArray(indices); } /// /// Retrieve a single element from the given position /// /// Position of the element to retrieve, must evaluate to a scalar position /// A clone of the scalar element found /// /// The method returns a lazy, shallow clone of the content of the cell element specified by . /// However, the return type (ILBaseArray) is not strongly typed and may contain any element. According to the /// true element stored in the cell, this might be an array of arbitrary type, null or even another cell. Moreover, handling /// ILBaseArray directly is not recommended for ILNumerics, since this would hinder the memory management from proper /// functioning. Therefore: The use of this method is not recommended and left to ILNumerics experts - for very /// specific and rare situations. /// public new ILBaseArray GetBaseArray(params ILBaseArray[] indices) { using (ILScope.Enter(this)) using (ILScope.Enter(indices)) return base.GetBaseArray(indices); } /// /// Retrieve a subcell of this cell /// /// Subcell definition, arbitrary size /// A cell with a lazy, shallow clone of the elements of this cell, addressed by /// The cell returned will have the size and shape specified by . public new ILRetCell GetCell(params ILBaseArray[] indices) { using (ILScope.Enter(this)) using (ILScope.Enter(indices)) { return new ILRetCell((ILCellStorage)Storage.Subarray(indices)); } } /// /// Enumerator returning elements as scalar cells /// /// Enumerator /// This method enables the use of cells 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 new IEnumerator GetEnumerator() { using (ILScope.Enter(this)) { return base.GetEnumerator(); } } /// /// 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). internal new bool GetLimits(out ILStorage min, out ILStorage max) { using (ILScope.Enter(this)) return base.GetLimits(out min, out max); } /// /// Retrieve single element from this cell /// /// Position of the element /// Lazy, shallow clone of the element to retrieve or null, if there is no element at this place public new object GetValue(params int[] idx) { using (ILScope.Enter(this)) { return base.GetValue(idx); } } /// /// Retrieve a typed single element from within the cell, supports deep indexing /// /// Expected type of the value to be returned /// Location of the single element addressed /// A clone of the single element addressed by /// The element returned will have the type given by . It is an error to specify /// a different type as the true type of the element specified. An exception is thrown if both types differ. public new T GetValue(params int[] indices) { using (ILScope.Enter(this)) { return Storage.GetValue(indices); } } /// /// Test if an element of the cell is an array of the given element type /// /// The array element type to check the cell element against /// Position of the cell element to be tested /// true if the element found at the given position is an array of the element type , false otherwise /// The method is helpful in order to investigate the contents of a cell array. If you are not sure about the /// types of elements in the cell, this function can be used to make sure, elements are of the expected type before retrieving them as such. /// In most situations, elements of a cell are stored arrays of a distinct element type. That element type is given to IsTypeOf as /// typeparameter . That means, in order to find out, if the first cell element stores an array of int (ILArray<int>), /// one may use cell.IsTypeOf<int>(0) /// In order to test, if a cell element is of type ILCell, one can provide the type ILCell as type parameter: /// cell.IsTypeOf<ILCell>(0). Note the different semantic when checking for cell elements of type cell. Here we do not test for the /// element type but for the array type itself, ie. ILCell. The reason of this is: the type of elements of ILCell is /// an implementation detail and therefore hidden to the user. /// /// /// In the following example a ILCell of size 3x2 is created. It stores several array types, among which other cells are stored as elements of the outer cell. /// ILCell cell = ILMath.cell(new ILSize(3, 2) /// , "first element" /// , 2.0 /// , ILMath.cell(Math.PI, 100f) /// , ILMath.create<short>(1, 2, 3, 4, 5, 6) /// , new double[] {-1.4, -1.5, -1.6}); /// /// The cell is now: /// ILCell [3,2] /// <String> first element <Int16> [2,3,4,5,6] /// <Double> 2 ILCell [1,3] /// ILCell [2,1] (null) /// /// We test the element type of every element in the cell: /// /// Console.Out.WriteLine("cell[0,0] is of type 'string': {0}", cell.IsTypeOf<string>(0)); /// Console.Out.WriteLine("cell[0,0] is of type 'double': {0}", cell.IsTypeOf<double>(0)); /// /// Console.Out.WriteLine("cell[1,0] is of type 'double': {0}", cell.IsTypeOf<double>(1)); /// Console.Out.WriteLine("cell[2,0] is of type 'ILCell': {0}", cell.IsTypeOf<ILCell>(2)); /// /// Console.Out.WriteLine("cell[0,1] is of type 'short': {0}", cell.IsTypeOf<short>(0, 1)); /// Console.Out.WriteLine("cell[1,1] is of type 'ILCell': {0}", cell.IsTypeOf<ILCell>(1, 1)); /// Console.Out.WriteLine("cell[2,1] is of type 'double': {0}", cell.IsTypeOf<double>(2, 1)); /// /// This gives the following output: /// /// cell[0,0] is element type 'string': True /// cell[0,0] is element type 'double': False /// cell[1,0] is element type 'double': True /// cell[2,0] is element type 'ILCell': True /// cell[0,1] is element type 'short': True /// cell[1,1] is element type 'ILCell': True /// cell[2,1] is element type 'double': False // element is null, IsTypeOf<> never gives true /// public new bool IsTypeOf(params ILBaseArray[] position) { using (ILScope.Enter(this)) using (ILScope.Enter(position)) { return Storage.IsTypeOf(position); } } /// /// Create replication of this cell /// /// Dimensions specifier. If the number of elements in is /// less than the number of dimensions in this cell, 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 by multiple replications of this array along /// arbitrary dimensions according to public new ILRetCell Repmat(params int[] dims) { using (ILScope.Enter(this)) return new ILRetCell((ILCellStorage)Storage.Repmat(dims)); } /// /// Create reshaped copy of this cell /// /// New dimensions of the cell /// Reshaped copy of the cell /// The current instance will not be changed! A new cell is created, having /// the elements of this cell and a shape as determined by . /// /// If the number of elements in /// do not match the number of elements in this cell. public new ILRetCell Reshape(ILSize dimensions) { using (ILScope.Enter(this)) { return base.Reshape(dimensions); } } /// /// 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); } /// /// Dimension shifted cell from this cell /// /// Number of dimensions to shift /// Shifted version of this cell /// The shift is done 'to the left': /// ILCell A = cell(2,4); /// ILCell B = A.Shifted(1); /// // B is now: ILCell [4,2] /// /// ILCell C = cell(2,4,3); /// ILCell D = C.Shifted(1); /// // D is now: ILCell [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 ILRetCell Shifted(int shift) { using (ILScope.Enter(this)) return new ILRetCell((ILCellStorage)Storage.ShiftDimensions(shift)); } /// /// Subarray access (readonly) /// /// 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 stored in the cell. /// public new ILRetCell Subarray(params ILBaseArray[] indices) { using (ILScope.Enter(this)) using (ILScope.Enter(indices)) { ILCellStorage elements = (ILCellStorage)Storage.Subarray(indices); return new ILRetCell(elements); } } /// /// 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. /// Writing cells to *.mat files is NOT SUPPORTED yet! 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 /// /// 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): /// /// 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 { using (ILScope.Enter(this)) { ILStorage val = Storage.GetValueTyped(indices); if (val is ILCellStorage) return new ILRetCell((ILCellStorage)val); else return new ILRetCell(new ILStorage[] { val }, ILSize.Scalar1_1); } } } /// /// 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(this)) using (ILScope.Enter(indices)) { return Subarray(indices); } } } #endregion index access } }