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