///
/// 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 System.Text;
using ILNumerics.Storage;
using ILNumerics;
using ILNumerics.Exceptions;
using ILNumerics.Misc;
namespace ILNumerics {
///
/// N-dimensional, generic array class, temporary variant, is disposed after first use
///
/// Inner element type
public sealed class ILRetArray : ILDenseArray {
#region properties
///
/// Clone of this array (fast, cheap and shallow)
///
/// Calling this member will dispose this instance afterwards (for temporary arrays).
///
public override ILRetArray 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: Size.NumberOfElements == 1.
public override bool IsScalar {
get {
using (ILScope.Enter(this))
return Size.NumberOfElements == 1;
}
}
///
/// Test if this array is a vector
///
/// In order for an array to be a vector the number of non singleton
/// dimensions must equal 1. Keep in mind that all ILArrays have at least 2 dimensions. Therefore
/// it is not sufficient to test for the number of dimensions, but to take the number of
/// non singleton dimensions into account. This attribute is readonly.
public override bool IsVector {
get {
using (ILScope.Enter(this))
return (Size[0] == 1 || Size[1] == 1) && Size.NumberOfDimensions == 2;
}
}
///
/// Length of the longest dimension of this instance
///
/// This property is readonly.
/// Calling this member will dispose this instance afterwards (for temporary arrays).
public override int Length {
get {
using (ILScope.Enter(this))
return base.Length;
}
}
///
/// Return transposed version of this array
///
public new ILRetArray T {
get {
using (ILScope.Enter(this))
return new ILRetArray(Storage.ShiftDimensions(1));
}
}
///
/// Gets the name of this array (readonly)
///
public new String Name {
get {
using (ILScope.Enter(this))
return m_name;
}
}
#endregion
#region constructors
internal ILRetArray(ILDenseStorage denseStorage) :
base(denseStorage, true) { }
internal ILRetArray(ElementType[] elements, params int[] dimensions) :
this(elements, new ILSize(dimensions)) { }
internal ILRetArray(ElementType[] elements, ILSize dimensions) :
base(new ILDenseStorage(elements, dimensions), true) { }
internal ILRetArray(ILSize dimensions) :
base(new ILDenseStorage(dimensions), true) { }
internal static ILRetArray empty(ILSize dimension) {
return new ILRetArray(new ElementType[0], dimension);
}
#endregion
#region operator overloads
#region constructive operators
///
/// Implicitly convert scalar to array of size 1x1 (scalar).
///
/// Single element of ElementType type
/// New array of of size 1x1 holding the only element with value of val.
///
public static implicit operator ILRetArray(ElementType val) {
ILRetArray ret = new ILRetArray(
new ILDenseStorage(new ElementType[] { val }, new ILSize(1, 1)));
return ret;
}
///
/// Implicitly cast one dimensional System.Array to ILNumerics array (vector)
///
/// 1-dimensional system array, arbitrary type
/// ILNumerics array of same element type as elements of A.
/// Row vector. If A is null: empty array.
/// The System.Array A will directly be used for the new ILNumerics array!
/// No copy will be done! Make sure, not to reference A after this conversion!
public static implicit operator ILRetArray(ElementType[] A) {
if (A == null) {
// TODO: check: return null better?
ILDenseStorage dS = new ILDenseStorage(new ElementType[0], ILSize.Empty00);
return new ILRetArray(dS);
}
return new ILRetArray(A, 1, A.Length);
}
///
/// Implicitly convert n-dim. System.Array to ILNumerics array
///
/// Arbitrarily sized System.Array
/// If A is null: empty array. Else: new ILNumerics array of the same size as A
/// The inner type of input array must match the requested type
/// . The resulting ILArray will reflect all dimensions of
/// A. Elements of A will get copied to elements of output array (shallow copy).
/// If type of input does not match
/// ElementType
public static implicit operator ILRetArray(Array A) {
if (A == null || A.Length == 0) {
// TODO: check: return null better?
return new ILRetArray(ILSize.Empty00);
}
if (A.GetType().GetElementType() != typeof(ElementType))
throw new ILCastException("inner type of System.Array must match");
int[] dims = new int[A.Rank];
ElementType[] retArr = ILMemoryPool.Pool.New(A.Length);
int posArr = 0;
for (int i = 0; i < dims.Length; i++) {
dims[i] = A.GetLength(dims.Length - i - 1);
}
foreach (ElementType item in A)
retArr[posArr++] = item;
return new ILRetArray(retArr, dims);
}
///
/// Implicitly cast two dimensional System.Array to ILNumerics array
///
/// 2-dimensional System.Array
/// If A is null: empty array. ILNumerics array of same size and type as A otherwise.
public static implicit operator ILRetArray(ElementType[,] A) {
if (A == null || A.Length == 0) {
// TODO: check: return null better?
return new ILRetArray(ILSize.Empty00);
}
int[] dims = new int[2];
ElementType[] retArr = ILMemoryPool.Pool.New(A.Length);
int posArr = 0;
for (int i = 0; i < 2; i++) {
dims[i] = A.GetLength(dims.Length - i - 1);
}
foreach (ElementType item in A)
retArr[posArr++] = item;
return new ILRetArray(retArr, dims);
}
///
/// Implicitly cast three dimensional System.Array to ILNumerics array
///
/// 3-dimensional System.Array
/// If A is null: empty array. ILNumerics array of same size and type as A otherwise.
public static implicit operator ILRetArray(ElementType[, ,] A) {
if (A == null || A.Length == 0) {
// TODO: check: return null better?
return new ILRetArray(ILSize.Empty00);
}
int[] dims = new int[3];
ElementType[] retArr = ILMemoryPool.Pool.New(A.Length);
int posArr = 0;
for (int i = 0; i < 3; i++) {
dims[i] = A.GetLength(dims.Length - i - 1);
}
foreach (ElementType item in A)
retArr[posArr++] = item;
return new ILRetArray(retArr, dims);
}
///
/// Convert array to temporary cell
///
/// Source array
/// Temporary scalar cell, having the only element with a clone of A
public static implicit operator ILRetCell(ILRetArray A) {
using (ILScope.Enter(A)) {
ILRetCell ret = new ILRetCell(ILSize.Scalar1_1, A.Storage);
ret.Storage.FromImplicitCast = true;
return ret;
}
}
#endregion
#region implicit conversions
///
/// 'Clone' conversion
///
/// Source array
/// Temporary ILArray, will be disposed after next operation
/// This conversion is for convenient reasons only. It enables the direct
/// use of (persistent) ILArray objects in situations where (temporary) ILRetArray
/// is required. A (fast) clone will be made. This is an alias for A.C.
public static implicit operator ILRetArray(ILArray A) {
if (object.Equals(A,null)) return null;
return A.C;
}
///
/// 'Clone' conversion
///
/// Source array
/// Temporary ILArray, will be disposed after next operation
/// This conversion is for convenient reasons only. It enables the direct
/// use of (persistent) ILArray objects in situations where (temporary) ILRetArray
/// is required. One example is the conversion of ILArray as return type.
/// A (fast) clone will be made. This is an alias for A.C.
public static implicit operator ILRetArray(ILInArray A) {
if (object.Equals(A, null)) return null;
return A.C;
}
///
/// 'Clone' conversion
///
/// Source array
/// temporary ILArray, will be disposed after next operation
/// This conversion is for convenient reasons only. It enables the direct
/// use of (persistent) ILArray objects in situations where (temporary) ILRetArray
/// is required. One example is the conversion of ILArray as return type.
/// A (fast) clone will be made. This is an alias for A.C.
public static implicit operator ILRetArray(ILOutArray A) {
if (object.Equals(A, null)) return null;
return A.C;
}
#endregion
#endregion operator overloads
#region public function
///
/// Clone of this array
///
///
/// Clones of all arrays in ILNumerics are done in a very fast, lazy way. This means,
/// at the time the clone is made, no relevant memory is copied. Elements of both arrays rather point to the same
/// underlying System.Array. A reference counting mechanism ensures the detaching of thoses arrays
/// on write access.
/// The clone returned will be of the same type as this instance.
internal override ILBaseArray Clone() {
return this;
}
///
/// Concatenate this array
///
/// n-dimensional storage
/// Dimension index along which to concatenate the arrays.
/// New array with copy elements of this array and A
/// The array returned will be a copy of both arrays involved. None
/// of the input arrays will be altered. If is larger than
/// the number of dimensions of one of the arrays its value will be used in modulus.
/// The resulting array has the size of both input arrays, laid beside one
/// another along the dimension.
public new ILRetArray Concat(ILInArray A, int dim) {
using (ILScope.Enter(this,A))
return new ILRetArray(Storage.Concat(A.Storage, dim));
}
///
/// Compare elements and shape of this array with another array
///
/// Other array
/// true if shape and element values of both arrays match, false otherwise
/// Calling this member will dispose this instance afterwards (for temporary arrays.
public override bool Equals(object A) {
using (ILScope.Enter(this))
return base.Equals(A);
}
///
/// Copy values of all elements into System.Array.
///
/// [Output] System.Array, holding all element values of this ILDenseStorage.
/// The System.Array may be predefined. If its length is sufficient, it will be used and
/// its leading elements will be overwritten when function returns. If 'outArray' is null or has too few elements,
/// it will be recreated from the ILNumerics memory pool.
public new void ExportValues(ref ElementType[] outArray) {
using (ILScope.Enter(this))
Storage.ExportValues(ref outArray);
}
///
/// Enumerator returning elements as ElementType
///
/// Enumerator
/// This method enables the use of ILNumerics arrays in foreach loops.
/// The iterator is returned, if arrays are directly used in foreach statements. The iterator
/// is compatible with ILNumerics memory management.
/// ILArray<double> A = rand(5,4,6);
/// foreach (double element in A) {
/// // all elements are scalar double values
/// String.Format("Element: {0} ", element);
/// // Note: 'element' cannot be used to alter the collection!
/// }
///
public override IEnumerator GetEnumerator() {
using (ILScope.Enter(this)) {
ElementType[] values = GetArrayForRead();
int len = Size.NumberOfElements;
for (int i = 0; i < len; i++)
yield return values[i];
}
}
///
/// Generate a hash code based on the current arrays values
///
/// Hash code
/// The hashcode is generated by taking the values currently stored in the array into account.
/// Therefore, the function must iterate over all elements in the array - which makes it somehow a costly
/// operation. Take this into account, if you consider using large arrays in collections like dictionaries
/// or hashtables, which make great use of hash codes.
/// Calling this member will dispose this instance afterwards (for temporary arrays).
public override int GetHashCode() {
using (ILScope.Enter(this))
return base.GetHashCode();
}
///
/// Get minimum and maximum value of all elements - if any
///
/// [Output] Minimum value
/// [Output] Maximum value
/// true if the limits exists and could be computed, false otherwise
/// Empty arrays will return false. In this case the output parameter will be: default(ElementType).
/// Calling this member will dispose this instance afterwards (for temporary arrays).
public override bool GetLimits(out ElementType min, out ElementType max) {
using (ILScope.Enter(this))
return base.GetLimits(out min, out max);
}
///
/// Get single element from this array
///
/// Indices, location of element
/// The requested element
public override ElementType GetValue(params int[] idx) {
using (ILScope.Enter(this))
return base.GetValue(idx);
}
///
/// Create replication of this array
///
/// Dimensions specifier. If the number of elements in is
/// less than the number of dimensions in this array, the trailing dimensions will
/// be set to 1 (singleton dimensions). On the other hand, if the number specified
/// is larger then the number of dimension stored inside the storge the resulting
/// storage will get its number of dimensions extended accordingly.
/// Array being created by multiple replications of this array along
/// arbitrary dimensions according to
public new ILRetArray Repmat(params int[] dims) {
using (ILScope.Enter(this))
return new ILRetArray(Storage.Repmat(dims));
}
///
/// Reshaped copy of this array
///
/// New dimensions of the array
/// Reshaped copy of the array
/// The current instance will not be changed. A new storage is created, having
/// the elements of this array and a shape as determined by .
///
/// If the number of elements in
/// do not match the number of elements in this array.
public new ILRetArray Reshape(ILSize dimensions) {
using (ILScope.Enter(this)) {
ILArray ret = C;
ret.Storage.Reshape(dimensions);
return ret;
}
}
///
/// Serialize this ILArray into a binary stream.
///
/// System.IO.Stream to receive the byte stream
/// for this ILBaseArray
/// True on success, false on error.
/// Calling this member will dispose this instance afterwards (for temporary arrays).
///
public override bool Serialize(Stream outStream) {
using (ILScope.Enter(this))
return base.Serialize(outStream);
}
///
/// Create array from this array and shift dimensions
///
/// Number of dimensions to shift
/// Shifted version of this array
/// The shift is done 'to the left':
/// ILArray<double> A = zeros(2,4);
/// ILArray<double> B = A.Shifted(1);
/// // B is now: <double> [4,2]
///
/// ILArray<double> C = zeros(2,4,3);
/// ILArray<double> D = C.Shifted(1);
/// // D is now: <double> [4,3,2]
///
/// The dimensions are shifted circulary to the left. This
/// can be imagined as removing the first dimensions from the beginning of the list of
/// dimensions and "append" them to the end in a ringbuffer style.
/// For dimension shifts of '1', you may consider using the
/// property for readability.
/// must be positive. It is taken modulus the number of dimensions.
///
public new ILRetArray Shifted(int shift) {
using (ILScope.Enter(this))
return new ILRetArray(Storage.ShiftDimensions(shift));
}
///
/// Subarray creation
///
/// Range specification, defining the size of the subarray
/// Subarray as copy of a part of this array
/// Consult the ILNumerics subarray documentation for all subarray indexing rules.
public new ILRetArray Subarray(params ILBaseArray[] size) {
using (ILScope.Enter(this))
using (ILScope.Enter(size))
return new ILRetArray(Storage.Subarray(size));
}
/////
///// Short textual summary of this instance; used for debug output
/////
///// String representation of type and size
///// The type of elements and the size of the array are displayed. If the array
///// is scalar, its value is displayed next to the type.
///// Calling this member will dispose this instance afterwards (for temporary arrays).
//public override string ShortInfo() {
// using (ILScope.Enter(this))
// return base.ShortInfo();
//}
///
/// Send values of this instance to stream.
///
/// Stream to write the values into.
/// Format string to be used for output. See for a specification
/// of valid formating expressions. This flag is only used, when 'method' is set to 'Serial'.
/// A constant out of . Specifies the way in which
/// the values will be serialized.
/// If the 'Formatted' method is used, any occurences of the NewLine character(s)
/// will be replaced from the format string before applying to the elements. This is done to
/// prevent the format from breaking the 'page' style of the output.
/// If 'method' is set to 'Matlab', the array will be written as Matfile version 5.0. No compression will be used. The internal 'Name' property will be used as the
/// array name for writing. This array instance will be the only array in the .mat file. If you want to write several arrays bundled into one mat file, use the MatFile class to
/// create a collection of arrays and write the MatFile to stream.
public override void ToStream(Stream stream, string format, ILArrayStreamSerializationFlags method) {
using (ILScope.Enter(this))
try {
int len;
switch (method) {
case ILArrayStreamSerializationFlags.Serial:
len = Size.NumberOfElements;
using (TextWriter tw = new StreamWriter(stream)) {
for (int i = 0; i < len; i++) {
tw.Write(format, GetValue(i));
}
}
break;
case ILArrayStreamSerializationFlags.Formatted:
format = format.Replace(Environment.NewLine, "");
ILDenseStorage temp = this.Storage.ShiftDimensions(1);
//len = Dimensions.NumberOfElements / Dimensions[1];
using (TextWriter tw = new StreamWriter(stream)) {
tw.Write(temp.ValuesToString(0));
}
break;
case ILArrayStreamSerializationFlags.Matlab:
ILMatFile mf = new ILMatFile(new ILBaseArray[1] { this });
mf.Write(stream);
break;
}
} catch (Exception e) {
throw new ILException("ToStream: Could not serialize to stream.", e);
}
}
#endregion
#region indexer
///
/// Subarray creation
///
/// Range specification, defining the size of the subarray
/// Subarray as copy of a part of this array
/// Consult the ILNumerics subarray documentation for all subarray indexing rules.
public ILRetArray this[params ILBaseArray[] range] {
get {
using (ILScope.Enter(this))
using (ILScope.Enter(range))
return new ILRetArray(Storage.Subarray(range));
}
}
#endregion
#region memory management
internal override bool EnterScope() {
return false;
}
#endregion
}
}