///
/// 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 ILNumerics.Storage;
using System.IO;
using ILNumerics.Exceptions;
namespace ILNumerics {
[System.Diagnostics.DebuggerTypeProxy(typeof(ILNumerics.Misc.ILArrayDebuggerProxy<>))]
[System.Diagnostics.DebuggerDisplay("{ShortInfo(),nq}")]
[Serializable]
// ToDo: DOKU for ILDenseArray missing
public partial class ILDenseArray : ILBaseArray {
#region constructors
internal ILDenseArray(ILStorage storage, bool isTempArray)
: base(storage, isTempArray) {
}
#endregion
#region properties
///
/// internal access to the underlying storage
///
internal new ILDenseStorage Storage {
get { return (m_storage as ILDenseStorage); }
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;
}
}
}
///
/// Clone of this array (fast, lazy and shallow)
///
public virtual ILRetArray C {
get {
return new ILRetArray((ILDenseStorage)Storage.Clone());
}
}
///
/// Return transposed version of this array
///
/// For matrices, this swaps columns with rows. For arrays, the dimensions are shifted by one.
/// Note, for complex elements, no conjugate is created! Use conj(A.T) if this is intended.
public ILRetArray T {
get {
// if this is updated to create a conjugate for complex data types
// -> do not forget to update quick reference ILNumerics4Matlab also!
return new ILRetArray(Storage.ShiftDimensions(1));
}
}
///
/// [deprecated] Get maximum value of array - if any
///
/// This property is marked as deprecated and will be removed in a future version. Use one of the
/// following alternatives instead:
///
///
[Obsolete()]
public ElementType MaxValue {
get {
ElementType ret, dummy;
GetLimits(out dummy, out ret);
return ret;
}
}
///
/// [deprecated] Get minimum value of array - if any
///
/// This property is marked as deprecated and will be removed in a future version. Use one of the
/// following alternatives instead:
///
///
///
///
[Obsolete()]
public ElementType MinValue {
get {
ElementType ret, dummy;
GetLimits(out ret, out dummy);
return ret;
}
}
#endregion
#region memory management
///
/// Get number of arrays, referencing the same underlying data storage
///
/// This number is always greater than or equal to 1.
/// For temporary arrays, calling this property does not - as usual -
/// disposes the array
public int ReferenceCount {
get {
return Storage.ReferenceCount;
}
}
#endregion
#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() {
ILRetArray ret = new ILRetArray((ILDenseStorage)Storage.Clone());
return ret;
}
///
/// Concatenate this array
///
/// N-dimensional array. Except for dimensions
/// the dimensions of A must match the dimensions of this storage
/// Index of dimension to concatenate arrays along.
/// If dim is larger than the number of dimensions of any of the arrays,
/// its value will be used in modulus the number of dimensions.
/// New array having the size
/// of both input arrays layed behind each other along the dim's-dimension
public ILRetArray Concat(ILInArray A, int dim) {
using (ILScope.Enter(A))
return new ILRetArray(Storage.Concat(A.Storage, dim));
}
///
/// 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 void ExportValues(ref ElementType[] outArray) {
Storage.ExportValues(ref outArray);
}
///
/// Get direct reference to inner System.Array storage for read access - use with care!
///
/// Reference to inner System.Array for reading
/// This method is provided for experts only! Altering elements of this
/// array may cause the data to be invalidated or corrupted! Use this array only for reading! Note
/// the ILNumerics array storage format (column major). Keep in mind, the length
/// of the array may exceeds the number of elements!
/// Accessing the inner system array directly should be left to ILNumerics experts only!
/// Unless you really know, what you are doing, you should rather use the higher order access
/// methods provided by ILArray<T>!
/// Unlike (almost) all other member function of an array, this function
/// does not keep track of internal memory management. It means, the storage which this array is based
/// upon, will not be set free after the function returns. You (as the user of the array) will have to pay
/// attention yourself, when to call dispose on the array - if necessary. Also, for elements of reference
/// types (e.g. ILCell), retrieving and storing elements from/into the System.Array directly does
/// not simulate a value semantic as all other functions do! This means, references are copied. Attention
/// must be paid to dereference / clone elements accordingly.
public ElementType[] GetArrayForRead() {
return Storage.GetArrayForRead();
}
///
/// Direct reference to inner System.Array storage for write access - use with care!
///
/// Reference to inner System.Array
/// Altering this array can be done directly. If necessary, the array is detached before
/// returned. Watch the column order format of storages in ILNumerics. Keep in mind, the length
/// of the System.Array may exceed the number of elements of the ILNumerics array.
/// Accessing the inner system array directly should be left to ILNumerics experts only.
/// Unless you really know, what you are doing, you should rather use the higher order access
/// methods provided by ILArray<T>!
/// Unlike (almost) all other member function of an array, this function
/// does not keep track of internal memory management. It means, the storage which this array is based
/// upon, will not be set free after the function returns. You (as the user of the array) will have to pay
/// attention yourself, when to call dispose on the array - if necessary. Also, for elements of reference
/// types (e.g. ILCell), retrieving and storing elements from/into the System.Array directly does
/// not simulate a value semantic as all other functions do! This means, references are copied. Attention
/// must be paid to dereference / clone elements accordingly.
public ElementType[] GetArrayForWrite() {
return Storage.GetArrayForWrite();
}
///
/// 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() {
ElementType[] values = GetArrayForRead();
int len = Size.NumberOfElements;
for (int i = 0; i < len; i++)
yield return values[i];
}
///
/// Gives away internal storage for further use (e.g. in ILArray), disposes this array
///
/// Internal storage
internal ILDenseStorage GiveStorageAwayOrClone() {
if (m_scopeCounter <= 0) {
ILDenseStorage ret = Storage;
m_storage = null;
return ret;
} else {
return (ILDenseStorage)Storage.Clone();
}
}
///
/// 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
internal ILRetArray Repmat(params int[] dims) {
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 ILRetArray Reshape(ILSize dimensions) {
using (ILScope.Enter()) {
ILArray ret = C;
ret.Storage.Reshape(dimensions);
return ret;
}
}
///
/// Reshaped copy of this array
///
/// New dimensions of the array
/// Reshaped copy of the array
/// The current instance will not be changed. A new array is created, having
/// the elements of this array and a shape as determined by .
///
/// If the number of elements in 'newDimension'
/// do not match the number of elements in this array.
public ILRetArray Reshape(params int[] dimensions) {
return Reshape(new ILSize(dimensions));
}
///
/// 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 Subarray(params ILBaseArray[] size) {
using (ILScope.Enter(size))
return new ILRetArray(Storage.Subarray(size));
}
///
/// 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 ILRetArray Shifted(int shift) {
return new ILRetArray(Storage.ShiftDimensions(shift));
}
///
/// 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) {
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);
}
}
///
/// Give that storage away for in-place operations, if possible (depends on scope and temp type of array)
///
/// true if the storage of the array is about to get disposed anyway
/// The function investigates the state of the array. If this is a temporary array in
/// the outer most scope, it would get disposed after the
internal bool TryGetStorage4InplaceOp(out ElementType[] array) {
// check if this array is yet to be available
if (!Settings.AllowInArrayAssignments && m_isTempArray && m_scopeCounter <= 1) {
// it's efficient only if we dont have to make a copy of the underlying array
if (Storage.ReferenceCount == 1) {
ILDenseStorage storage = Storage;
m_storage = null;
array = storage.GetArrayForWrite();
return true;
}
}
array = null;
return false;
}
#endregion
}
}