/// /// 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.Text; using System.IO; using System.Runtime.Serialization; using System.Runtime.CompilerServices; using ILNumerics.Storage; using ILNumerics.Misc; using ILNumerics.Exceptions; namespace ILNumerics { /// /// The main rectangular array to be used in algorithms /// /// Inner type. This will mostly be a system numeric type or a /// complex floating point type. /// This class serves as the main rectangular array, holding arbitrary elements (usually numeric types) /// in arbitrary dimensions. /// Arrays of this type may use any type as generic element. However, common mathematical functions and operators /// are defined for a limited number of inner types only. All binary operations (+,-,*,/,,<=]]>,etc.) are /// defined for two arrays with the same numeric type, would it be from the System namespace (double, /// int,...) or ILNumerics.complex/ ILNumerics.fcomplex. Most algebraic functions require floating point /// types. See the class for a list of all computational functions. /// Arrays are capable of creating flexible subarrays /// and to get altered at runtime. Read about all details of ILNumerics arrays in the /// ILNumerics Array documentation. /// Arrays of this type are dense arrays. Cloning arrays is done as lazy /// copy on write, i.e. clones do only use new memory, if attempting to write on them. Arrays integrate into the memory /// management of ILNumerics. Read about the most important /// simple rules, for using arrays in custom computational functions. /// Arrays come with overloaded mathematical operators, allowing for a convenient syntax. A /// sophisticated memory management in the back will make sure, that as little memory as needed is used, even in /// expressions like: a + c * 2 / abs(sin(c) * -b / log(a)). Here all arrays are of the same size. Evaluating /// this expression does only need the memory of twice the size of one array. Memory gets collected and reused /// for every subexpression evaluation. Further optimization options exist, as described in /// Optimizing Algorithm Performance. /// /// A simple example demonstrating some uses of arrays in a very simple application: /// using System; ///using System.Collections.Generic; ///using System.Linq; ///using System.Text; ///using ILNumerics; /// /// ///namespace ConsoleApplication1 { /// class Program : ILMath { /// static void Main(string[] args) { /// ILArray<double> A = rand(10,20); /// ILArray<double> B = A * 30 + 100; /// ILLogical C = any(multiply(B,B.T)); /// Console.Out.Write(-B); /// Console.ReadKey(); /// } /// } ///} /// /// /// /// [Serializable] public sealed class ILArray : ILDenseArray { private static bool s_isTempArray = false; #region constructors /// /// Create new ILArray, specify (dense) storage /// /// internal ILArray(ILDenseStorage storage) : base(storage, s_isTempArray) { } /// /// create new ILArray, specify dimensions /// /// private ILArray(ILSize dimensions) : base(new ILDenseStorage(dimensions), s_isTempArray) { } /// /// create new ILArray, specify storage and if the new array should be disposed automatically /// /// /// internal ILArray(ILDenseStorage storage, bool registerForDisposal) : base(storage, s_isTempArray) { if (registerForDisposal) ILScope.Context.RegisterArray(this); } /// /// create new ILArray, specify dimensions /// /// /// private ILArray(ILSize dimensions, bool registerForDisposal) : base(new ILDenseStorage(dimensions), s_isTempArray) { if (registerForDisposal) ILScope.Context.RegisterArray(this); } /// /// create new ILArray from System.Array /// /// System.Array /// dimension specifier internal ILArray(ElementType[] elements, ILSize size) : base(new ILDenseStorage(elements, size), s_isTempArray) { } /// /// create new ILArray from System.Array, optionally register the array for disposal /// /// System.Array /// if true, the array will be disposed once the current scope is closed /// dimension specifier internal ILArray(ElementType[] elements, ILSize size, bool registerForDisposal) : base(new ILDenseStorage(elements, size), s_isTempArray) { if (registerForDisposal) ILScope.Context.RegisterArray(this); } /// /// create new ILArray from System.Array /// /// System.Array /// dimension specifier internal ILArray(ElementType[] elements, params int[] size) : base(new ILDenseStorage(elements, new ILSize(size)), s_isTempArray) { } /// /// create new ILArray from System.Array /// /// variable length System.Array internal ILArray(params ElementType[] elements) : base(new ILDenseStorage(elements, new ILSize(1, elements.Length)), s_isTempArray) { } /// /// [deprecated] Create empty array of arbitrary size /// /// Dimension sizes /// New empty array /// This function is markes as deprecated and only included for compatibility reasons. /// It will be removed in a future version. Use instead. [Obsolete("Use ILNumerics.ILMath.empty{T}() instead")] public static ILRetArray empty(params int[] size) { if (size == null || size.Length == 0) return new ILArray(ILSize.Empty00); ILArray ret = new ILArray(new ILSize(size)); if (!ret.IsEmpty) throw new ILArgumentException("'size' must specify the size of an empty array"); return ret; } /// /// [deprecated] Create empty array of arbitrary size /// /// Dimension sizes /// New empty array /// This function is markes as deprecated and only included for compatibility reasons. /// It will be removed in a future version. Use instead. [Obsolete("Use ILNumerics.ILMath.empty{T}() instead")] public static ILRetArray empty(ILSize size) { ILArray ret = new ILArray(size); if (!ret.IsEmpty) throw new ILArgumentException("'size' must specify the size of an empty array"); return ret; } #endregion #region implicit cast operators #region constructional operators /// /// Implicitly convert scalar to array of size 1x1 (scalar). /// /// System type of size scalar /// New ILArray of type ILArray ]]> of size 1x1 /// holding the only element with value of val. /// public static implicit operator ILArray (ElementType val) { ILArray ret = new ILArray( new ILDenseStorage( new ElementType[1] {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. 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 /// The size of the result depends on the global option Settings.CreateRowVectorByDefault /// public static implicit operator ILArray (ElementType[] A) { if (A == null) return null; ILArray ret; if (Settings.CreateRowVectorsByDefault) { ret = new ILArray(A, 1, A.Length); } else { ret = new ILArray(A, A.Length, 1); } ILScope.Context.RegisterArray(ret); return ret; } /// /// Implicitly convert n-dimensional 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 the output array (shallow copy). /// /// If type of input does not match /// ElementType public static implicit operator ILArray (Array A) { if (A == null) return null; if (A.Length == 0) { return new ILArray(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); } if (dims.Length == 1 && Settings.CreateRowVectorsByDefault) { dims = new int[2] {1, dims[0]}; } foreach (ElementType item in A) retArr[posArr++] = item; ILArray ret = new ILArray(retArr,dims); ILScope.Context.RegisterArray(ret); return ret; } /// /// 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 ILArray(ElementType[,] A) { if (A == null) return null; if (A.Length == 0) { return new ILArray(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; ILArray ret = new ILArray(retArr, dims); ILScope.Context.RegisterArray(ret); return ret; } /// /// 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 ILArray(ElementType[,,] A) { if (A == null) return null; if (A.Length == 0) { return new ILArray(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; ILArray ret = new ILArray(retArr, dims); ILScope.Context.RegisterArray(ret); return ret; } #endregion #region conversional operators /// /// "Persistence cast" make a steady array out of a temp array /// /// Temporary array /// Steady ILArray, will survive multiple usages /// This is one of the most important casts in the ILNumerics framework. It changes temporary /// arrays from temporary state to ('steady') ILArrays and persistent state. The inner storage is kept and used for /// the new array. The new arrays can than get used multiple times in any function. In contrast to /// that, ILRetArrays are disposed off after first use. public static implicit operator ILArray(ILRetArray A) { if (object.Equals(A, null)) return null; ILArray ret = new ILArray(A.GiveStorageAwayOrClone()); ILScope.Context.RegisterArray(ret); return ret; } /// /// "Persistence cast" make a steady array out of an input array /// /// Input array /// Steady ILArray, will survive multiple usages /// This is one of the most important casts in the ILNumerics framework. It changes temporary /// arrays from temporary state to ('steady') ILArrays and persistent state. The inner storage is kept and used for /// the new array. The new arrays can than get used multiple times in any function. In contrast to /// that, ILRetArrays are disposed off after first use. public static implicit operator ILArray(ILInArray A) { if (object.Equals(A, null)) return null; ILArray < ElementType > ret = new ILArray(new ILDenseStorage( A.Storage.GetDataArray(), A.Size)); ILScope.Context.RegisterArray(ret); return ret; } /// /// "Persistence cast" make a steady array out of an input array /// /// Input array /// Steady ILArray, will survive multiple usages /// This is one of the most important casts in the ILNumerics framework. It changes temporary /// arrays from temporary state to ('steady') ILArrays and persistent state. The inner storage is kept and used for /// the new array. The new arrays can than get used multiple times in any function. In contrast to /// that, ILRetArrays are disposed off after first use. public static implicit operator ILArray(ILOutArray A) { if (object.Equals(A, null)) return null; ILArray ret = new ILArray(new ILDenseStorage( A.Storage.GetDataArray(), A.Size)); ILScope.Context.RegisterArray(ret); return ret; } /// /// Convert dense array to scalar temporary cell /// /// Input array /// Scalar cell having the only element with a clone of array public static implicit operator ILRetCell(ILArray A) { using (ILScope.Enter(A)) { ILRetCell ret = new ILRetCell(ILSize.Scalar1_1, A.Storage); ret.Storage.FromImplicitCast = true; return ret; } } #endregion #endregion #region memory management /// /// Assign another array to this array variable. This is an optional, yet more efficient alternative to using '=' /// /// New array /// By assigning to this property, this array is immediately released to the memory pool and replaced by the new array. In difference to that, /// by using the common '=' assignment operator, the array is released only at the time, the current /// block is left. Therefeore, prefere this method, if a /// smaller memory pool is crucial. However, for variables of type ILArray, regular assignments are allowed as well. /// public ILRetArray a { set { Assign(value); } get { return this.C; } } /// /// Assign another array to this array variable. This is an optional, yet more efficient alternative to '=' /// /// New array /// By using this method, this array is immediately released to the memory pool and replaced by the new array. In difference to that, /// by using the common '=' assignment operator, the array is released only at the time, the current /// block is left. Therefeore, prefere this method, if a /// smaller memory pool is crucial. /// public void Assign(ILRetArray value) { if (!IsDisposed) Storage.Dispose(); m_storage = value.GiveStorageAwayOrClone(); //ILScope.Context.RegisterArray(this); } internal override bool EnterScope() { return false; } #endregion #region mutability + indexer /// /// Set single value to element at index specified /// /// New value /// Index of element to be altered public void SetValue(ElementType value, params int[] idx) { Storage.SetValueTyped(value, idx); } /// /// Alter range of this array /// /// Array with new values /// Range specification public void SetRange(ILInArray value, params ILBaseArray[] range) { using (ILScope.Enter(value)) using (ILScope.Enter(range)) { if (object.Equals(value, null)) { Storage.IndexSubrange(null, range); } else { Storage.IndexSubrange(value.Storage, range); } } } /// /// Subarray creation/ manipulation/ deletion /// /// Range specification, defining the size of the subarray /// Subarray as copy of this array public ILRetArray this[params ILBaseArray[] range] { get { using (ILScope.Enter(range)) return new ILRetArray(Storage.Subarray(range)); } set { SetRange(value, range); } } #endregion } }