///
/// 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
}
}